PaaS容器集群优化之路

来源:互联网 发布:程序员前景 编辑:程序博客网 时间:2024/05/29 02:16


本文探讨了在一个复杂的PaaS系统中,如何系统化、科学化的进行全系统的性能优化工作。


性能优化面对的挑战


以下是整个PaaS平台的架构:



其中主要包括这些子系统:


  • 微服务治理框架:为应用提供自动注册、发现、治理、隔离、调用分析等一系列分布式/微服务治理能力,屏蔽分布式系统的复杂度。

  • 应用调度与资源管理框架:打通从应用建模、编排部署到资源调度、弹性伸缩、监控自愈的生命周期管理自动化。

  • 应用开发流水线框架:打通从编写代码提交到自动编译打包、持续集成、自动部署上线的一系列CI/CD全流程自动化。

  • 云中间件服务:应用云化所需的数据库、大数据、通信和应用中间件服务;通过服务集成管控可集成传统非云化的中间件能力。


面对一个如此复杂的系统,性能优化工作是一个非常艰巨的挑战,这里有这么一些痛点:


  • 源代码及开发组件多,100+ git repo,整体构建超过1天

  • 运行架构复杂,全套安装完需要30+VM,200+进程

  • 软件栈深,网络平面复杂

  • 集群规模大,5k — 10k节点环境搭建非常困难

  • 系统操作会经过分布式的多个组件,无法通过单一组件诊断发现系统瓶颈

  • 无法追踪上千个处于不同层次的API的时延和吞吐

  • 大部分开发人员专注于功能开发,无法意识到自己的代码可能造成性能问题


优化分析


那么,对于这么一个大的、复杂的系统,从方法论的角度来讲,应该怎么去优化呢?基本思路就是做拆分,把一个大的问题分解为多个互相不耦合的维度,进行各个击破。从大的维度来讲,一个PaaS容器集群,可以分为3个大的子系统。


  1. 控制子系统:控制指令的下发和运行(k8s),例如创建pod

  2. 业务流量子系统:容器网络(flannel)、负载均衡(ELB/kube-proxy)

  3. 监控子系统:监控告警数据的采集(kafka, Hadoop)


这个看起来仅仅是一个架构上的划分,那么如何和具体的业务场景对应起来呢?我们可以考虑如下一个场景,在PaaS平台上大批量的部署应用。看看在部署应用的过程中,会对各个子系统产生什么压力。


  • 应用软件包大小:400M

  • 应用模板大小:10M

  • 1000个节点,每个节点一个POD,一个实例

  • 10种类型的软件包,依赖长度为3,10GB 网络

  • 调度及资源管理 3VM


这是一个典型的部署应用的一些规格,那么对于这样的一个输入,我们可以按照架构把压力分解到每个子系统上,这样得出的子系统需要支撑的指标是:


  1. 控制子系统: Kubernetes调度速度 > 50 pods/s,仓库支持300并发下载,>40M/s

  2. 数据子系统:overlay容器网络TCP收发性能损耗 <5%

  3. 监控子系统:在上面这个场景中不涉及,但可以从别的场景大致告警处理能力100条/秒


这里的业务场景:架构分析:子系统指标,这三者是m:1:n的,也就是说在不同场景下对不同的组件的性能要求不同,最后每个组件需要取自己指标的最大值。


指标决定了后续怎么进行实验测试,而测试是要花较大时间成本的,所以在指标的选取上要求少求精,尽量力图用2-3个指标衡量子系统。


优化测试 & 工具


上面讲的还是偏纸上的推演和分析,接下来进入实战阶段



对于服务器后端的程序来讲,推荐使用Promtheus这个工具来做指标的定义和采集。Promtheus的基本工作原理是:后端程序引入Promtheus的SDK,自定义所有需要的测量的指标,然后开启一个http的页面,定期刷新数据。Promtheus服务器会定期抓取这个页面上的数据,并存在内部的时间序列数据库内。这种抓而非推的方式减少了对被测试程序的压力,避免了被测程序要频繁往外发送大量数据,导致自身性能反而变差而导致测量不准确。Promtheus支持这几种数据类型:


  • 计数(对应收集器初始化方法NewCounter、NewCounterFunc、NewCounterVec,单一数值,数值一直递增,适合请求数量统计等)

  • 测量(对应收集器初始化方法NewGauge、NewGaugeFunc、NewGaugeVec,单一数值,数值增减变动,适合CPU、Mem等的统计)

  • 直方图测量(对应收集器初始化方法NewHistogram、NewHistogramVec,比较适合时长等的统计)

  • 概要测量(对应收集器初始化方法NewSummary、NewSummaryVec,比较适合请求时延等的统计)


我们可以看看在Kubernetes项目里面是怎么用的:


var (
   // TODO(a-robinson): Add unit tests for the handling of these metrics once
   // the upstream library supports it.
   requestCounter = prometheus.NewCounterVec(
       prometheus.CounterOpts{
           Name: "apiserver_request_count",
           Help: "Counter of apiserver requests broken out for each verb, API resource, client, and HTTP response contentType and code.",
       },
       []string{"verb", "resource", "client", "contentType", "code"},
   )
   requestLatencies = prometheus.NewHistogramVec(
       prometheus.HistogramOpts{
           Name: "apiserver_request_latencies",
           Help: "Response latency distribution in microseconds for each verb, resource and client.",
           // Use buckets ranging from 125 ms to 8 seconds.
           Buckets: prometheus.ExponentialBuckets(125000, 2.0, 7),
       },
       []string{"verb", "resource"},
   )
   requestLatenciesSummary = prometheus.NewSummaryVec(
       prometheus.SummaryOpts{
           Name: "apiserver_request_latencies_summary",
           Help: "Response latency summary in microseconds for each verb and resource.",
           // Make the sliding window of 1h.
           MaxAge: time.Hour,
       },
       []string{"verb", "resource"},
   )
)


在这里,一个http请求被分为verb, resource, client, contentType, code这五个维度,那么后面在PromDash上就能图形化的画出这些请求的数量。 从而分析哪种类型的请求是最多,对系统造成最大压力的,如图:



除了Promtheus,还可以引入其他的测量手段,对系统进行分析。



  • 在Kubernetes调度过程中,各个状态Pod的数量,看哪一步是最卡的



  • go pprof分析,哪些函数是最耗CPU的


优化开发


发现了瓶颈之后,下一步就是解决瓶颈,和具体业务逻辑有关,本文在这里就不做过多的阐释。需要对相关代码非常熟悉,在不改变功能的情况下增强性能,基本思路为并发/缓存/去除无用步骤等。


优化成果


这是我们在Kubernetes项目上控制面优化的成果:


控制面指标华为的分支数据社区版数据Master节点数量5无明确数据Node节点(kubemark模拟)数量10000节点5000节点部署吞吐率> 100 pod/s约为500 pod/sPod端到端延时< 2 s< 5 sAPI延时< 79.32 ms< 1 s


这里仅仅显示了控制子系统的指标,其他子系统还没有支持那么大的集群,尤其在网络方面,不同用户的网络架构差别很大。所以数据仅供参考


优化的优化


在上面的优化过程当中,基本上工程师要做几百次优化的测试和开发。这里会产生一个循环:


  • 测试寻找瓶颈点

  • 修改代码突破这个瓶颈点

  • 重新测试验证这段代码是否有效,是否需要改优化思路


这就是一个完整的优化的迭代过程,在这个过程当中,大部分时间被浪费在构建代码、搭建环境、输出报告上。开发人员真正思考和写代码的时间比较短。为了解决这个问题,就需要做很多自动化的工作。在Kubernetes优化的过程中,有这么几项方法可以节省时间:



  • kubemark模拟器 :社区项目,使用容器模拟虚拟机,在测试中模拟比达到1:20,也就是一台虚拟机可以模拟20台虚拟机对apiserver产生的压力。在测试过程当中,我们使用了500台虚拟机,模拟了10000节点的控制面行为。

  • CI集成:提交PR后自动拉性能优化分支并开始快速构建

  • CD集成:使用I层的快照机制,快速搭建集群并执行测试案例输出测试报告


以上都是在实践过程中总结的一些点,对于不同的项目工程应该有很多点可以做进一步的优化,提升迭代效率。


在搭建完这套系统后,我们发现这个系统可以从源头上预防降低系统性能的代码合入主线。如果一项特性代码造成了性能下降,在CI的过程当中,功能开发者就能收到性能报告,这样开发者就能自助式的去查找自己代码的性能问题所在,减少性能工程师的介入。


Q&A


Q:节点资源充足情况下,Docker的运行性能会持续下降,有什么方法可以检测Daemon?A:这个问题是个好问题,我观察到的是Docker Daemon CPU耗的比较多,可以打开pprof测量下哪个函数耗的最多。


Q:再详细介绍一下如何进行性能优化的,有没有什么具体的优化指标?

A:Kubernetes管理子系统的指标是API时延,Pod从创建到运行时延,Pod从创建到启动吞吐。


Q:对于应用程序包分发是否做过相关优化,传统应用的程序包都比较大?A:一个是要做好镜像分层,应用构建时就把运行时和应用分开,另一个就是在镜像下载时做P2P分发,这个我们内部做过,阿里的那个容器项目也做过不过都没开源,简单山寨一个其实也不难。


Q:Pod从创建到启动不是由kubelet和Docker决定的吗?瓶颈会在哪儿,挂volume,加载network plugin?

A:Pod创建要从调用Kubernetes API创建Pod对象开始,后面要经过调度,调度的时延还行,但一旦大量Pod被创建,吞吐就慢了,要排队调度。kubelet的那些操作本身也还行,比下载镜像要快。很多问题是规模问题,在一个万节点的集群上你会发现不少操作都会慢。


Q:如果发现应用程序本身需要优化,如何增加断点分析哪一步逻辑业务可能造成了瓶颈问题,比如你们能不能模拟用户体验?看是哪一部用户操作造成了延迟?嗯?

A:这个问题比较泛,单从哪一部分用户来说。Promtheus内可以分用户的维度来统计。也就是说同样一些API操作,它能帮你按多个维度来分析,可以安增删改查,也可以按请求时延来排序,帮你发现什么操作是最慢的。断点方式,Kubernetes的代码里面有tracelog。


基于Kubernetes的DevOps实践培训


本次培训内容包含:Kubernetes架构、安装、深入了解Kubernetes、Kubernetes高阶——设计与实现、Kubernetes落地实践、微服务、Cloud Native等,点击识别下方二维码加微信好友了解具体培训内容



点击阅读原文链接即可报名。