ASI 2021 年双十一万级别超大规模集群的高性能提升

作者 | 韩堂 幻云 川义等


缘起统一调度和弹性调度


ASI 是 Alibaba Serverless infrastructure 的缩写,是针对云原生应用设计的统一基础设施。


为了实现最大化利用云的能力,通过统一调度,实现了 ASI 成为阿里集团所有业务的底座,包括新加入到统一调度架构的搜推广业务,实时计算 Flink 业务,FaaS 业务,中间件,新计算 PAI 等,以及通过统一调度来进行架构升级的 MaxCompute 业务, 泛电商业务等。ASI 通过一套架构成为所有业务和基础服务的底座,带来的是整体阿里集团的站点交付在容器和调度层面完成大一统,今年在云侧的交付效率提升,在 9.15 完成建站压测验收发挥了非常重要的作用。

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 1:统一调度的合作模式


在这个过程当中,统一调度是 ASI 技术底座,一层调度和各个二层调度,业务方一起通力合作(如图1),从研发,测试,发布一起完成技术大升级,以及通过业务迁移实施最终实现千万级核的规模,确保了双十一 9.15 的云侧顺利交付,并完成双十一大考。


在统一调度的架构基础上,通过弹性调度体系来完成资源和能效优化的目标。包括 CPUShare,CPU 归一化,VPA 垂直伸缩,Federation 集群联邦,重调度技术的规模化铺开,以及 HPA 横向扩缩,ECI 弹性调度的探索。


统一调度架构的升级,弹性调度体系的建设对集群规模化都提出了更高的需求,单集群规模化的需求成为了今年最大的挑战。如搜推广在离线集群实际达到了万级别的节点数,十万级别的 pod 数,调度吞吐千级别 pod/s;MaxCompute 业务 Task 链路达到了每秒十万级别的调度频次;在快上快下大促当天通过在大数据离线集群中快速拉起在线站点场景中,完成了大促当日多个交易导购单元站点的快速拉起和释放。


apiserver/scheduler/etcd/webhook/kubelet 上完成了大量的性能优化,具备行业领先性。


统一调度架构


在线场景下应用服务的资源约束多,追求最佳部署:既要保障应用服务的高可用性,还要保障应用服务的运行时效果,调度吞吐一般比较慢;离线场景下,尤其是以 MaxCompute 为代表的大数据计算场景任务规模大、任务规格小、运行周期短,就要求调度离线任务时需要具备很高的调度吞吐能力(十万级别的调度频次)。


针对在线以及搜索的离线我们采用的 K8s 原生的 pod 链路或 pod 兼容链路。针对 MaxCompute 采用自研的 Task 链路。MaxCompute 单集群上万台机器时,每秒十万级别的调度频次带来这样高频的资源流转对 Kube ApiServer 消息转发以及 etcd 造成很大压力,我们通过性能分析以及压测得出,K8s 的原生 pod 链路能力无法满足 MaxCompute 的性能需求。因此 ASI 统一调度在 K8s 原生 pod 链路上,创造出了基于 Pod 和 Task 双链路的统一调度架构。


统一调度架构规模化对 ASI 底座带来的全方位挑战


ASI 在统一调度中完成 2 个重要的角色,第一个是供给云原生资源,为业务提供 pod 对应的计算资源;第二个是提供状态数据库,为业务提供状态信息存储。基于 ASI 构建的搜推广等上面跑的离线业务,Blink、PAI、Holo 等新计算平台,APICallLatency  已经成为其计算链路服务 SLO 的关键部分,大促建站,快上快下的在线站点快速交付,APICallLatency 也成为其 Pod 交付 SLO 的关键部分。

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 2:性能 SLO 体系&服务调用管理大图-APICallLatency 成为 SLO 的关键部分

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 3:社区版本 K8s 的规模限制


面对社区 K8s 5000 的能力现状,ASI 需要满足统一调度万级别节点需要做些什么呢?会面临哪些挑战呢?


1)资源层面:随着集群规模增大,业务形态的变化,以 IP、云盘为代表的核心资源会打破已有计划性的资源供应,间断性的突发增长,造成资源短缺,出现云资源申请超时问题,造成 Pod 交付失败。


日常单集群每天十万级别的扩缩容量级,如果采用社区版本单机的 DaemonSet 直接访问阿里云 openapi 和 K8s api,对 ASI 的压力都是非常巨大的,都会很容易触发 ASI 或云 openapi 的限流,造成 Pod 交付超时失败。同时在 Serverless 场景下,对这块的扩容效率有更高的要求。


2)节点层面:随着节点规模增大,kubelet 无法及时更新 node 心跳时间问题,导致节点状态 NotReady,导致容器调度受影响,特别影响到训练作业的生产以及迁移。


3)APIServer 层面:随着 Pod 规模的增大,WatchCache 的大小满足不了 Pod 访问的要求,出现了大量的watch Error 及 relist 情况。


随着集群资源变化更大时,watch 的性能压力会越大,而在统一调度中,离线的单机客户端也会 watch pod,这意味着 pod 的 watch 请求直接翻倍。在快上快下场景下,需要数十分钟级别快速拉起 10 万 级别 pod,大规模的 event 推送延迟会更加严峻。


4)ETCD 层面:随着集群中资源对象数据量的增大,ETCD 存储的数据规模过大,引起 Latency 大幅上涨。


伴随着 Mesh、Dapr、ingress、安全 sidecar 等云原生的需求产生,也包括集团场景以及历史需求的适配和兼容, Pod Size 变得越来越大,阿里面临 50Kb 的 pod Size,远远超过 etcd 2k 性能边界。


同时伴随着单集群组件数量的暴增,超过 100 个以上组件,通过逐层的读写放大,最终造成请求量过多引起的 TooMany Request 问题也此起彼伏。


性能瓶颈的分析思考


统一调度项目对 ASI 单集群的规模化能力是强依赖的。


首先是搜推广独立集群年初计划数十个集群即将迁移 ASI,并进一步迁移统一调度协议。它上面的集群需要跑大量离线任务,这些离线任务扩缩容接口 QPS 将预计达到千级别 QPS。同时搜推广业务对管控面的可用性依赖比较高,管控面不可用中断时间过长可能会导致 P1、P2 级别故障,需要将管控面性能抖动或者异常恢复时长控制在安全时间范围内。


另外是 ODPS&电商混部场景,快上快下(大促当日在数分钟内完成站点的拉起和释放)第一次在 ASI 场景落地,另外快上快下第一次在 ASI 上进行落地,研发,性能优化和稳定性保障都面临挑战,新的链路对周边系统的系统压力变化也是优先要关注,并推动相关依赖方进行优化,包括实际我们发现快上快下会打满云底层存储云盘,统一调度多了一倍的离线组件,预计增加 1 倍 pod watch 等压力,这些都是需要重点解决的问题。

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 4:统一调度带来的挑战分析


同时除了要支撑今年双十一统一调度规模和吞吐等性能要求外,这次规模化建设当中,需要解决一个问题,就是能够持续回答 ASI 的 SLO,覆盖整个链路核心组件,通过具备性能压测常态化能力,能够持续对 ASI 进行模拟压测,回答在一定的规模下,ASI SLO 是多少?同时针对每个版本的压测性能情况,回答是否能满足 SLO。同时在整个压测过程中,除了像之前关注的最核心的 SLO 外,需要关注整个链路涉及到的相关组件,包括资源消耗怎么样的,组件的 failover 消耗时间是咋样的,稳定性风险在哪里(需要囊括运维组件,如监控等,核心的控制器等)。


ASI常态化压测-性能SLO可持续性保障


在面对统一调度规模化的需求时,我们首先做的是规模化推演,推演集群的压力,从数据推演压力和潜在的解决方案。但光有这些不够,重要的是建立起全链路的压测环境,这个我们基于 Kubemark 搭建了大规模集群模拟的平台,通过一个容器启动多个Kubemark 进程的方式,使用了 数百 个 4c 的容器模拟万级别节点的 kubelet。同时我们构建了多套稳定持续的压测环境,能够去根据不同的 K8s 版本进行仿真度提升,最终支撑线上的压测场景。

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 5:常态化压测能力的重点突破


针对不同场景,综合抽象出需要重点加强模拟的基础能力,包括:1)大规模的节点模拟;2)相关的组件,包括存储和网络组件等;3)业务 Sidecar 容器的模拟;4)统一调度离在线场景中的影子实例模式;5)大促快上快下的离线退涨水模拟等。


结合这些需要模拟增强的基础能力,以及需要的压测环*,我们重点针对常态化压测,进行整个压测服务的平台能力建设,包括原子压测能力,可随意定制组合的压测模板能力,压测流水线,以及压测自动报告分析产出的能力。

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 6:常态化压测平台的设计


在实际规模化优化压测验证过程,对 etcd 内核进行升级改造,测试版本验证过程中可能出现数据一致性问题导致集群不可用,集群数据恢复起来困难且耗时。为了减少 etcd 存储后端升级验证的效率,为了避免压测过程中升级的版本对压测环境进行破坏,保障常态化压测服务的稳定性,我们对压测环境进行改造,每一套压测环境是类似 kok 的架构,addon 组件都部署在 base 集群,指向压测集群,这样压测集群核心管控组件就可高频的恢复重建,加快优化的步伐。

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 7:常态化压测环境的高可用部署设计


通过压测环境,仿真度提升,以及压测平台的建设,单集群的压测丰富度能够很好的满足 ASI 集团双十一的需求,运行稳定,而且时间上有大幅降低,并且这些能力能够被其他场景所复用。

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 8:常态化压测建设后的效率提升

ASI优化实践


从管控的核心链路来看,主要的瓶颈点在于中心的组件,主要包括 APIServer,Etcd,Webbook,Controller(Operator)以及业务侧。除了 Etcd 外,其他 ASI 内部组件都具备一定的横向扩展能力。当然 APIServer 也不能无限制扩容,否则也会对 Etcd 造成过多的压力。我们可以从管控 Master 的角度来看,优化的策略是怎么样的:


1)客户端侧,包括 webhook,controller,operator,kubelet,各路 daemonset 等。针对客户端可以做 cache 优化,让各个 client 优先访问本地 informer cache,也需要做负载均衡优化,主要包括对 apiserver 的负载均衡,当然要想降低对存储侧的压力,需要控制器和 kubelet 进行优化合并写请求,减小对 ASI 链路的写放大,降低对 etcd 的写压力。同时针对客户端对服务端的各种压力,可以通过组件性能规范来完成改造,在组件启用,准入的时候进行规范校验是否满足,进而推动最佳实践的落地,包括推动组件的合并,下线,以及组件不合理 QPS 整改,json 转 pb 等。


2)服务端侧,可以从访问层,缓存层,存储层 3个层次进行优化。在访问层上重点建设了基于 ua limiter 和 api 的精细化限流能力等;在缓存层,我们重点建设了 cache 的索引优化以及 watch 优化,包括今年重点对 watch 的多索引优化,在存储层上重点通过 snappy 压缩算法对 pod 进行数据压缩。


3)存储侧,主要指的是 etcd 侧,一方面通过管控的其他组件降低对 etcd 的读写压力外,自身主要通过内核升级外,更多通过 etcd 的数据进一步分片,基于硬件的升级方案改造;其他也包括通过无阻塞 compact,multi boltdb,存储引擎切换来降低 etcd compact 的带来的抖动等。


4)业务侧,主要包括 ASI 上层的各个平台,以及具体的业务。这方面主要包括降低 pod 数据量大小,如 mesh 对 pod yaml 的改造,搜推广 C2 平台降低 pod yaml 的大小以及 pod 的个数,并推动业务侧基于 ASI 提供的基础防护能力和业务特征做更符合业务安全特性的防护能力,包括限流,限额等。

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 9:ASI 优化策略大图

APIServer性能优化Tips


ASI APIServer  Kubernetes 集群的所有外部请求访问入口,以及 Kubernetes 集群内部所有组件的协作枢纽。APIServer 具备了以下几方面的功能:

1)屏蔽后端数据持久化组件 etcd 的存储细节,并且引入了数据缓存,在此基础上对于数据提供了更多种类的访问机制。

2)通过提供标准 API,使外部访问客户端可以对集群中的资源进行 CRUD 操作。

3)提供了 list-watch 原语,使客户端可以实时获取到资源的状态。

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 10:ASI APIServer 优化大图


为了应对如此多的变量对大规模集群带来的复杂影响,我们采用了探索问题本质以不变应万变的方法。为了可以全面而且系统化地对 APIServer 进行优化,我们由下到上把  apiserver 整体分为二个层面,分别为存储层(storage+cache)、访问层。底层的 etcd 是 Kubernetes 元数据的存储服务,是 apiserver 的基石。存储层中的 storage 提供 apiserver 对 etcd 访问功能,包括 apiserver 对 etcd 的 list,watch,以及 CRUD 操作。存储层中的 cache 相当于是对 etcd 进行了一层封装:
1)提供了一层对来自客户端且消耗资源较大的 list-watch 请求的数据缓存,以此提升了 apiserver 的服务承载能力。2)同时,它也提供了按条件搜索的能力。上面的访问层提供了处理 CRUD 请求的一些特殊逻辑,同时对客户端提供各种资源操作服务。

1、数据压缩优化


在 K8s 中,所有的对象最终均会作为 key/value 存入 etcd,当 value 较大时,会对 etcd 造成很大的压力。由于业务的复杂性,阿里巴巴电商的 Pod 相比于社区的 Pod,复杂庞大的多,社区的 pod 存入 etcd 最终可能就1kb,但电商的 Pod 可能达到 20kb,而且由于 Service Mesh 技术的引入,他们会注入额外的 sidecar 容器,最终导致 ASI 的许多 Pod 都达到了 50K。


为了降低对 etcd 的压力,我们引入了 snappy 压缩优化:

  • 更新创建 pod 时,先用 snappy 压缩 pod 数据再写入 etcd
  • 读取 pod 时,从 etcd 读取数据,snappy 解压后再返回给客户端


有人或许担心引入 snappy 算法带来的额外的 CPU 消耗和延时,考虑到 K8s 对象本身的序列化开销和访问 etcd 的延时,解压缩的 CPU 消耗和延时几乎可以忽略不计。优化后,一般的pod的大小可以压缩为原来的 1/2,对于注入 sidecar 容器的 pod,由于 pod 内容同质化内容较多,可以压缩为原来的 1/3。


引入压缩优化后,由于底层数据格式的变化,如何上线、回滚变的尤为棘手,一般的做法是 关闭集群->数据格式转换->启动集群。为了保证集群不停服,我们采用热升级的方式开启或者关闭优化,确保开启snappy压缩优化后,kube-apiserver 也可以读取未压缩数据,关闭 snappy 压缩优化后,kube-apiserver 可以识别解压 snappy 数据。02


2、watch索引优化


watch 是整个 K8s 体系通信的核心,所有的控制器均是通过 ListWatch 拿到 K8s 对象的最新信息干活。当集群资源变化越大时,watch 的性能压力会越大,而在统一调度中,离线的单机客户端也会 watch pod,这意味着 pod 的 watch 请求直接翻倍。在快上快下场景下,我们碰到了大规模的 event 推送延迟,导致刚开始无法满足客户要求。


首先看一下 watch 的推送原理。首先 kube-apiserver 针对每一种资源会发起一个连接到 etcd,同时建立一个 event chan,接受 etcd 的 event,每一个客户端 watch apiserver 时,kube-apiserver 会为每个 client 建立一个 watcher chan,event 被 dispatch 到各个 watcher,各个 watcher 负责 filter 事件并推送出去。ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 11:watch 索引优化图解


为了解决 kubelet 这一类 watch 请求,kube-apiserver 引入了 triggerFunction 优化功能,他类似一个对 watcher 的索引,比如一个 pod 只能属于 kubelet,kube-apiserver dispatch 事件时,只需要将 event 推送至所属的 kubelet,其他 kubelet 的 watcher chan 可以直接忽略,这样可以大大降低 kube-apiserver 的性能消耗。


而在统一调度下,单机离线客户端的 watch 请求并没有做索引,且原生的 kube-apiserver 只支持设置单索引,导致了推送的大规模延时。我们原有的 triggerFunction 基础上,引入了 MultipleTriggerFunctions,支持设置多个索引。单个 event 的 99 分位推送延时从 5ms 降低至 0.1ms,CPU 的消耗从原有的 70 个 CPU 降低只 30 个 CPU,顺利满足了快上快下的需求。03


3、etcd多client并发优化


Kubernetes 针对每一种资源会创建一个 grpc 连接至 etcd,所有的读/写/watch 请求均通过该通道完成,当集群规模变大、QPS 增加到一定程度时,我们发现 etcd 出现较大的访问延时,对比了 etcd 服务端的延时,发现客户端和服务端延时相差较大,客户端延时明显大于服务端延时。我们对所有资源的均创建了多个 client,并发访问 etcd,而针对部分访问需求较多的资源(pods 等)额外加大了并发,降低了 etcd 访问延时。


4、精细化限流和限流管理


我们引入了精细化限流方式,可以从 user agent(kubelet/kub-scheduler 等)、resource(pods/nodes 等)、verb(get/list/update)等不同维度限流。

List 操作是对 kube-apiserver 性能影响最大的操作,数次对 Pod 的全量 List 就可以导致 kube-apiserver 直接 OOM,绝大多数的 List 请求可能只是读取部分符合条件的 pod。因此我们进一步精细化了 List 限流保证 kube-apiserver 的稳定性。此外我们还开启了社区最新的 APF 限流,可以控制不同等级的组件获得不同的并发访问量,优先保证核心链路组件的访问质量。

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 12:限流策略对比,结合社区,可管理性我们选择了 APF 和 UA-Limiter


限流策略如何管理,数百套集群,每套集群规模都不太一样,集群节点数、pod 数都是不同的,内部组件有近百个,每个组件请求的资源平均有 4 种,对不同资源又有平均 3 个不同的动作,如果每个都做限流,那么规则将会爆炸式增长,即便做收敛后维护成本也非常的高。因此我们抓最核心的,核心资源 pod\node、核心动作(创建、删除、大查询);最大规模的,daemonset 组件、PV/PVC 资源。并结合线上实际流量分析,梳理出二十条左右的通用限流策略,并将其纳入到集群交付流程中实现闭环。当新的组件接入,我们也会对其做限流设计,如果比较特殊的,则绑定规则并在集群准入和部署环节自动下发策略,如果出现大量的限流情况,也会触发报警,由 SRE 和研发去跟进优化和解决。05


5、protobuf 改造


服务器端的优化是一方面,客户端的优化也很重要。protobuf 改造就是是其中一项重要的优化,客户端可以通过 json/yaml/protobuf 多种格式获取 kube-apiserver 数据,protobuf 相比 json 的序列化效率相比快了 5 倍,因此让使用了 protobuf 协议可以更快的全量 List 数据。这在控制器的 ListWatch 场景显得尤为重要,ListWatch 的机制是首先 List 全量数据,然后发起 Watch 请求获取增量数据,假如 List 的 latency 过长,会直接导致 Watch 失败,进而导致 ListWatch 失效,控制器开始反复 List 数据,造成系统雪崩。


因此我们通过组件规范,推动所有的客户端以 protobuf 格式访问 kube-apiserver 的核心资源(pods/nodes)。后续我们可能考虑在 http 这一层引入 snappy 压缩算法,来进一步降低客户端和服务器端的 List 延时。


6、多路 apiserver 架构


核心方案就是通过对 apiserver 进行分组,通过不同的优先级策略进行对待,从而对服务进行差异化 SLO 保障。通过分流以降低主链路 apiserver 压力,针对 P2 及以下组件接入旁路 apiserver,并可以在紧急情况(如自身稳定性收到影响)下,做整体限流。

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 13:APIServer 多路架构

Etcd优化Tips


etcd 是 K8s 集群中存储元数据,是 K8s 的基石,它的性能往往影响着整个集群的响应时间。当集群规模突破一定规模时,曾出现如下性能瓶颈问题:

  • etcd 出现大量的读写延迟,延迟甚至可达分钟级
  • kube-apiserver 查询 pods/nodes/configmap/crd 延时很高,导致 etcd oom
  • etcd list-all pods 时长可达 30 分钟以上
  • 控制器无法及时感知数据变化,如出现 watch 数据延迟可达 30s 以上等
  • event 压力大影响 lease 数据,进而引起组件频繁选主。


1、Etcd 内核升级


我们深入研究了 etcd 内部的实现原理,并发现了影响 etcd 扩展性的一个关键问题在底层 bbolt db 的 page 页面分配算法上:随着 etcd 中存储的数据量的增长,bbolt db 中线性查找“连续长度为 n 的 page 存储页面”的性能显著下降。


为了解决该问题,我们设计了基于 segregrated hashmap 的空闲页面管理算法,hashmap 以连续 page 大小为 key,连续页面起始 page id 为 value。通过查这个 segregrated hashmap 实现 O(1) 的空闲 page 查找,极大地提高了性能。在释放块时,新算法尝试和地址相邻的 page 合并,并更新 segregrated hashmap。通过这个算法改进,我们可以将 etcd 的存储空间从推荐的 2GB 扩展到 100GB,极大的提高了 etcd 存储数据的规模,并且读写无显著延迟增长。


我们也和谷歌工程师协作开发了 etcd raft learner(类 zookeeper observer)/fully concurrent read 等特性,在数据的安全性和读写性能上进行增强。这些改进已贡献开源。


2、Etcd单资源拆分


进一步,我们通过将 API Server 中不同类型的对象存储到不同的 etcd 集群中。从 etcd 内部看,也就对应了不同的数据目录,通过将不同目录的数据路由到不同的后端 etcd 中,从而降低了单个 etcd 集群中存储的数据总量,提高了扩展性。


实际大集群中,我们是这样进行拆分的:1)把访问最核心的资源放在了一起,如 pod,configmap,endpoint,lease 等;CRD 资源放在了第二个 etcd 集群;Event 放在了一个独立集群。

ASI 2021 年双十一万级别超大规模集群的高性能提升

图 14:etcd 拆分


整个拆分主要考虑安全原则和数据热点,这样既能提高性能,又能减少核心主 etcd 故障因素,包括:

1)重要数据白名单机制从原来的集群中迁出,用于重点保护,如 pod,node 数据;

2)观察数据例如 CR 等从原来集群中迁出,避免对原有集群核心数据的影响;

3)考虑热点 key 负载打散;

4)考虑延时和增长情况;

5)考虑各个资源对象数据的情况以及增长情况,如 Node 数,Pod 数,service 数,CR 数等。


2、Etcd 硬件升级


etcd 集群对磁盘 IO 时延非常敏感,我们对比了云盘,本地盘(nvme, optane, AEP)的性能,最终发现 optane 和 AEP 的设备性能有很大提升。考虑到长期维护问题,因此我们选择了云上标准的 AEP 机型。


但 AEP 机型属于本地盘,它也存一些劣势,在故障迁移时会面临更多挑战,特别是 etcd 的故障迁移,处理时长,冷热备数据的安全性,我们在本地盘基于自研的 operator 增加了这部功能,并配置相应的 1-5-10 能力。03


3、Etcd 参数调优


1)etcd 使用 boltdb 作为底层数据库存储 kv, 它的使用优化对整体性能影响很大。通过调节不同的 batch size 和 interval, 使我们可以根据不同硬件和工作负载优化性能。

2)compact的压缩周期04


4、multi boltdb


当这种单一集群 etcd 性能承压的情况下,我们需要水平扩展多个 etcd 集群。目前我们已经使用了 K8s apiserver 的不同资源拆分到不同 etcd 的能力实现了基本的拆分功能,实现了不错的效果。


但是我们看到还有一些新的需求例如单一 pod 资源本身就会有非常大的存储压力的场景,我们需要进行进一步的优化,这里我们在 etcd server 层做数据拆分。


etcd 内部单一使用一个存储 boltdb 底层数据库,利用单一 WriteTX, ReadTX 进行读写。当数据量超大时,单一 db 压力很大。我们在前期测试中发现 compact 清理时,boltdb 上清理压力很大,进而导致整个集群出现堆积,造成验收不符合预期。


因此,我们将 etcd 底层存储层 boltdb 进行水平拆分扩展,类似常见的数据库分库分表,具体内部使用 hash 策略进行存储对象的分配策略。具体设计如下图:

ASI 2021 年双十一万级别超大规模集群的高性能提升

ASI 2021 年双十一万级别超大规模集群的高性能提升图 15:multi boltdb


在这里,etcd 内部新加入一层中间层 MultiTX 层统一处理上层对底层 boltdb 的读写功能,并将这些请求按照 hash 策略路由读写请求到不同的底层 boltdb。compact 也分别在不同 boltb 里独立进行,分担压力。


Webhook&Controller优化Tips


webhook 承接 api-server 操作完资源后的回调,类似于一个 http 请求所经过的中间件。在 ASI 集群中大量注入逻辑和验证 都是 webhook 做的,例如 pod 的 sidecar 注入, postStartHook 注入,failizer 的注入, 级连删除的校验等。所以,webhook 在集群中属于核心链路组件。webhook 的不可用会导致集群中所有资源的变更都不可用。webhook 的延迟会导致 apiserver 的延迟,因此 webhook 的性能直接影响了 api-server 的性能,从而影响整个集群的规模化能力。

1、使用 protobuf 协议请求 APIServer


webhook&controller 在请求 API-Server 的时候,如果是 get/list 操作,会优先请求本地 informer。在建立和更新本地 informer 的过程中,webhook&controller 会全量 list APIServer。此时使用 protobuf 协议 相对于 json 协议可以消耗更少的资源,更快的建立 informer 本地缓存。

2、减少深拷贝操作


通过本地 Informer, webhook&controller 通过 list 方法获取数据时,避免了请求 APIServer,但是依然要对获取到的数据进行 DeepCopy 操作。但是这个 DeepCopy 操作并非一定需要的,只有对资源进行修改操作时,才需要 DeepCopy。为此,webhook&controller 在 List 方法里减少了 DeepCopy 操作,业务在获取到 List 对象之后再按需进行深拷贝操作 。

3、减少序列化/反序列操作


一次 webhook 回调请求中,会有多个 plugin 针对同一个资源进行 admit 操作。如果每一次操作都需要进行反序列化解析,那么会带来重复性计算。为此,webhook 每一次 admit 操作基于上一次操作的结果,这样反序列就可以减少到一次。在返回给 APIServer 的序列化的过程中,webhook 根据 admit 后的对象跟传入的对象相比,如果没有发生改变,那就直接返回给 APIServer,不需要经过序列化计算。

4、优化反序列操作


webhook&controller 存在大量的字符串发序化操作,其占据了 65%以上的 cpu 资源, 30%以上的内存资源。为此,我们从业务的角度出发,按需反序列化解析。对于没有使用到的字段,就不进行反序列化。同时,我们采用了 社区的 json-iterator/go 包代替了 golang 提供的 encoding/json 包。这样整体操作下来,json 相关的反序列化操作资源消耗降低到了 30%以下。

5、合并写请求,减少写放大


频繁请求 Api-Server 的原因在于在处理 reconcile 中存在着多次跟 api-server 交互请求,例如读取 all-namespace. 修改 annotation, 修改 fialnaizer,update 对象时遇到 reconflict 冲突。这些都会导致跟 api-server 的交互请求,我们针对扩缩容核心链路的写请求进行分析降低了 30%。

6、快速 failover


controller 中存储着近百万的对象,从 API Server 获取这些对象并反序列化的开销是无法忽略的,重 Controller 恢复时可能需要花费几分钟才能完成这项工作,这对于阿里巴巴规模的企业来说是不可接受的。为了减小组件升级对系统可用性的影响,我们需要尽量的减小 controller 单次升级对系统的中断时间,这里通过提前加载数据的方案来解决这个问题:1)预启动备 controller informer,提前加载 controller 需要的数据;2)主 controller 升级时,会主动释放 Leader Lease,触发备立即接管工作。


Kubelet优化Tips


1、对APIServer负载均衡


高可用集群实际的运行中,可能会出现多个 API Server 之间的负载不均衡,尤其是在集群升级或部分节点发生故障重启的时候。这给集群的稳定性带来了很大的压力,原本计划通过这样高可用的方式分摊 API Server 面临的压力,但在极端情况下所有压力又回到了一个节点,导致系统响应时间变长,甚至击垮该节点继而导致雪崩。


在 API Server 测增加 SLB,所有的 kubelets 连接 SLB,这个也是阿里云 ACK 的标准做法。


我们针对 client,特别是大量的 kubelet 节点增加一个核心功能:定期地重建连接切换 API Server 完成洗牌;同时在 kubelet 上针对一个时间段内频繁的收到 429 时,尝试重建连接切换 API Server。02


2、降低写放大


K8s pod 写放大问题非常严重,给 apisever/etcd 带来很大压力,泛电商一般场景 23 次,搜推广 2.5 协议大概 5 次,3.0 协议 host 网络 9 次、非 host 网络 15 次,可以通过合并请求优化,在搜索高吞吐场景中,目前 kubelet 侧优化从 5 次降低为 1 次。


业务侧专项改造举例


业务侧包括搜索 c2,mesh, faas 等合作方都进行了很多的改造。这里列一下安全为例:


安全基于 Mesh 的 Sidecar 改造

1)对接上文中提到的 APIServer 多路架构中的旁路;

2)CR 资源治理,包括把各个资源的数量从 O(n))降低为 O(1)常数级别;

3)  Pod 资源优化,主要通过合并容器,环境变量,挂载合并等缩小 pod yaml 大小等。


ASI 作为云原生的引领实施者,它的高性能,高可用,它的稳定性影响着甚至决定着阿里集团和云产品的业务的发展,真诚希望容器领域感兴趣的同学进行深入交流,更期待大家的加入,一起在云端构建云的新界面,让我们的用户用好云,感兴趣的同学欢迎来撩:zhiqing.ht@alibaba-inc.comen.xuze@alibaba-inc.comhantang.cj@taobao.com


上一篇:PMP学习笔记3:项目经理角色


下一篇:容器技术入门2:使用K8S搭建游戏应用