蚂蚁团体运维着可能是寰球最大的 K8s 集群:K8s 官网以 5k node 作为 K8s 规模化的高峰,而蚂蚁团体事实上运维着规模达到 10k node 规模的 K8s 集群。一个形象的比喻就是,如果官网以及跟着官网的 K8s 使用者能设想到的 K8s 的集群规模是泰山,那么蚂蚁团体在官网的解决方案之上曾经实现了一个珠穆朗玛峰,引领了 K8s 规模化技术的晋升。
这个量级的差别,不仅仅是量的差别,更是 K8s 治理保护的质的晋升。能保护有如此微小挑战巨量规模的 K8s 集群,其背地起因是蚂蚁团体付出了远大于 K8s 官网的优化致力。
所谓万丈高楼平地起,本文着重探讨下蚂蚁团体的在 K8s 的基石 — etcd 层面做出的高可用建设工作:只有 etcd 这个基石稳当了,K8s 这栋高楼大厦才放弃稳定性,有 tidb 大佬黄东旭朋友圈佐证【图片已获黄总受权】。
面临的挑战
etcd 首先是 K8s 集群的 KV 数据库。
从数据库的角度来看,K8s 整体集群架构各个角色如下:
- etcd 集群的数据库
- kube-apiserver etcd 的 API 接口代理、数据缓存层
- kubelet 数据的生产者和消费者
- kube-controller-manager 数据的消费者和生产者
- kube-scheduler 数据的消费者和生产者
etcd 实质是一个 KV 数据库,存储了 K8s 本身资源、用户自定义的 CRD 以及 K8s 零碎的 event 等数据。每种数据的一致性和数据安全性要求不统一,如 event 数据的安全性小于 K8s 本身的资源数据以及 CRD 数据。
K8s 的晚期拥护者在推广 K8s 时,声称其比 OpenStack 的劣势之一是 K8s 没有应用音讯队列,其提早比 OpenStack 低。这其实是一个误会,无论是 etcd 提供的 watch 接口,还是 K8s client 包中的 informer 机制,无不表明 K8s 是把 etcd 当做了音讯队列,K8s 音讯的载体很多,譬如 K8s event。
从音讯队列的角度来看,K8s 整体集群架构各个角色如下:
- etcd 音讯路由器
- kube-apiserver etcd 生产者音讯代理和音讯播送【或者成为次级音讯路由器、消费者代理】
- kubelet 音讯的生产者和消费者
- kube-controller-manager 音讯的消费者和生产者
- kube-scheduler 音讯的消费者和生产者
etcd 是推模式的音讯队列。etcd 是 K8s 集群的 KV 数据库和音讯路由器,充当了 OpenStack 集群中的 MySQL 和 MQ 两个角色,这样的实现貌似简化了集群的构造,但其实不然。在 large scale 规模 K8s 集群中,个别教训,首先都会应用一个独自 etcd 集群存储 event 数据:把 KV 数据和一部分 MQ 数据物理隔离开,实现了 KV 和 MQ 角色的局部拆散。如 参考文档 2 中提到美团“针对 etcd 的经营,通过拆分出独立的 event 集群升高主库的压力”。
当 K8s 集群规模扩充时,etcd 承载着 KV 数据剧增、event 音讯暴增以及音讯写放大的三种压力。
为了证实所言非虚,特援用局部数据为佐证:
- etcd KV 数据量级在 100 万以上;
- etcd event 数据量在 10 万以上;
- etcd 读流量压力峰值在 30 万 pqm 以上,其中读 event 在 10k qpm 以上;
- etcd 写流量压力峰值在 20 万 pqm 以上,其中写 event 在 15k qpm 以上;
- etcd CPU 经常性飙升到 900% 以上;
- etcd 内存 RSS 在 60 GiB 以上;
- etcd 磁盘使用量可达 100 GiB 以上;
- etcd 本身的 goroutine 数量 9k 以上;
- etcd 应用的用户态线程达 1.6k 以上;
- etcd gc 单次耗时常态下可达 15ms。
应用 Go 语言实现的 etcd 治理这些数据十分吃力,无论是 CPU、内存、gc、goroutine 数量还是线程使用量,基本上都靠近 go runtime 治理能力极限:常常在 CPU profile 中观测到 go runtime 和 gc 占用资源超过 50% 以上。
蚂蚁的 K8s 集群在经验高可用我的项目保护之前,当集群规模冲破 7 千节点规模时,曾呈现如下性能瓶颈问题:
- etcd 呈现大量的读写提早,提早甚至可达分钟级;
- kube-apiserver 查问 pods / nodes / configmap / crd 延时很高,导致 etcd oom;
- etcd list-all pods 时长可达 30 分钟以上;
- 2020 年 etcd 集群曾因 list-all 压力被打垮导致的事变就达好几起;
- 控制器无奈及时感知数据变动,如呈现 watch 数据提早可达 30s 以上。
如果说这种情况下的 etcd 集群是在刀锋上跳舞,此时的整个 K8s 集群就是一个活火山:稍不留神就有可能背个 P 级故障,彼时的整个 K8s master 运维工作大略是整个蚂蚁团体最危险的工种之一。
高可用策略
实现一个分布式系统高可用能力的晋升,大略有如下伎俩:
- 晋升本身稳定性与性能;
- 精密治理上游流量;
- 保障服务上游服务 SLO。
etcd 通过社区与各方使用者这么多年的锻炼,其本身的稳定性足够。蚂蚁人能做到的,无非是使出周扒皮的本事,进步集群资源整体利用率,scale out 和 scale up 两种技术手段并行不悖,尽可能的晋升其性能。
etcd 本身作为 K8s 的基石,其并无上游服务。如果说有,那也是其本身所应用的物理 node 环境了。上面别离从 etcd 集群性能晋升、申请流量治理等角度论述咱们在 etcd 层面所做出的高可用能力晋升工作。
文件系统降级
在山窝里飞出金凤凰,诚非易事。让 etcd 跑的更快这件事,没有什么伎俩比提供一个高性能的机器更短平快地奏效了。
1. 应用 NVMe ssd
etcd 本身 = etcd 程序 + 其运行环境。晚期 etcd 服务器应用的磁盘是 SATA 盘,通过简略地测试发现 etcd 读磁盘速率十分慢,老板豪横地把机器鸟枪换炮 — 降级到应用了 NVMe SSD 的 f53 规格的机器:etcd 应用 NVMe ssd 存储 boltdb 数据后,随机写速率可晋升到 70 MiB/s 以上。
参考文档 2 中提到美团“基于高配的 SSD 物理机器部署能够达到日常 5 倍的高流量拜访”,可见晋升硬件性能是大厂的首选,能折腾机器千万别节约人力。
2. 应用 tmpfs
NVMe ssd 虽好,实践上其读写极限性能跟内存比还是差一个数量级。咱们测试发现应用 tmpfs【未禁止 swap out】替换 NVMe ssd 后,etcd 在读写并发的状况下性能依然能晋升 20% 之多。考查 K8s 各种数据类型的特点后,思考到 event 对数据的安全性要求不高然而对实时性要求较高的特点,咱们毫不犹豫的把 event etcd 集群运行在了 tmpfs 文件系统之上,将 K8s 整体的性能晋升了一个档次。
3. 磁盘文件系统
磁盘存储介质降级后,存储层面可能进一步做的事件就是钻研磁盘的文件系统格局。目前 etcd 应用的底层文件系统是 ext4 格局,其 block size 应用的是默认的 4 KiB。咱们团队曾对 etcd 进行单纯的在单纯写并行压测时发现,把文件系统降级为 xfs,且 block size 为 16 KiB【在测试的 KV size 总和 10 KiB 条件下】时,etcd 的写性能依然有晋升空间。
但在读写并发的状况下,磁盘自身的写队列简直毫无压力,又因为 etcd 3.4 版本实现了并行缓存读,磁盘的读压力简直为零,这就意味着:持续优化文件系统对 etcd 的性能晋升空间简直毫无帮忙。自此以后单节点 etcd scale up 的要害就从磁盘转移到了内存:优化其内存索引读写速度。
4. 磁盘通明大页
在古代操作系统的内存治理中,有 huge page 和 transparent huge page 两种技术,不过个别用户采纳 transparent huge page 实现内存 page 的动静治理。在 etcd 运行环境,敞开 transparent huge page 性能,否则 RT 以及 QPS 等经常性的监控指标会经常性的呈现很多毛刺,导致性能不安稳。
etcd 调参
MySQL 运维工程师常被人称为“调参工程师”,另一个有名的 KV 数据库 RocksDB 也不遑多让,二者可调整的参数之多到了令人发指的中央:其要害就在于针对不同存储和运行环境须要应用不同的参数,能力充分利用硬件的性能。etcd 随不迭之,但也不拉人后,预计当前其可调整参数也会越来越多。
etcd 本身也对外裸露了很多参数调整接口。除了阿里团体 K8s 团队已经做出的把 freelist 由 list 改良为 map 组织模式优化外,目前惯例的 etcd 可调整参数如下:
- write batch
- compaction
1.write batch
像其余惯例的 DB 一样,etcd 磁盘提交数据时也采纳了定时批量提交、异步写盘的形式晋升吞吐,并通过内存缓存的形式均衡其延时。具体的调整参数接口如下:
- batch write number 批量写 KV 数目,默认值是 10k;
- batch write interval 批量写事件间隔,默认值是 100 ms。
etcd batch 这两个默认值在大规模 K8s 集群下是不适合的,须要针对具体的运行环境调整之,防止导致内存应用 OOM。个别地法则是,集群 node 数目越多,这两个值就应该成比例减小。
2.compaction
etcd 本身因为反对事务和音讯告诉,所以采纳了 MVCC 机制保留了一个 key 的多版本数据,etcd 应用定时的 compaction 机制回收这些过期数据。etcd 对外提供的压缩工作参数如下:
- compaction interval 压缩工作周期时长;
- compaction sleep interval 单次压缩批次距离时长,默认 10 ms;
- compaction batch limit 单次压缩批次 KV 数目,默认 1000。
(1)压缩工作周期
K8s 集群的 etcd compaction 能够有两种路径进行 compaction:
- etcd 另外提供了 comapct 命令和 API 接口,K8s kube-apiserver 基于这个 API 接口也对外提供了 compact 周期参数;
- etcd 本身会周期性地执行 compaction;
- etcd 对外提供了本身周期性 compaction 参数调整接口,这个参数的取值范畴是 (0, 1 hour];
- 其意义是:etcd compaction 即只能关上不能敞开,如果设置的周期时长大于 1 hour,则 etcd 会截断为 1 hour。
蚂蚁 K8s 团队在通过测试和线下环境验证后,目前的压缩周期取值教训是:
- 在 etcd 层面把 compaction 周期尽可能地拉长,如取值 1 hour,形同在 etcd 本身层面敞开 compaction,把 compaction interval 的精密调整权交给 K8s kube-apiserver;
- 在 K8s kube-apiserver 层面,依据线上集群规模取值不同的 compaction interval。
之所以把 etcd compaction interval 精密调整权调整到 kube-apiserver 层面,是因为 etcd 是 KV 数据库,不不便经常性地启停进行测试,而 kube-apiserver 是 etcd 的缓存,其数据是弱状态数据,相对来说启停比拟不便,不便调参。至于 compaction interval 的取值,一条教训是:集群 node 越多 compaction interval 取值能够适当调大。
compaction 实质是一次写动作,在大规模集群中频繁地执行 compaction 工作会影响集群读写工作的延时,集群规模越大,其延时影响越显著,在 kube-apiserver 申请耗时监控上体现就是有频繁呈现地周期性的大毛刺。
更进一步,如果平台上运行的工作有很显著的波谷波峰个性,如每天的 8:30 am ~ 21:45 pm 是业务高峰期,其余时段是业务波峰期,那么能够这样执行 compaction 工作:
- 在 etcd 层面设定 compaction 周期是 1 hour;
- 在 kube-apiserver 层面设定 comapction 周期是 30 minutes;
- 在 etcd 运维平台上启动一个周期性工作:以后时间段在业务波谷期,则启动一个 10 minutes 周
期的 compaction 工作。
其本质就是把 etcd compaction 工作交给 etcd 运维平台,当产生电商大促销等全天无波谷的非凡长周期时间段时,就能够在平台上紧急敞开 compaction 工作,把 compaction 工作对失常的读写申请影响升高到最低。
(2)单次压缩
即便是单次压缩工作,etcd 也是分批执行的。因为 etcd 应用的存储引擎 boltdb 的读写模式是多读一写:能够同时并行执行多个读工作,然而同时刻只能执行一个写工作。
为了避免单次 compaction 工作始终占用 boltdb 的读写锁,每次执行一批固定量【compaction batch limit】的磁盘 KV 压缩工作后,etcd 会开释读写锁 sleep 一段时间【compaction sleep interval】。
在 v3.5 之前,compaction sleep interval 固定为 10 ms,在 v3.5 之后 etcd 曾经把这个参数凋谢进去不便大规模 K8s 集群进行调参。相似于 batch write 的 interval 和 number,单次 compaction 的 sleep interval 和 batch limit 也须要不同的集群规模设定不同的参数,以保障 etcd 安稳运行和 kube-apiserver 的读写 RT 指标安稳无毛刺。
运维平台
无论是 etcd 调参,还是降级其运行的文件系统,都是通过 scale up 的伎俩晋升 etcd 的能力。还有两种 scale up 伎俩尚未应用:
- 通过压测或者在线获取 etcd 运行 profile,剖析 etcd 流程的瓶颈,而后优化代码流程晋升性能;
- 通过其余伎俩升高单节点 etcd 数据量。
通过代码流程优化 etcd 性能,能够依据 etcd 应用方的人力状况进行之,更长期的工作应该是紧跟社区,及时获取其版本升级带来的技术红利。通过升高 etcd 数据规模来获取 etcd 性能的晋升则必须依赖 etcd 应用方本身的能力建设了。
咱们曾对 etcd 的单节点 RT 与 QPS 性能与 KV 数据量的关系进行过 benchmark 测试,失去的论断是:当 KV 数据量减少时,其 RT 会随之线性减少,其 QPS 吞吐则会指数级降落。这一步测试后果带来的启发之一即是:通过剖析 etcd 中的数据组成、内部流量特色以及数据拜访特点,尽可能地升高单 etcd 节点的数据规模。
目前蚂蚁的 etcd 运维平台具备如下数据分析性能:
- longest N KV — 长度最长的 N 个 KV
- top N KV — 段时间内拜访次数最多的 N 个 KV
- top N namespace — KV 数目最多的 N 个 namespace
- verb + resoure — 内部拜访的动作和资源统计
- 连接数 — 每个 etcd 节点的长连贯数目
- client 起源统计 — 每个 etcd 节点的内部申请起源统计
- 冗余数据分析 — etcd 集群中近期无内部拜访的 KV 散布
依据数据分析后果,能够进行如下工作:
- 客户限流
- 负载平衡
- 集群拆分
- 冗余数据删除
- 业务流量精密剖析
1. 集群拆分
前文提到,etcd 集群性能晋升的一个经典伎俩就是把 event 数据独立拆分到一个独立的 etcd 集群,因为 event 数据是 K8s 集群一中量级比拟大、流动性很强、访问量十分高的数据,拆分之后能够升高 etcd 的数据规模并加重 etcd 单节点的内部客户端流量。
一些经验性的、常规性的 etcd 拆分伎俩有:
- pod/cm
- node/svc
- event, lease
这些数据拆分后,大概率能显著晋升 K8s 集群的 RT 与 QPS,然而更进一步的数据拆分工作还是有必要的。根据数据分析平台提供的热数据【top N KV】量级以及内部客户拜访【verb + resource】状况,进行精密剖析后能够作为 etcd 集群拆分工作的根据。
2. 客户数据分析
针对客户数据的剖析分为 longest N KV 剖析、top N namespace。
一个显然成立的事实是:单次读写访问的 KV 数据越长,则 etcd 响应工夫越长。通过获取客户写入的 longest N KV 数据后,能够与平台应用方钻研其对平台的应用办法是否正当,升高业务对 K8s 平台的拜访流量压力和 etcd 本身的存储压力。
个别地,K8s 平台每个 namespace 都是调配给一个业务独自应用。后面提到 K8s 可能因为 list-all 压力导致被压垮,这些数据拜访大部分状况下都是 namespace 级别的 list-all。从平台获取 top N namespace 后,重点监控这些数据量级比拟大的业务的 list-all 长连贯申请,在 kube-apiserver 层面对其采取限流措施,就能够基本上保障 K8s 集群不会被这些长连贯申请打垮,保障集群的高可用。
3. 冗余数据分析
etcd 中不仅有热数据,还有冷数据。这些冷数据尽管不会带来内部流量拜访压力,然而会导致 etcd 内存索引锁粒度的增大,进而导致每次 etcd 拜访 RT 时延减少和整体 QPS 的降落。
近期通过剖析某大规模【7k node 以上】K8s 集群 etcd 中的冗余数据,发现某业务数据在 etcd 中存储了大量数据,其数据量大却一周内没有拜访过一次,与业务方询问后获悉:业务方把 K8s 集群的 etcd 当做其 crd 数据的冷备应用。与业务方沟通后把数据从 etcd 中迁徙掉后,内存 key 数目立刻降落 20% 左右,大部分 etcd KV RT P99 延时立刻降落 50% ~ 60% 之多。
4. 负载平衡
K8s 平台运维人员个别都有这样一条教训:etcd 集群如果产生了启停,须要尽快对所有 K8s kube-apiserver 进行一次重启,以保障 kube-apiserver 与 etcd 之间连接数的平衡。其起因有二:
- kube-apiserver 在启动时能够通过随机形式保障其与 etcd 集群中某个节点建设连贯,但 etcd 产生启停后,kube-apiserver 与 etcd 之间的连接数并无规律,导致每个 etcd 节点承当的客户端压力不平衡;
- kube-apiserver 与 etcd 连接数平衡时,其所有读写申请有 2/3 概率是通过 follower 转发到 leader,保障整体 etcd 集群负载的平衡,如果连贯不平衡则集群性能无奈评估。
通过 etcd 运维平台提供的每个 etcd 的连贯负载压力,能够实时获取集群连贯的均衡性,进而决定运维染指的机会,保障 etcd 集群整体的衰弱度。
其实最新的 etcd v3.5 版本曾经提供了 etcd 客户端和 etcd 节点之间的主动负载平衡性能,但这个版本才公布没多久,目前最新版本的 K8s 尚未反对这个版本,能够及时跟进 K8s 社区对这个版本的反对进度以及时获取这一技术红利,加重平台运维压力。
将来之路
通过一年多的包含 kube-apiserver 和 etcd 在内的 K8s 高可用建设,目前 K8s 集群曾经稳定下来,一个显著的特色是半年内 K8s 集群没有产生过一次 P 级故障,但其高可用建设工作不可能停歇 — 作为寰球 K8s 规模化建设领导力象限的蚂蚁团体正在挑战 node 量级更大规模的 K8s 集群,这一工作将推动 etcd 集群建设能力的进一步晋升。
后面提到的很多 etcd 能力晋升工作都是围绕其 scale up 能力晋升开展的,这方面的能力还须要更深层次的增强:
- etcd 最新 feature 地及时跟进,及时把社区技术提高带来的开源价值转换为蚂蚁 K8s 平台上的客户价值
2. 及时跟进阿里团体在 etcd compact 算法优化、etcd 单节点多 multiboltdb 的架构优化以及 kube-apiserver 的服务端数据压缩等 etcd 优化工作【见参考文档 1】,对兄弟团队的工作进行借鉴和反馈,协同作战独特晋升
- 跟进蚂蚁本身 K8s 平台上 etcd 的性能瓶颈,提出咱们本人的解决方案,在晋升咱们平台的技术价值的同时反哺开源
除了关注 etcd 单节点性能的晋升,咱们下一步的工作将围绕分布式 etcd 集群这一 scale out 方向开展。后面提到的 etcd 集群拆分工作,其本质就是通过分布式 etcd 集群的形式晋升 etcd 集群整体的性能:该集群的数据划分形式是根据 K8s 业务层面的数据类型进行的。
该工作能够进一步拓展为:不辨别 KV 的业务意义,从单纯的 KV 层面对把数据依据某种路由形式把数据写入后端多 etcd 子集群,实现 etcd 集群整体的冷热负载平衡。
分布式 etcd 集群的实现有两种形式:proxyless 和 proxy based:proxy based etcd 分布式集群的申请链路是 client[kube-apiserver] -> proxy -> etcd server,而谓的 proxyless 分布式 etcd 集群的申请链路是 client[kube-apiserver] -> etcd server。
proxy based etcd 分布式集群的益处是能够间接基于 etcd 社区提供的 etcd proxy 进行开发,前期亦可回馈社区,实现其开源价值、技术价值和客户价值的对立。但通过测试:依照测试发现,kube-apiserver 通过 proxy 向 etcd 发动读写申请后 RT 和 QPS 升高 20% ~ 25%。所以下一步的工作重点是开发 proxyless etcd 集群。
目前的拆分后的 etcd 分布式集群实质或者 67% 的概率是 proxy based 分布式集群:kube-apiserver 的申请大略有三分之二的概率是通过 follower 转发到 leader,此处的 follower 实质就是一个 proxy。如果 kube-apiserver 所有申请都是与 leader 直连后被解决,实践上以后的 K8s 集群的 RT 和 QPS 就有 67% * 20% ≈ 13.4% 的性能收益。
proxyless etcd 分布式集群的毛病是如果把 proxy 的路由逻辑放入 kube-apiserver 中,会造成 kube-apiserver 版本升级成本增加,但相比于至多 20%【未来通过 etcd 集群规模裁减这个收益必定会更大】的收益,这个仅仅影响了 kube-apiserver 单个组件的版本升级的老本是值得的。
除了 multiple etcd clusters 的思路外,数据中间件团队基于 OBKV 之上实现了 etcd V3 API,算是另一种比拟好的技术路线,颇相似于本文结尾黄东旭提到的在 tikv 之上 etcd V3 API 接口层,能够称之为类 etcd 零碎,目前相干工作也在推动中。
总之,随着咱们 K8s 规模越来越大,蚂蚁团体 etcd 整体工作的重要性就日益凸显。如果说后期 etcd 的高可用建设之路是在泥泞大道上蹒跚前行,那么当前的 etcd 高可用建设之路必是坎坷不平 — 路线越走越广阔!
参看文档
参考文档 1:
https://www.kubernetes.org.cn/9284.html
参考文档 2:
https://tech.meituan.com/2020/08/13/openstack-to-kubernetes-in-meituan.html
作者简介
于雨(github @AlexStocks),dubbogo 社区负责人,一个有十一年服务端基础架构和中间件研发一线工作教训的程序员。
陆续参加和改良过 Redis/Pika/Pika-Port/etcd/Muduo/Dubbo/dubbo-go/Sentinel-go 等出名我的项目,目前在蚂蚁金服可信原生部蚂蚁大规模 K8s 集群调度团队从事容器编排工作,参加保护寰球规模最大的 Kubernetes 生产集群之一,致力于打造规模化、金融级、可信的云原生基础设施。
欢送对 Serverless 主动伸缩技术、自适应混合部署技术以及 Kata/Nanovisor 等平安容器技术感兴趣的同行或者 2022 届应届毕业生退出咱们。
分割邮箱 xiaoyun.maoxy@antgroup.com 或者 yuyu.zx@antgroup.com。
本周举荐浏览
- 咱们做出了一个分布式注册核心
- 还在为多集群治理懊恼吗?OCM 来啦!
- RFC8998+BabaSSL— 让国密驶向更远的星辰大海
- MOSN 子项目 Layotto:开启服务网格 + 利用运行时新篇章
更多文章请扫码关注“金融级分布式架构”公众号