云计算十字真言及其在小博无线的实践

  1. 云栖社区>
  2. 博客>
  3. 正文

云计算十字真言及其在小博无线的实践

rippletek 2016-11-03 11:31:22 浏览9471

本文正在参加“最佳上云实践”评选,来给我们投票吧:https://yq.aliyun.com/activity/158(编号28)


小博无线2013年10月上云以来,已在云端飞行了三年整。作为小博技术团队的早期成员之一,我有幸参与了云端系统从单台主机进化为今天数十台主机, 上百个负载均衡, 数百个容器的略具规模的系统的全过程。本文是这三年来我们使用云计算平台的经验总结。

由于小博无线的整个云端系统是搭建在阿里云计算平台上,本文中讨论的所有工具都是基于阿里云的。然而,正如编程思想和实践方法是与具体编程语言无关的,使用云计算工具的思想和实践方法也是独立于工具存在的。

总的来说,云计算平台作为承载互联网业务的基础设施,要把它用好,不外从两方面考虑:

  1. 高可用: 保证公司的业务流和现金流持续正常流动,不受服务不可用或服务质量下降的影响。
  2. 高利用: 在保证效果的前提下,尽可能少的购买资源并把购买的计算资源充分利用起来,不闲置,不浪费,将成本降至最低。

我们这三年来为了达成这两方面的探索和实践可以总结为下面这张图:

cloud_computing

图中的5种基本实践,本文将它们称为"云计算十字真言":

"冗余, 漂移, 伸缩, 熔断, 扁平"

冗余

首先,只有通过冗余部署消除单点,才能实现高可用。 [1]

工具

云磁盘和对象存储

储存在云磁盘和对象存储(OSS)中的数据都是自动冗余的。

负载均衡(SLB)

SLB是我们最常用的工具,不仅能消除单点,还可通过增加后端节点来水平扩展业务。负载均衡自身的冗余采用跨可用区的双节点主备。

slb_redundency

云数据库

我们使用了多个RDS和Redis实例, 它们的冗余也是通过类似于负载均衡的双节点主备来实现的。但与其他一些云计算平台需要手动创建两个实例并完成主备配置不一样的是,阿里云的云数据库采用隐式主备,备用节点对用户不可见。新建一个RDS或Redis实例时阿里云会自动创建好主节点和备用节点,并监控主节点状态,当主节点故障时无需用户干预,运维机器人会自动进行主备切换,保证高可用。

实践

  • 所有基于TCP (http/https)或UDP的服务接口不能通过单台主机开放,必须通过负载均衡开放
  • 云主机(ECS)只负责流量分担和业务计算,不保存持久化数据
  • 使用数据库保存持久化数据, ECS通过访问数据库读写数据
  • 给每个消息队列至少分配两个生产者和两个消费者

一种高可用建站模式

综合上面介绍的工具和实践方法,可以推出一种比较通用的高可用建站模式。

site

  • DNS解析为负责流量接入的公网SLB
  • 反向代理服务器组负责依据请求路径区分出不同的业务类型,再根据业务类型将请求反向代理到业务对应的内网SLB
  • 业务请求通过内网SLB最终达到计算节点,计算节点读写数据库并返回处理结果
  • 图中第1,3,5层的SLB和RDS的冗余由阿里云隐式实现,第2,4层的ECS需要我们显式多点部署才能实现冗余

漂移

冗余可以有效的解决由于单点故障而停服的问题。然而,对于由n个服务节点组成的系统,每出现一个故障节点,系统容量就下降1/n。考虑仅有两个服务节点的情形,其中一个点出现故障时,系统容量就会下降一半,这时系统的可用性已相当脆弱,服务质量也有可能由于容量缩水而大幅下滑。如何令系统在出现部分节点失效的状况下仍能保持设计容量?一种行之有效的办法就是新加入健康节点去替换失效节点,让本来分布在失效节点上的流量漂移到新节点上。

工具

容器

要让服务能够漂起来,应先将服务容器化。Docker可以把一个服务的软件运行时环境,代码以及配置通过一个Dockerfile全部打包为一个image来统一部署和回滚,非常方便易用。

容器调度

我们选用的容器调度方案是Mesos + Marathon。Mesos将多台ECS的CPU和内存资源统一管理,无需关注容器具体部署到哪几台主机上。Marathon可以为每种服务配置多个服务节点并配合健康检查来实现高可用。如果健康检查发现一个服务节点无法正常提供服务,Marathon就自动新建一个服务节点来代替这个失效节点,令健康的节点个数始终等于配置值,让流量从失效节点漂移到新节点上。

SLB API

因为所有服务都通过负载均衡开放,所以我们需要使用SLB API来添加健康的新节点并移除失效的旧节点。

运维机器人

说到运维机器人,业内最著名的运维机器人恐怕要数Netflix的ChaosMonkey, 此猴最喜欢做的事情就是随机关闭一些正常运行的云主机。而我们开发的运维机器人具备的第一个功能却是自动重启已死机的ECS,所以我们给她取了一个和ChaosMonkey正好相反的名字 - TidyMaid

tidy_maid

我们这一节介绍的"漂移",以及后面两节介绍的"伸缩"和"熔断",都离不开TidyMaid。

实践

无感知上线

利用漂移,可以实现在终端用户完全无感知的情况下完成线上系统的变更。具体操作步骤如下:

  • 创建新版本容器
  • 调用API AddBackendServers将新版本容器所在的ECS加入SLB后端服务器组
  • 调用API DescribeHealthStatus轮询新加入的ECS的健康状态,直到新节点在SLB的状态为"健康"
  • 调用API SetBackendServers将旧版本容器所在的ECS的分发权重设为0,等待1分钟
  • 销毁旧版本容器
  • 调用API RemoveBackendServers从后端服务器组移除旧版本容器所在的ECS

为了实现无感知上线,我们先将旧节点的分发权重设置为0,负载均衡就会停止向旧节点导入流量,再等待1分钟让此前正在处理中的流量处理完毕,然后销毁旧节点,回收资源。每次上线变更,服务容器所在的ECS会发生变化,同时,线上流量在Mesos集群中漂移。

漂移带来自由

流量漂移的方法不仅保持了系统平稳运行所需的设计容量,还为开发和运维带来了新的自由。

举个例子,本来防止内存泄露一直是服务器程序设计的一大难题,现在流量可以无感知漂移后,我们可以通过监控容器的资源占用并利用运维机器人销毁使用内存过多的容器来释放被泄露的内存。当容器被销毁后,由于节点个数小于配置值,容器调度器会自动新建容器并让流量漂移过去。缓慢的内存泄露往往极难调查并且周期性影响服务质量,但现在已无大碍。

再举一例,当流量可以漂移后,ECS层面的稳定性也就不那么重要了,我们完全有能力在仅能稳定运行数小时的云主机上构建出能稳定运行数月的服务。当ECS死机时,运行在上面的业务节点都会由于健康检查失败而被标记为失效状态,此时容器调度器自动新建容器来让流量漂移过去,同时,运维机器人会自动重启死机的ECS,让它恢复活力。

伸缩

使用漂移解决了保持设计容量的问题后,又遇到新问题: "到底为每个业务分配多少资源才合适?"

流量通常是一个关于时间的函数,存在高峰和低谷。资源预留太少,安全边际不够,在高峰时段可能由于容量不够而影响服务质量。但如果总是按高峰时段的流量来为服务分配资源,在低谷时段却又很浪费。我们通过伸缩来优雅的解决资源分配的问题。

让资源分配随流量变化,流量变大时扩容,流量变小时缩容, 这就是伸缩。

实践

扩容一般分为两类:

  • 水平扩容: 节点配置不变,通过增加服务节点个数扩容
  • 垂直扩容: 节点个数不变,通过提高服务节点配置扩容

我们将服务容器的CPU利用率监控起来,如果过去15分钟的CPU平均值高于80%,监控系统就通知运维机器人水平扩容一个节点。反之,如果CPU平均值低于40%就缩容一个节点。最少可缩至两个节点。

同样,将内存利用率也监控起来,如果过去15分钟的内存使用超过80%, 监控系统就通知运维机器人将分配给容器的可用内存增加20%, 节点配置的内存达到2G后,考虑到单节点所需资源太多会导致难以匹配到有足够多空闲资源的主机,改用水平扩容。如果过去15分钟的内存使用低于40%, 就将分配给容器的可用内存减少20%,让出资源给其他服务使用。

一种自动运维模式

auto_ops_pattern

运维自动化的关键在于完善监控体系和功能接口化。监控发现异常后,触发运维机器人的接口进行相应的维护操作。需要注意的是,许多自动化功能必需云计算平台的接口支持,比如漂移和伸缩,如果没有SLB API的支持,都是无法实现的。

具体到伸缩的实现,我们使用Zabbix监控各容器的资源占用,资源占用过高或过低的状况都会触发Zabbix调用TidyMaid对应的Web API请求伸或缩,TidyMaid再调用Marathon和阿里云对应的Web API完成伸缩操作。

熔断

综合运用冗余,漂移和伸缩,可以大幅提高系统的可用性。但是,任何系统都无法做到100%可用,当系统出现故障时,如何让局部故障的影响停留在局部而不至于扩散出去影响全局?这就需要利用熔断机制。如何在不同的业务场景下对不同的故障进行优雅熔断,是非常具体,有时甚至是极具挑战性的问题。在这里我只简单介绍一下两种比较常用的模式。

前后端分离

前后端分离具有天然的熔断效果,当局部数据不可用时,不会影响整体页面渲染。

依赖监控与功能开关

如果功能模块A依赖外部接口B,给模块A设计一个开关接口,同时将B监控起来,一旦发现B不可用,运维机器人就调用A的关闭接口将功能A下线,等监控发现B重新可用后,运维机器人再调用A的打开接口将功能A上线。

在"漂移"一节介绍的无感知上线方案中的上线功能和SLB API就是一个很好的例子。由于上线功能依赖SLB API,当SLB API不可用时,我们就会熔断上线功能,等SLB API可用后再重新接回。整个熔断和接回的过程都由TidyMaid自动完成,无需手动干预。

扁平

最后,为了提高资源利用率,应将各类业务容器无差别的分配到各个云主机上,而不是将各个主机按功能的不同分开使用,这种无差别统一管理资源的思想就是扁平。

实践

从4层负载均衡迁移到7层

在前面"冗余"一节介绍的高可用建站模式中,如果内网SLB使用4层转发,当nginx服务器组的容器和业务计算服务器组的容器分布在同一个ECS上的时候,就会由于网络打环而无法完成请求处理。对此,我们一开始是将Mesos集群中的ECS分为两组,一组机器专门跑nginx容器, 另一组跑业务计算容器,后来则通过将内网SLB从4层迁移到7层,消除了分组,实现了扁平。

经典网络中的反例

大多数的三方API服务存在访问IP白名单的限制,因此在经典网络中往往需要创建专门的服务器组来代理三方API请求。但在VPC中,由于请求可以通过NAT网关转发,将网关的公网IP加入白名单即可,无需额外创建专门的代理服务器组。