随着Kubernetes1.2v发布,K8S现在能支持1000个节点的集群(即1千万请求/秒),附带对大多数API操作(99%尾部这段)延迟降低80%。这意味着在最近的6个月内,K8S支持的容量增加了10倍同时还保证用户使用感受——99%pod启动时间少于3秒,大多数API操作99%延迟在几十毫秒(唯一例外是LIST操作,对于很大的集群需要几百毫秒)。Kubernetes 1.2v的千万并发令人乍舌?三个月后,K8S 1.3v将会再次带来10倍的提升。
kubernetes 1.2v千万并发实测,请看视频:
在这个视频里,我们看到集群规模上升到1000个节点上到达10MQPS(即每秒1千万请求),还包括了滚动更新,没有宕机时间和任何尾部延迟。这在互联网上也足以列入前百强的表现。
接下来,我们来介绍一下K8S是如何做到这些的,以及我们未来在K8S扩容性上进一步提高的计划。
方法论
我们对于K8S的扩容性做的基准是基于以下服务层面上的目标(ServiceLevel Objectives):
API的相应:99%的API调用返回时间都小于1秒
Pod启动时间:99%的pod和它们容器(pull好的镜像)在5秒内启动
只有这两点同时满足,我们才说K8S的扩容性到达了怎样怎样一个节点的数量。我们持续收集和报告这些测量数据来作为我们项目测试的框架,测试也相应的分成了两个部分:API相应时间和pod启动时间。
API响应
K8S为用户提供了一些抽象概念来代表他们的应用,比如说,用冗余控制器(即RC, Replicaiton Controller)作为一群pod的抽象。把所有RC列出来或把一个给定的RC所包含的所有pods列出来,就是一个很常见的场景(usecase)。但从另外一方面来说,很少会有需要去把系统里的所有pods列出来,比如说3万个pod(即比如1000个节点,每个节点有30个pod)意味着150MB的数据(即5KB/pod* 3万pods)。这个测试使用冗余控制器。
对于这个测试来说(假设N是集群里的节点数量),我们做了:
创建大约3N个的不同数量的冗余控制器(5,30,250副本),这样我们总共会有30N的副本。我们分步来进行它们的创建(即不是同时开始的),然后一直等到它们跑起来。
在每个冗余控制器上都进行一些操作(扩容,列出所有实例等),把这些操作也分步来做,来测试每个操作的延迟性。这个和一个真实的用户会进行的常规集群操作很类似。
停止和删除系统内的所有冗余控制器。
这些测试的结果,请看下面“Kubernetes 1.2参数”的数据。
在1.3版本中,我们计划会进一步延伸这些测试,内容会包含创建服务、部署、DaemonSets和其他API对象。
Pod启动时间端对端的延迟
用户对K8S来跳用和启动一个pod所需时间非常感兴趣。这个不仅仅是初次创建pod,而且也包括当节点失败的时候,冗余控制器需要多久来创建一个代替的pod。
对于这个测试来说(假设N是集群里的节点数量),我们做了:
创建一个单独的冗余控制器,有30*N的副本,等它们全部都跑起来。我们也跑高密度的测试,有100*N的副本,但集群内的节点数量少一些。
启用一系列的单个pod的冗余控制器-没200毫秒起一个。对于每一个,我们都测量“端到端启动总时间”(后面会具体定义这个时间)
停止和删除系统中所有冗余控制器和pods
端到端启动总时间,我们的定义是指从用户给API server 发送需要生成一个冗余控制器请求那刻开始,一直到pod的“running&ready”这个状态返回给用户,这个过程走表的时间。这意味着,“podstartup time”(pod启动时间)包含了RC的创建,依次序的话即创建pod、调度器调度pod、Kubernetes建立intra-pod的网络、启动容器、等待pod对健康检查成功回应,以及到最后pod把它的状态返回给API server,API server再给用户,这一整个过程的所需时间。
我们当然可以通过去掉等待的时间或者创建pod的时间来人为大大地缩短“pod startup time”(pod启动时间),但我们还是秉持坚信一个更为广义的定义来契合最为现实的场景,才能使广大用户理解他们对K8S性能的真实期待。
Kubernetes 1.2 实测数据
所以结果如何呢?我们再Google Compute Engine上跑了测试。对于1000个节点的集群,master使用了一个n1-standard-32的VM(32核,120GB内存)。
API响应
下面两张图表代表了 99% API调用的延迟在K8S 1.0版本和1.2版本之间的对比,基于100个节点的集群(柱状越短,表现越好)
对于LIST的操作,我们单独来呈现结果,因为这些操作的延迟要高很多。
我们也跑了1000个节点的集群的测试。
因为LIST操作要大的多,所以我们再一次把这些操作的测试结果单独来呈现:所有的延迟,在两个不同的集群尺寸下,都低于1秒。
pod启动端到端延迟
关于“pod启动时间延迟”的结果(即前面说到的“pod端到端延迟”的部分)显示在下图。为了有参考,我们把K8S1.0版本针对100个节点集群的结果也显示在了图里的第一部分。
由图可见,K8S 1.2 在性能上显著减少了100个节点集群尾部(即99%这段)延迟时间,现在在K8S可提供的最大集群尺寸范围内可以提供很低的pod启动延迟。跟6个月之前相比,K8S现在1000个节点的集群无论在API调用延迟和pod启动延迟上都有了全方面的提高。
Kubernetes 1.2性能飞跃是怎么做到的
在API server层面上创建“read cache”(read缓存) 参见:点我
在Kubelet里引入pod生命周期事件发生器(即PLEG -Pod Lifecycle Event Generator)参见:点我
提高调度器的流量 参见:点我
一个更高效的JSON parser
对Kubernetes 1.3版本的规划:
当然,我们工作还远未结束,我们会持续提高Kubernetes的性能,就像Google对内使用Borg那样,把K8S的scale增加到无穷大。基于对底层测试和生产环境中对容器集群的使用场景,我们目前对1.3已经有了如下规划:
目前的瓶颈依然还是API server,花费大量时间在给JSONobject进行排列。我们家化增加protocol buffer来为集群内的组件沟通以及在etcd内存储JSON objects做可选路径。用户依然可以使用JSON来跟APIserver进行沟通,但由于大量的K8S的沟通是集群内(API server向节点、调度器向API server等)。我们期待使用在master上CPU和memory的消耗会有显著降低。
Kubernetes使用标签来标示成组的objects。比如,来找到哪些pods属于一个给定的冗余控制器,会需要把所有在同一个namesapce下的并且还符合标签选择器的pod都扫一遍。因此对于做一个有效的标签索引的增加可以充分利用已有的APIobject缓存,这样能更快速的来查找并且匹配符合标签选择器的对象,速度会提高很多。
调度的决定来自于很多不同的因素,包括基于资源来分布pods,基于相同的选择器来分步pods(比如同一个服务、冗余控制器、工作等)等等。这些计算,尤其是选择器的分步,可能还是有改进空间的,参见:点我
再就是etcd 3.0的发布值得期待,其中在设计上就有Kubernetes应用场景的考虑,将会带来性能上的提高和引入新功能。CoreOS已经在开展把Kubernetes引入etcd3.0版本的工作,参见:点我
对于K8S 1.3的期待不至于这个列表,可以预见的是,我们将会在K8S1.3看到一个类似从1.0到1.2一样的飞跃。
结语
在过去的六个月,我们见证了Kubernetes性能的极大飞跃,能够跑1000个节点的集群,同时还具备和之前版本较小集群规模同样出色的回应性。但我们对此远远不满足,我们会把Kubernetes推到更强大,K8S1.3将会更大程度地提高系统的scale、性能和回应性,同时还会增加新的功能,使得K8S更好地来适应高需求的、基于容器集群的应用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。