对于蘑菇街而言,每年的 11.11 已经成为一年中最大的考验,考验的是系统稳定性,容灾能力,紧急故障处理,运维等各个方面的能力。蘑菇街的私有云平台,从无到有,已经经过了近一年的发展,生产环境上经历了 3 次大促,稳定性方面得到了初步验证。本文我将从架构、技术选型、应用等角度来谈谈蘑菇街的私有云平台。
另,ArchSummit 全球架构师峰会北京站将于 2015 年 12 月 18 日~19 日在北京国际会议中心召开,大会设置了《揭秘双十一背后的技术较量》专题来深入解读双十一背后的技术故事,欢迎关注。
蘑菇街的私有云平台(以下简称蘑菇街私有云)是蘑菇街面向内部上层业务提供的基础性平台。通过基础设施的服务化和平台化,可以使上层业务能够更加专注在业务自身,而不是关心底层运行环境的差异性。它通过基于Docker 的CaaS 层和KVM 的IaaS 层来为上层提供IaaS/PaaS 层的云服务,以提高物理资源的利用率,以及业务部署和交付的效率,并促进应用架构的拆分和微服务化。
在架构选型的时候,我们觉得Docker 的轻量化,秒级启动,标准化的打包/部署/运行的方案,镜像的快速分发,基于镜像的灰度发布等特性,都十分适合我们的应用场景。而Docker 自身的集群管理能力在当时条件下还很不成熟,因此我们没有选择刚出现的Swarm,而是用了业界最成熟的OpenStack,这样能同时管理Docker 和KVM 虚拟机。相对来说,Docker 适合于无状态,分布式的业务,KVM 适合对安全性,隔离性要求更高的业务。
对于上层业务来说,它不需要关心是运行在容器中,还是KVM 虚拟机里。今后的思路是应用的微服务化,把上层的业务进行拆分,变成一个个微服务,从而对接PaaS 基于容器的部署和灰度发布。
技术架构
在介绍双十一的准备工作之前,我先简单介绍一下蘑菇街私有云的技术架构。
我们采用的是OpenStack+novadocker+Docker 的架构模式,novadocker 是StackForge 上一个开源项目,它做为nova 的一个插件,通过调用Docker 的RESTful 接口来控制容器的启停等动作。每个Docker 就是所谓的“胖容器”,它会有独立的IP 地址,通过supervisord 来管理容器内的子进程,常见的如SSHD、监控agent 等进程。
我们在IaaS 的基础上自研了PaaS 层的编排调度等组件,实现了应用的弹性伸缩、灰度升级,支持一定的调度策略。我们通过Docker 和Jenkins 实现了持续集成(CI)。Git 中的项目如果发生了git push 等动作,便会触发Jenkins Job 进行自动构建,如果构建成功便会生成Docker Image 并push 到镜像仓库。基于CI 生成的Docker Image,可以通过PaaS 的API 或界面,进行开发测试环境的实例更新,并最终进行生产环境的实例更新,从而实现持续集成和持续交付。
网络方面,我们没有采用Docker 默认提供的NAT 网络模式,NAT 会造成一定的性能损失。通过OpenStack,我们支持Linux bridge 和openvswitch,不需要启动iptables,Docker 的性能接近物理机的95%。
准备工作
稳定性
迎战双11,最重要的当然是确保稳定性。通过近一年的产品化和实际使用,我们积累了丰富的提高稳定性的经验。
对于那些已遇到过的问题,需要及时采用各种方式进行解决或者规避。
比如说,CentOS6.5 对network namespace 支持不好,在Docker 容器内创建Linux bridge 会导致内核crash,upstream 在2.6.32-504 中修复了这个bug,因此线上集群的内核版本,必须升级至2.6.32-504 或以上。
又比如,CentOS6.5 自带的device mapper 存在dm-thin discard 导致内核可能随机crash,这个问题我们早在四月份的时候已经发现并解决了,解决的办法是关闭discard support,在docker 配置中添加“–storage-opt dm.mountopt=nodiscard --storage-opt dm.blkdiscard=false”,并且严格禁止磁盘超配,因为磁盘超配可能会导致整个device mapper 无法分配磁盘空间,而把整个文件系统变成只读,从而引起严重问题。
监控
我们在双11 前重点加强的是针对容器的监控。
在此之前,我们已经自研了一套container tools。主要功能有两个:一是能够以容器为粒度计算load 值,可以根据load 值进行容器粒度的qps 限流。二是替换了原有的top、free、iostat、uptime 等命令,确保运维在容器内使用常用命令时看到的是容器的值,而不是整个物理机的值。双十一之后我们还会把lxcfs 移植到我们的平台上来。
在宿主机上,我们增加了多维度的阈值监控和报警,包括对关键进程的存活性监控/语义监控,内核日志的监控,实时pid 数量的监控,网络连接跟踪数的监控,容器oom 的监控报警等等。
实时pid 数量监控
为什么要监控实时的pid 数量呢?因为目前的Linux 内核对pid 的隔离性支持是不完善的。还没有任何Linux 发行版能做到针对pid 按照容器粒度进行pid_max 限制。
曾经发生过一个真实的案例是:某个用户写的程序有bug,创建的线程没有及时回收,容器中产生了大量的线程,最后在宿主机上都无法执行命令或者ssh 登陆,报的错是"bash: fork: Cannot allocate memory",但是此时通过free 命令看到空闲的内存却是足够的。
为什么会这样呢?根本原因是内核中的pid_max(/proc/sys/kernel/pid_max) 是全局共享的。当一个容器中的pid 数目达到上限32768,会导致宿主机和其他容器无法创建新的进程。最新的4.3-rc1 才支持对每个容器进行pid_max 的限制。
内存使用监控
值得一提的是,我们发现cgroup 提供的内存使用值是不准确的,比真实使用的内存值要低。因为内核memcg 无法回收slab cache,也不对dirty cache 量进行限制,所以很难估算容器真实的内存使用情况。曾经发生过统计的内存使用率一到70-80%,就发生OOM 的情况。为此,我们调整了容器内存的计算算法,根据经验值,将cache 的40% 算做rss,调整后的内存计算比之前精确了不少。
日志乱序
还有一个问题是跑Docker 的宿主机内核日志中经常会产生字符乱序,这样会导致日志监控无法取到正确的关键字进行报警。
经过分析发现,这个跟我们在宿主机和Docker 容器中都跑了rsyslogd 有关。由于内核中只有一个log_buf 缓冲区,所有printk 打印的日志先放到这个缓冲区中,docker host 以及container 上的rsyslogd 都会通过syslog 从kernel 的log_buf 缓冲区中取日志,导致日志混乱。通过修改container 里的rsyslog 配置,只让宿主机去读kernel 日志,就能解决这个问题。
隔离开关
平时我们的容器是严格隔离的,我们做的隔离包括CPU、内存和磁盘IO,网络IO 等。但双十一的业务量可能是平时的十几倍或几十倍。我们为双十一做了不少开关,在压力大的情况下,我们可以为个别容器进行动态的CPU,内存等扩容或缩容,调整甚至放开磁盘iops 限速和网络的TC 限速。
健康监测
我们还开发了定期的健康监测,定期的扫描线上可能存在的潜在风险,真正做到提前发现问题,解决问题。
灾备和紧急故障处理
除了稳定性,灾备能力也是必须的,我们做了大量的灾备预案和技术准备。比如我们研究了不启动Docker Daemon 的情况下,离线恢复Docker 中数据的方法。具体来说,是用dmsetup create 命令创建一个临时的dm 设备,映射到Docker 实例所用的dm 设备号,通过mount 这个临时设备,就可以恢复出原来的数据。
我们还支持Docker 容器的冷迁移。通过管理平台的界面可以一键实现跨物理机的迁移。
与已有运维系统的对接
Docker 集群必须能与现有的运维系统无缝对接,才能快速响应,真正做到秒级的弹性扩容/缩容。我们有统一的容器管理平台,实现对多个 Docker 集群的管理,从下发指令到完成容器的创建可以在 7 秒内完成。
性能优化
我们从系统层面也对 docker 做了大量的优化,比如针对磁盘 IO 的性能瓶颈,我们调优了像 vm.dirty_expire_centisecs,vm.dirty_writeback_centisecs, vm.extra_free_kbytes 这样的内核参数。还引入了 Facebook 的开源软件 flashcache ,将 SSD 作为 cache,显著的提高 docker 容器的 IO 性能。
我们还通过合并镜像层次来优化 docker pull 镜像的时间。在 docker pull 时,每一层校验的耗时很长,通过减小层数,不仅大小变小,docker pull 时间也大幅缩短。
镜像
文件层数
文件大小
docker pull 时间
原镜像 13 1.051 GB 2m13 新镜像 1 674.4 MB 0m26
总结
总的来说,双 11 是对蘑菇街私有云的一次年终大考,对此我们已有了充分的准备。随着 Docker 集群部署的规模越来越大,我们还有很多技术难题有待解决,包括容器本身的隔离性问题,集群的弹性调度问题等等。同时我们也很关注 Docker 相关的开源软件 Kubernetes、Mesos、Hyper、criu、runC 的发展,未来将引入容器的热迁移,Docker Daemon 的热升级等特性。
如果大家想了解更多的话,可以关注我们的技术博客 http://mogu.io/ 。蘑菇街期待你的加入,一起来建设大规模的 Docker 集群。
作者介绍
郭嘉,蘑菇街平台技术部架构师,虚拟化组负责人。2014 年加入蘑菇街,目前主要专注于蘑菇街的私有云建设,关注 Docker、KVM、OpenStack、Kubernetes 等领域。邮箱:guojia@mogujie.com。
感谢郭蕾对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。
评论