docker 阿里集团 AliDocker 化双 11 总结 (GOOD)

laofo · 2018年12月14日 · 20 次阅读

前言

在基础设施方面,今年双 11 最大的变化是支撑双 11 的所有交易核心应用都跑在了 Docker 容器中。几十万 Docker 容器撑起了双 11 交易 17.5 万笔每秒的下单峰值。众所周知 Docker 技术这几年大热,但如果期望阿里这么大体量的应用全部使用 Docker,这可不是一朝一夕就能完成的事情。阿里的应用数量庞大,种类众多,光兼容性的验证没个 1、2 年的时间没人敢把核心应用放上去。因此虽然 Docker 能给研发和运维带来的好处,作为技术人员大家都心领神会,但是想直接去使用,那面对 Docker 浪潮却只能是坐观弄潮者,徒有羡鱼情。

T4 和 Docker 的融合

所幸的是,这个状况在去年 7 月份有了改变,这事要从阿里内部的容器技术产品 T4 说起。T4 是阿里在 2011 年的时候基于 Linux Container(LXC) 开发的容器技术基础设施。从 12 年到 15 年 3 年时间里用的应用越来越多,实际上已经覆盖了电商领域大部分 App。相比 Docker 的模式和理念,T4 其实更适合阿里内部的运维现状。T4 是从阿里内部的资源管理和日常运维中土生土长出来的产品,在诞生的第一天就针对内部基础设施、运维工具甚至是运维习惯做了很多特别的设计。T4 在 LXC 容器的基础上,对容器资源和各种统计的可见性做了很多卓有成效的隔离,使得在容器内部看到的资源就是分配给这个容器的资源,内部看到的负载就是这个容器的负载等等。同时在 LXC 之外还做了容器的磁盘空间配额限制和隔离,容器内看到的那块磁盘大小就是创建容器时分配给他的磁盘配额大小。这样在 CPU、网络、内存、磁盘等资源使用和统计监控上做到了容器内和物理机上基本没有区别。原来跑在物理机,或者 KVM、Xen 中的应用,能够平滑无感知的迁移到 T4 中。当年从 Xen、Kvm 迁移到 T4 的过程中,很多应用的开发者和 Owner 确实不知道什么时候完成迁移的,可能在某次常规的应用发布中,后台工具系统已经自动做完迁移了。甚至直到去年在和一个应用研发的沟通中,他坚信自己的应用是跑在 KVM 中的,我们到后台查了一下,其实已经在 T4 上了。

我们在去年 5 月份接手了 T4 的整个维护工作,发现 T4 的功能和 Docker 非常相似,但是 T4 和 Docker 相比有一块很大的短板就是没有镜像机制,再加上 T4 这种对人工运维的友好性,在长期使用中就出现了一个问题,就是应用的容器里面遗留了越来越多的不一致,对运维的标准化造成了阻碍。比如有相当一部分应用,在迁移到另外一台物理机上后就没法运行了。因为从第一次上线到存活期间做的各种环境变更、软件升级等,很难严格的记录到发布系统里。另外一个发现是 T4 的技术栈和 Docker 非常相似,都是基于 linux 内核的 cgroup、namespace、chroot、bridge 等机制运作起来的。T4 使用了 LXC,Docker 的执行引擎也支持 LXC,但神奇的是 T4 却能够在阿里内部老版本的 OS 和内核上跑起来。因此直觉告诉我将 T4 和 Docker 结合起来应该是可行的。于是从去年 6 月份开始对这个方向做了探索,终于找到一个恰当的模式,对 Docker 和 T4 都做了一些修改整合后,将两者融合为了一个产品,相当于既让 T4 具备了 Docker 的镜像能力,又让 Docker 具备了 T4 对内部运维体系的友好性,并且能够运行在内部早期的 AliOS5u 和 2.6 内核上。这个产品在内部称为 AliDocker,在去年 8 月份推出了第一个雏形版本。另外这个版本还解决了 Docker 当时很严重的一个问题,就是 Daemon 退出其上所有的容器都会退出,这一点在真正生产环境大规模部署时是无法接受的。Docker 官方直到 1.10 版本才开始部分解决这个问题。我们当时的 Docker 版本从 1.5 一直跟进到后来大规模部署的 1.9 版本,通过 Docker 的 Daemon 管控进程和容器的解耦,Daemon 重启后对之前运行容器的自动识别和重新接管,解决了这个问题。这样 Docker 在阿里内部大规模应用就有了可能。

从这个版本发布到能够替换 T4 大规模部署还走了很长的路,首先 T4 和 Docker 毕竟是两个不同的产品,除了大家耳熟能详的容器机制之外,其实还有非常多的细节和特性。为了让应用在迁移中无感知,AliDocker 对原先 T4 容器的细节功能做了全面的兼容,同时对上层的运维系统做了大量改造,使其支持 Docker 场景下的发布和运维模式,从 Docker 镜像构建到分发启停、扩容迁移都做了完备的工具和流程支持。其次在 T4 到 AliDocker 切换的过程中,我们做了 2 者混跑的支持,也就是说同一台物理机上可以同时跑原来的 T4 容器和新的 AliDocker 容器,互不干扰并且能统一运维。因为众多应用的实例是交错部署在众多物理机上的,同一个物理机上往往有十几个不同应用的实例混跑。这种兼容机制就保证了不同应用可以按各自的节奏逐步完成 Docker 化,而不需要在某个时间和空间做一刀切,避免了大规模升级 Docker 的过程中不必要的应用腾挪和迁移。然后在我们将 AliDocker 和 T4 功能完全对齐,从实例级别到应用级别做了足够的灰度后,推送了一个开关,使得从那一刻开始创建新 T4 实例时会自动创建为 AliDocker 实例,从而完成了增量实例的切换。对于存量的 T4 实例,我们选择了一个完整的深圳交易单元,分批次做了批量切换,在切换期间如果发生大的问题,可以把深圳单元的流量全部切换到上海。这一保障要得益于阿里的异地多活灾备架构,对于这类底层基础设施的升级能够提供理想的兜底方案,使我们敢于放开手脚去做,而又能有效的控制风险。所幸在整个升级洗牌的过程中,没有动用到这个大杀器的功能,虽然出了一些小问题但都能及时修复,影响不大,也让我们的系统更加健壮,让各个部门的人对交易核心流量切换到 AliDocker 这件事情更有信心。

2 核心应用镜像化

但是仅仅将运行容器从 T4 切换到 Docker 其实对我们带来的改变并不大。Docker 真正的核心价值在于镜像机制,以及镜像机制带来的研发与运维模式的变革。应用镜像化大致来说有 2 种方式,一种是比较保守的方式,镜像中只包含基础环境,容器起来后,再登录到容器中部署应用包。这种方式和原先的 T4 类似,镜像化上不够彻底。为了彻底根治环境不一致的沉疴,从机制上杜绝非标准变更,让每个环境改变都沉淀下来,我们采取了另一种更激进的方式:镜像中除了包含基础环境外,还包含应用程序。应用新版本发布时,直接销毁原有的容器,用新版本的镜像启动新的容器提供服务。这样任何在上一个容器中做的小动作都会随着下一次发布全部清洗掉,如果想要保留下来,就必须固化到应用的 Dockerfile 中。一个应用镜像就代表了应用的所有依赖环境和当前版本。任何时间任何地点将应用最新镜像拉起,都能得到和线上其他实例一致的服务和行为。我们在推广 AliDocker 的过程中,一直和所有的应用方强调这个理念,也获得了大家的认同。

于是在今年 5 月底,我们成立了专门的项目组,快速推进这个事情,目标是把双 11 流量覆盖的核心应用全部升级为镜像化模式的 Docker 应用。由于我们做到了运行态与 T4 保持一致,改造过程比较顺利,但实际上线中也遇到了许多问题,其中最大的问题就是发布与扩容速度。在镜像化之前,应用新版本发布时只需要分发应用包本身,而应用包一般只有几百 M 的大小;切换到镜像化模式之后,由于镜像包含了一个完整 OS 的 lib 库以及应用依赖的 rpm 包,往往有几个 G 的大小。应用一下感觉发布过程变得非常慢了,有时慢到难以忍受。同时这个变化对分发网络和 Docker 镜像仓库也造成了非常大的压力。在大规模发布或扩容时,很容易把仓库的下载源打挂,发布失败率居高不下,严重影响了整个发布速度和体验。为了解决这个问题,我们成立了紧急攻坚小组,集中精力对发布扩容链条的各个环节做了大力优化。

首先,在存储上,AliDocker 镜像仓库的存储直接使用了阿里云的分布式文件存储产品 OSS。阿里内部的线下开发测试环境和线上正式生产环境在网络上是隔离的,而 OSS 产品在服务端做了线上和线下的打通。AliDocker 除了用 OSS 解决了镜像存储的高可用问题以外,也借助 OSS 的这个特性实现了线下 push 镜像线上 pull 镜像的功能。

其次,在分发架构上,由于阿里在全球各地都有机房,大规模扩容时除了异地机房延迟增加之外,还有可能把长传带宽打满,所以我们在每个地区搭建了镜像 mirror 和超级缓存中心。在节点上下载镜像的单个层时采用了类似 BT(BitTorrent) 的 P2P 链式分发技术,P2P 分发中超级缓存中心作为默认回源节点。这样镜像仓库 mirror 加链式分发组成的多级细粒度分布式分发网络大大加快了分发速度,彻底解决了服务端网络和存储的压力。

最后,在发布流程上,我们针对内部发布系统做了多项优化。比如采取了预热模式,线下构建好镜像后就直接异步分发到线上各地域的 mirror 中,分批发布中第一批机器在执行时,第二批机器就提前去 pull 镜像。另外把之前固定的分批发布策略改成了智能滚动分批。每个批次的机器发布执行过程中,往往总有几台长尾机器比较慢,如果等这些最慢的机器都执行完才去执行下一批,在实例很多的时候会拖慢整个发布的过程。改成智能滚动分批后,在第一批发布完成应用 owner 确认没有问题之后,后面批次的发布不会等待长尾实例结束就会直接执行下一批,这样大大提高了并行度,减少了发布自动执行过程中不必要的等待时间。

在所有这些优化之后,实例最多 (近 8 千个实例),发布最慢的那个应用,整体发布时间缩短到了原来的 1/5,并且发布成功率也大大提高,因分发问题带来的稳定性也随之消失。

3 对 Swarm 的定制和优化

今年双 11 的另外一个变化是,大部分的流量都跑在了云上;交易主链路的核心应用在云上和云下都有实例。在 AliDocker 出现之前,云上和非云是两套完全不同的虚拟化机制,云上是 ECS 中直接跑应用,云下是物理机的 T4 容器中跑应用,应用下层的虚拟化机制不同也造成云上和云下只能采用两套不同的运维发布系统,让整个运维体系比较痛苦和臃肿。AliDocker 出现后,将这 2 者统一了起来,云下在物理机上跑 AliDocker 容器,云上在 ECS 上跑 AliDocker 容器,应用及上层运维系统看到的都是 AliDocker 容器。统一的机制带来更简单的实现。我们在这个时间点引入了 Swarm 来做 Docker 容器的管控。Swarm 协议基本兼容 daemon 协议,只在很小的几个点做了改动,可以将一个物理机集群当做一台宿主机来操作,为集群背景下的测试和运维带来了非常大的便捷。我们对 Swarm 做了一些改造,使 Swarm 支持批量创建容器,功能类似后来 Docker1.12 版本的 swarm 模式引进的 replica 概念。因为我们绝大多数应用最小化的部署实体都是对等部署的,多个容器中跑的是完全相同的镜像和配置,因此只是将 Swarm 中一次创建容器的请求处理过程,并行在多个物理机上执行就达到了目的。至于这多个物理机如何选出来,我们现有的资源管理平台有一套自己的调度系统,因此我们修改了 Swarm 的调度部分直接对接到了我们自己的调度系统上,同时对接了我们内部的集中式 ip 资源管理系统。每个容器的 ip 独立于宿主机的 ip,不需要端口映射,就可以直接发布到服务注册中心,供其他应用直接调用。

这个定制化的 Swarm 产品在内部称为为 AliSwarm,除了调度之外的基础功能都与官方 Swarm 相同。但是随着 AliSwarm 接入的节点越来越多,官方 Swarm 的实现部分暴露出了诸多性能问题。比如 Swarm 内部存在系统线程会随连接数增长的问题,当 node 达到一定量时大批量增删 node 很容易造成 Swarm 实例直接 crash;在 node 节点数变多的情况下,总会有那么一部分 node 节点不那么健康,在这种网络频繁时断时续的极端情况下,Swarm 的内部处理存在连接泄露问题,会使系统资源消耗越来越大;每次大规模节点上下线时 node 列表会发生频繁变化刷新,内部识别哪些是新增 node 哪些是删除 node 时做的 diff 操作会大量消耗 cpu;另外对单个容器的查询需要遍历全集群的容器信息,当节点规模在 1W 以上时,这种遍历也会消耗大量 cpu,等等;AliSwarm 在逐渐接入整个电商规模节点的过程中逐步发现这些性能问题,并一一做了解决。官方 Swarm 单实例能够平稳运行的最大集群规模,按之前官方公布的数字是 1000 台宿主机。AliSwarm 在双 11 之前实际线上运行的单实例集群规模已经在 3 万以上,并且 32 核机器 cpu 的 load 在 5 以下,在双 11 建站期间能够支持并发 3 千个以上的实例同时扩容。

节点规模变大之后,每次 swarm 自身发布初始化过程会持续几分钟,系统可用性降低。同时我们有部分业务需要独占的隔离资源池,如果为每个资源池都搭建一套 Swarm 维护成本比较高。因此我们开发了 SwarmProxy 系统,做了基于 TLS 证书管理多个集群的功能。同时每个集群运行 2 个对等的实例,一主一备,同一时间,只有主实例提供服务。主实例发生故障时可以自动切换到热备实例。这样 AliSwarm 自身版本升级时,就不需要等待新实例初始化完成才能提供服务,而是先让旧实例继续提供服务,新实例启动初始化完成后替换原来的热备实例,成为新的热备,然后再做一次主备切换完成升级。这个主备切换过程会根据版本号大小和新版本初始化完成情况自动执行,毫秒级完成。

4 阿里中间件(Aliware)Docker 化

除了交易应用外,今年我们还推进了阿里中间件 (Aliware) 的 Docker 化,中间件相对于应用来说主要区别是有状态、性能敏感、资源需求差异大、有个性化的运维标准等。中间件的状态经过分析主要分为三类:数据状态、配置状态、运行时状态。针对数据状态,我们通过挂载 Volume 的方式,让所有需要持久化的数据,全部直接落到宿主机的指定目录中,以保证容器升级或变更后,数据能够不丢失;针对配置状态,我们采用了镜像和配置分离的方式,容器启动时,会根据启动参数或环境变量去配置中心动态获取运行时配置,通过这种方式可以实现在任何环境下均使用相同的镜像,以减少镜像构建和传输的成本;针对运行时状态,我们制定了中间件镜像标准和运行时管控标准,对容器进行操作的时候容器管控平台会按照既定标准和流程进行,以保证整个过程平滑和能够被容器内应用感知并进行相关前置操作。

阿里中间件 (Aliware) 作为集团内的 P0 级基础服务,对性能的要求近乎苛刻,我们在 Docker 化之初就定下目标,性能损失需要控制在 3~5% 之内。影响中间件性能的因素主要有网络、CPU、内存、磁盘、内核、依赖包等,所以在实施过程中,我们对每一款中间件均进行了详细的性能测试,测试场景涵盖物理机 +Docker、物理机 +VM+Docker、物理机 +T4,经过测试、内核、网络、容器、中间件等多个团队的通力合作,最终所有中间件 Docker 化后的性能均达到预期,并沉淀出了 Docker 化场景下针对不同性能影响因素的调优方案和策略。

阿里中间件 (Aliware) 对资源的诉求也比较多样,比如消息中间件对网络、磁盘需求较大;缓存中间件对内存需求较大;数据中间件强依赖 CPU 性能等,针对这种情况我们在资源调度上会均衡各产品需求,让有不同资源诉求的中间件共享宿主机资源,以保证宿主机的资源使用率保持在合理的范围,既节约了成本,又提升了中间件的稳定性和性能表现。在双 11 大促备战期间,我们还对 Docker 化的中间件进行了资源的精细化调整,测试并评估了超线程(HT)带来的影响,并对强依赖 CPU 的中间件进行了调核,以规避资源争抢风险,进一步提高了中间件的稳定性,此外,我们还具备 Docker 化中间件资源动态调整的能力,比如双 11 大促前,我们可以动态为数据中间件增加 CPU 配额、为消息中间件增加磁盘配额。

在阿里集团内部,中间件 (Aliware) 每一款产品都有自己的个性化运维需求和流程,在这样的背景下,我们以 AliDocker 为推手,完成了中间件统一运维标准和体系的建立,并产出了中间件 Caas 平台和场景化运维平台,中间件运维效率、资源管理效率均得到了极大提升,双 11 前我们实现了所有中间件的 Docker 化改造,并承担了线上 20%-100% 的流量,按计划到财年底我们将实现中间件的 100%Docker 化。

在今年刚刚过去的双 11 中,从 AliDocker 引擎到上层运维部署体系都经历了一次大考,最终交易全链路所有核心应用全部在 AliDocker 容器中圆满完成了 1207 亿成交额的答卷,也证明了 AliDocker 技术体系在电商交易级别的大规模应用中能够担负重任!

企业级互联网架构 Aliware,让您的业务能力云化:https://www.aliyun.com/aliware

http://jm.taobao.org/2017/04/06/20170406/

暂无回复。
需要 登录 后方可回复。