山东前网站建设,wordpress 代码质量,信誉好的郑州网站建设,前端网站开发工具本文根据美团基础架构部/容器研发中心技术总监欧阳坚在2018 QCon#xff08;全球软件开发大会#xff09;上的演讲内容整理而成。 背景 美团的容器集群管理平台叫做HULK。漫威动画里的HULK在发怒时会变成“绿巨人”#xff0c;它的这个特性和容器的“弹性伸缩”很像#xf… 本文根据美团基础架构部/容器研发中心技术总监欧阳坚在2018 QCon全球软件开发大会上的演讲内容整理而成。 背景 美团的容器集群管理平台叫做HULK。漫威动画里的HULK在发怒时会变成“绿巨人”它的这个特性和容器的“弹性伸缩”很像所以我们给这个平台起名为HULK。貌似有一些公司的容器平台也叫这个名字纯属巧合。 2016年美团开始使用容器当时美团已经具备一定的规模在使用容器之前就已经存在的各种系统包括CMDB、服务治理、监控告警、发布平台等等。我们在探索容器技术时很难放弃原有的资产。所以容器化的第一步就是打通容器的生命周期和这些平台的交互例如容器的申请/创建、删除/释放、发布、迁移等等。然后我们又验证了容器的可行性证实容器可以作为线上核心业务的运行环境。 2018年经过两年的运营和实践探索我们对容器平台进行了一次升级这就是容器集群管理平台HULK 2.0。 把基于OpenStack的调度系统升级成容器编排领域的事实标准Kubernetes以后简称K8s。提供了更丰富可靠的容器弹性策略。针对之前在基础系统上碰到的一些问题进行了优化和打磨。美团的容器使用状况是目前线上业务已经超过3000个服务容器实例数超过30000个很多大并发、低延时要求的核心链路服务已经稳定地运行在HULK之上。本文主要介绍我们在容器技术上的一些实践属于基础系统优化和打磨。 美团容器平台的基本架构 首先介绍一下美团容器平台的基础架构相信各家的容器平台架构大体都差不多。 首先容器平台对外对接服务治理、发布平台、CMDB、监控告警等等系统。通过和这些系统打通容器实现了和虚拟机基本一致的使用体验。研发人员在使用容器时可以和使用VM一样不需要改变原来的使用习惯。 此外容器提供弹性扩容能力能根据一定的弹性策略动态增加和减少服务的容器节点数从而动态地调整服务处理能力。这里还有个特殊的模块——“服务画像”它的主要功能是通过对服务容器实例运行指标的搜集和统计更好的完成调度容器、优化资源分配。比如可以根据某服务的容器实例的CPU、内存、IO等使用情况来分辨这个服务属于计算密集型还是IO密集型服务在调度时尽量把互补的容器放在一起。再比如我们可以知道某个服务的每个容器实例在运行时会有大概500个进程我们就会在创建容器时给该容器加上一个合理的进程数限制比如最大1000个进程从而避免容器在出现问题时占用过多的系统资源。如果这个服务的容器在运行时突然申请创建20000个进程我们有理由相信是业务容器遇到了Bug通过之前的资源约束对容器进行限制并发出告警通知业务及时进行处理。 往下一层是“容器编排”和“镜像管理”。容器编排解决容器动态实例的问题包括容器何时被创建、创建到哪个位置、何时被删除等等。镜像管理解决容器静态实例的问题包括容器镜像应该如何构建、如何分发、分发的位置等等。 最下层是我们的容器运行时美团使用主流的LinuxDocker容器方案HULK Agent是我们在服务器上的管理代理程序。 把前面的“容器运行时”具体展开可以看到这张架构图按照从下到上的顺序介绍 最下层是CPU、内存、磁盘、网络这些基础物理资源。往上一层我们使用的是CentOS7作为宿主机操作系统Linux内核的版本是3.10。我们在CentOS发行版默认内核的基础上加入一些美团为容器场景研发的新特性同时为高并发、低延时的服务型业务做了一些内核参数的优化。再往上一层我们使用的是CentOS发行版里自带的Docker当前的版本是1.13同样加入了一些我们自己的特性和增强。HULK Agent是我们自己开发的主机管理Agent在宿主机上管理Agent。Falcon Agent同时存在于宿主机和容器内部它的作用是收集宿主机和容器的各种基础监控指标上报给后台和监控平台。最上一层是容器本身。我们现在主要支持CentOS 6和CentOS 7两种容器。在CentOS 6中有一个container init进程它是我们开发容器内部的1号进程作用是初始化容器和拉起业务进程。在CentOS 7中我们使用了系统自带的systemd作为容器中的1号进程。我们的容器支持各种主流编程语言包括Java、Python、Node.js、C/C等等。在语言层之上是各种代理服务包括服务治理的Agent、日志Agent、加密Agent等等。同时我们的容器也支持美团内部的一些业务环境例如set信息、泳道信息等配合服务治理体系可以实现服务调用的智能路由。美团主要使用了CentOS系列的开源组件因为我们认为Red Hat有很强的开源技术实力比起直接使用开源社区的版本我们希望Red Hat的开源版本能够帮助解决大部分的系统问题。我们也发现即使部署了CentOS的开源组件仍然有可能会碰到社区和Red Hat没有解决的问题。从某种程度上也说明国内大型互联公司在技术应用的场景、规模、复杂度层面已经达到了世界领先的水平所以才会先于社区、先于Red Hat的客户遇到这些问题。 容器遇到的一些问题 在容器技术本身我们主要遇到了4个问题隔离、稳定性、性能和推广。 隔离包含两个层面第一个问题是容器能不能正确认识自身资源配置第二个问题是运行在同一台服务器上的容器会不会互相影响。比如某一台容器的IO很高就会导致同主机上的其他容器服务延时增加。稳定性这是指在高压力、大规模、长时间运行以后系统功能可能会出现不稳定的问题比如容器无法创建、删除因为软件问题发生卡死、宕机等问题。性能在虚拟化技术和容器技术比较时大家普遍都认为容器的执行效率会更高但是在实践中我们遇到了一些特例同样的代码在同样配置的容器上服务的吞吐量、响应时延反而不如虚拟机。推广当我们把前面几个问题基本上都解决以后仍然可能会碰到业务不愿意使用容器的情况其中原因一部分是技术因素例如容器接入难易程度、周边工具、生态等都会影响使用容器的成本。推广也不是一个纯技术问题跟公司内部的业务发展阶段、技术文化、组织设置和KPI等因素都密切相关。容器的实现 容器本质上是把系统中为同一个业务目标服务的相关进程合成一组放在一个叫做namespace的空间中同一个namespace中的进程能够互相通信但看不见其他namespace中的进程。每个namespace可以拥有自己独立的主机名、进程ID系统、IPC、网络、文件系统、用户等等资源。在某种程度上实现了一个简单的虚拟让一个主机上可以同时运行多个互不感知的系统。 此外为了限制namespace对物理资源的使用对进程能使用的CPU、内存等资源需要做一定的限制。这就是Cgroup技术Cgroup是Control group的意思。比如我们常说的4c4g的容器实际上是限制这个容器namespace中所用的进程最多能够使用4核的计算资源和4GB的内存。 简而言之Linux内核提供namespace完成隔离Cgroup完成资源限制。namespaceCgroup构成了容器的底层技术rootfs是容器文件系统层技术。 美团的解法、改进和优化 隔离 之前一直和虚拟机打交道但直到用上容器才发现在容器里面看到的CPU、Memory的信息都是服务器主机的信息而不是容器自身的配置信息。直到现在社区版的容器还是这样比如一个4c4g的容器在容器内部可以看到有40颗CPU、196GB内存的资源这些资源其实是容器所在宿主机的信息。这给人的感觉就像是容器的“自我膨胀”觉得自己能力很强但实际上并没有还会带来很多问题。 上图是一个内存信息隔离的例子。获取系统内存信息时社区Linux无论在主机上还是在容器中内核都是统一返回主机的内存信息如果容器内的应用按照它发现的宿主机内存来进行配置的话实际资源是远远不够的导致的结果就是系统很快会发生OOM异常。 我们做的隔离工作是在容器中获取内存信息时内核根据容器的Cgroup信息返回容器的内存信息类似LXCFS的工作。 CPU信息隔离的实现和内存的类似不再赘述这里举一个CPU数目影响应用性能例子。 大家都知道JVM GC垃圾对象回收对Java程序执行性能有一定的影响。默认的JVM使用公式“ParallelGCThreads (ncpus 8) ? ncpus : 3 ((ncpus * 5) / 8)” 来计算做并行GC的线程数其中ncpus是JVM发现的系统CPU个数。一旦容器中JVM发现了宿主机的CPU个数通常比容器实际CPU限制多很多这就会导致JVM启动过多的GC线程直接的结果就导致GC性能下降。Java服务的感受就是延时增加TP监控曲线突刺增加吞吐量下降。针对这个问题有各种解法 显式的传递JVM启动参数“-XX:ParallelGCThreads”告诉JVM应该启动几个并行GC线程。它的缺点是需要业务感知为不同配置的容器传不同的JVM参数。在容器内使用Hack过的glibc使JVM通过sysconf系统调用能正确获取容器的CPU资源数。我们在一段时间内使用的就是这种方法。其优点是业务不需要感知并且能自动适配不同配置的容器。缺点是必须使用改过的glibc有一定的升级维护成本如果使用的镜像是原生的glibc问题也仍然存在。我们在新平台上通过对内核的改进实现了容器中能获取正确CPU资源数做到了对业务、镜像和编程语言都透明类似问题也可能影响OpenMP、Node.js等应用的性能。 有一段时间我们的容器是使用root权限进行运行实现的方法是在docker run的时候加入‘privilegedtrue’参数。这种粗放的使用方式使容器能够看到所在服务器上所有容器的磁盘导致了安全问题和性能问题。安全问题很好理解为什么会导致性能问题呢可以试想一下每个容器都做一次磁盘状态扫描的场景。当然权限过大的问题还体现在可以随意进行mount操作可以随意的修改NTP时间等等。 在新版本中我们去掉了容器的root权限发现有一些副作用比如导致一些系统调用失败。我们默认给容器额外增加了sys_ptrace和sys_admin两个权限让容器可以运行GDB和更改主机名。如果有特例容器需要更多的权限可以在我们的平台上按服务粒度进行配置。 Linux有两种IODirect IO和Buffered IO。Direct IO直接写磁盘Buffered IO会先写到缓存再写磁盘大部分场景下都是Buffered IO。 我们使用的Linux内核3.X社区版本中所有容器Buffer IO共享一个内核缓存并且缓存不隔离没有速率限制导致高IO容器很容易影响同主机上的其他容器。Buffer IO缓存隔离和限速在Linux 4.X里通过Cgroup V2实现有了明显的改进我们还借鉴了Cgroup V2的思想在我们的Linux 3.10内核实现了相同的功能每个容器根据自己的内存配置有对应比例的IO CacheCache的数据写到磁盘的速率受容器Cgroup IO配置的限制。 Docker本身支持较多对容器的Cgroup资源限制但是K8s调用Docker时可以传递的参数较少为了降低容器间的互相影响我们基于服务画像的资源分配对不同服务的容器设定不同的资源限制除了常见的CPU、内存外还有IO的限制、ulimit限制、PID限制等等。所以我们扩展了K8s来完成这些工作。 业务在使用容器的过程中产生core dump文件是常见的事比如C/C程序内存访问越界或者系统OOM的时候系统选择占用内存多的进程杀死默认都会生成一个core dump文件。 社区容器系统默认的core dump文件会生成在宿主机上由于一些core dump文件比较大比如JVM的core dump通常是几个GB或者有些存在Bug的程序其频发的core dump很容易快速写满宿主机的存储并且会导致高磁盘IO也会影响到其他容器。还有一个问题是业务容器的使用者没有权限访问宿主机从而拿不到dump文件进行下一步的分析。 为此我们对core dump的流程进行了修改让dump文件写到容器自身的文件系统中并且使用容器自己的Cgroup IO吞吐限制。 稳定性 我们在实践中发现影响系统稳定性的主要是Linux Kernel和Docker。虽然它们本身是很可靠的系统软件但是在大规模、高强度的场景中还是会存在一些Bug。这也从侧面说明我们国内互联网公司在应用规模和应用复杂度层面也属于全球领先。 在内核方面美团发现了Kernel 4.x Buffer IO限制的实现问题得到了社区的确认和修复。我们还跟进了一系列CentOS的Ext4补丁解决了一段时间内进程频繁卡死的问题。 我们碰到了两个比较关键的Red Hat版Docker稳定性问题 在Docker服务重启以后Docker exec无法进入容器这个问题比较复杂。在解决之前我们用nsenter来代替Docker exec并积极反馈给RedHat。后来Red Hat在今年初的一个更新解决了这个问题。https://access.redhat.com/errata/RHBA-2017:1620是在特定条件下Docker Daemon会Panic导致容器无法删除。经过我们自己Debug并对比最新的代码发现问题已经在Docker upstream中得到解决反馈给Red Hat也很快得到了解决。https://github.com/projectatomic/containerd/issues/2面对系统内核、Docker、K8s这些开源社区的系统软件存在一种观点是我们不需要自己分析问题只需要拿社区的最新更新就行了。但是我们并不认同我们认为技术团队自身的能力很重要主要是如下原因 美团的应用规模大、场景复杂很多问题也许很多企业都没有遇到过不能被动的等别人来解答。对于一些实际的业务问题或者需求例如容器内正确返回CPU数目社区也许觉得不重要或者不是正确的理念可能就不会解决。社区很多时候只在Upstream解决问题而Upstream通常不稳定即使有Backport到我们正在使用的版本排期也很难进行保障。社区会发布很多补丁通常描述都比较晦涩难懂。如果没有对问题的深刻理解很难把遇到的实际问题和一系列补丁联系起来。对于一些复杂问题社区的解决方案不一定适用于我们自身的实际场景我们需要自身有能力进行判断和取舍。美团在解决开源系统问题时一般会经历五个阶段自己深挖、研发解决、关注社区、和社区交互最后贡献给社区。 性能 容器平台性能主要包括两个方面性能 业务服务运行在容器上的性能。容器操作创建、删除等等的性能。 上图是我们CPU分配的一个例子我们采用的主流服务器是两路24核服务器包含两个Node每个12核算上超线程共48颗逻辑CPU。属于典型的NUMA非一致访存架构系统中每个Node有自己的内存Node内的CPU访问自己的内存的速度比访问另一个Node内存的速度快很多差一倍左右。 过去我们曾经遇到过网络中断集中到CPU0上的问题在大流量下可能导致网络延时增加甚至丢包。为了保证网络处理能力我们从Node0上划出了8颗逻辑CPU用来专门处理网络中断和宿主机系统上的任务例如镜像解压这类高CPU的工作这8颗逻辑CPU不运行任何容器的Workload。 在容器调度方面我们的容器CPU分配尽量不跨Node实践证明跨Node访问内存对应用性能的影响比较大。在一些计算密集型的场景下容器分配在Node内部会提升30%以上的吞吐量。按Node的分配方案也存在一定的弊端会导致CPU的碎片增加为了更高效地利用CPU资源。在实际系统中我们会根据服务画像的信息分配一些对CPU不敏感的服务容器跨Node使用CPU资源。 上图是一个真实的服务在CPU分配优化前后响应延时的TP指标线对比。可以看到TP999线下降了一个数量级所有的指标都更加平稳。 性能优化文件系统 针对文件系统的性能优化第一步是选型根据统计到的应用读写特征我们选择了Ext4文件系统超过85%的文件读写是对小于1M文件的操作。 Ext4文件系统有三种日志模式 Journal写数据前等待Metadata和数据的日志落盘。Ordered只记录Metadata的日志写Metadata日志前确保数据已经落盘。Writeback仅记录Metadata日志不保证数据比Metadata先落盘。我们选择了Writeback模式默认是oderded它在几种挂载模式中速度最快缺点是发生故障时数据不好恢复。我们大部分容器处于无状态故障时在别的机器上再拉起一台即可。因此我们在性能和稳定性中选择了性能。容器内部给应用提供可选的基于内存的文件系统tmpfs可以提升有大量临时文件读写的服务性能。 如上图所示在美团内部创建一个虚拟机至少经历三步平均时间超过300秒。使用镜像创建容器平均时间23秒。容器的灵活、快速得到了显著的体现。 容器扩容23秒的平均时间包含了各个部分的优化如扩容链路优化、镜像分发优化、初始化和业务拉起优化等等。接下来本文主要介绍一下我们做的镜像分发和解压相关的优化。 上图是美团容器镜像管理的总体架构其特点如下 存在多个Site。支持跨Site的镜像同步根据镜像的标签确定是否需要跨Site同步。每个Site有镜像备份。每个Site内部有实现镜像分发的P2P网络。镜像分发是影响容器扩容时长的一个重要环节。 跨Site同步保证服务器总能从就近的镜像仓库拉取到扩容用的镜像减少拉取时间降低跨Site带宽消耗。基础镜像预分发美团的基础镜像是构建业务镜像的公共镜像通常有几百兆的大小。业务镜像层是业务的应用代码通常比基础镜像小很多。在容器扩容的时候如果基础镜像已经在本地就只需要拉取业务镜像的部分可以明显的加快扩容速度。为达到这样的效果我们会把基础镜像事先分发到所有的服务器上。P2P镜像分发基础镜像预分发在有些场景会导致上千个服务器同时从镜像仓库拉取镜像对镜像仓库服务和带宽带来很大的压力。因此我们开发了镜像P2P分发的功能服务器不仅能从镜像仓库中拉取镜像还能从其他服务器上获取镜像的分片。从上图可以看出随着分发服务器数目的增加原有分发时间也快速增加而P2P镜像分发时间基本上保持稳定。 Docker的镜像拉取是一个并行下载串行解压的过程为了提升解压的速度我们美团也做了一些优化工作。 对于单个层的解压我们使用并行解压算法替换Docker默认的串行解压算法实现上是使用pgzip替换gzip。 Docker的镜像具有分层结构对镜像层的合并是一个“解压一层合并一层再解压一层再合并一层”的串行操作。实际上只有合并是需要串行的解压可以并行起来。我们把多层的解压改成并行解压出的数据先放在临时存储空间最后根据层之间的依赖进行串行合并。前面的改动并行解压所有的层到临时空间导致磁盘IO的次数增加了近一倍也会导致解压过程不够快。于是我们使用基于内存的Ramdisk来存储解压出来的临时文件减轻了额外文件写带来的开销。做了上面这些工作以后我们又发现容器的分层也会影响下载加解压的时间。上图是我们简单测试的结果无论对于怎么分层的镜像并行解压都能大幅提升解压时间对于层数多的镜像提升更加明显。 推广 推广容器的第一步是能说出容器的优势我们认为容器有如下优势 轻量级容器小、快能够实现秒级启动。应用分发容器使用镜像分发开发测试容器和部署容器配置完全一致。弹性可以根据CPU、内存等资源使用或者QPS、延时等业务指标快速扩容容器提升服务能力。这三个特性的组合可以给业务带来更大的灵活度和更低的计算成本。 因为容器平台本身是一个技术产品它的客户是各个业务的RD团队因此我们需要考虑下面一些因素 产品优势推广容器平台从某种程度上讲自身是一个ToB的业务首先要有好的产品它相对于以前的解决方案虚拟机存在很多优势。和已有系统打通这个产品要能和客户现有的系统很好的进行集成而不是让客户推翻所有的系统重新再来。原生应用的开发平台、工具这个产品要易于使用要有配合工作的工具链。虚拟机到容器的平滑迁移最好能提供从原有方案到新产品的迁移方案并且容易实施。与应用RD紧密配合要提供良好的客户支持即使有些问题不是这个产品导致的也要积极帮忙解决。资源倾斜从战略层面支持颠覆性新技术资源上向容器平台倾斜没有足够的理由尽量不给配置虚拟机资源。总结 Docker容器加Kubernetes编排是当前容器云的主流实践之一美团容器集群管理平台HULK也采用了这样的方案。本文主要分享了美团在容器技术上做的一些探索和实践。内容主要涵盖美团容器云在Linux Kernel、Docker和Kubernetes层面做的一些优化工作以及美团内部推动容器化进程的一些思考欢迎大家跟我们交流、探讨。 作者简介 欧阳坚2006年毕业于清华大学计算机系拥有12年数据中心开发管理经验。曾任VMware中国Staff Engineer无双科技CTO中科睿光首席架构师。现任美团基础架构部/容器研发中心技术总监负责美团容器化的相关工作。招聘信息 美团点评基础架构团队诚招Java高级、资深技术专家Base北京、上海。我们是集团致力于研发公司级、业界领先基础架构组件的核心团队涵盖分布式监控、服务治理、高性能通信、消息中间件、基础存储、容器化、集群调度等技术领域。欢迎有兴趣的同学投送简历到 liuxing14meituan.com。