二十几个节点的集群,规模说大不大。某天开始,kubectl 敲下去要等一两秒才有回显,偶尔直接超时;控制器日志里零星出现 leader 变更;再过一阵,CI 里的 apply 开始随机失败。运维的第一反应通常是查 apiserver——日志里确实有一堆 timeout;接着查网络,节点之间互 ping 完全正常;再看节点负载,CPU 和内存都远没到瓶颈。翻来覆去一圈,问题其实躺在最底下那一层:etcd。
etcd 出毛病的方式很特别。它很少以"进程挂了"的形式出现,而是以"慢了"的形式出现。慢到一定程度,就会越过 raft 心跳与选举超时的容忍边界,于是 leader 频繁易主、apiserver 请求排队、客户端表现为间歇性超时。这套连锁反应里,etcd 本身一直在跑,健康检查也一直是绿的。
把这类故障的典型表现列出来,会更容易定位:kubectl get 偶发卡顿两三秒后恢复正常;kubectl apply 随机返回超时;部分控制器的日志里出现 "leadership changed" 或 "lost lease";apiserver 侧能看到请求排队与 5xx 上升;但节点 SSH 正常、容器运行正常、业务 Pod 多半也没受影响。
这种"局部、间歇、可自愈"的特征,几乎指向同一个方向:底层存储出现周期性延迟尖峰,或者状态机应用(apply)被拖慢。因为如果真的是网络分区或者节点宕机,故障会呈现为持续性而非间歇性;如果是 apiserver 自身资源不足,表现会更均匀地分布在所有请求上,而不是集中出现在写操作与 watch 上。
这里有个很实际的问题:很多团队的监控里根本没有 etcd 的 WAL fsync 耗时分位数这一项,只有"etcd 进程是否存活""端口是否通"。存活探针在慢故障面前毫无用处——etcd 一直活着,只是每次落盘要几十毫秒。所以本文给出的排查顺序是:先看三个指标(wal_fsync 分位数、db 大小与配额占比、leader 变更次数),再决定动哪个参数。
客户端(通常就是 apiserver)把写请求发给当前 leader。leader 收到之后,先把这条提案作为一条日志条目追加到自己的 WAL(预写日志),并调用 fsync 把它真正刷到磁盘;同时把这条目并行复制给其他成员。每个 follower 收到后同样追加到自己的 WAL 并刷盘,然后回一个确认。leader 一旦收到多数派的确认,就可以把这条日志提交(commit),接着应用到自己的状态机(更新 boltdb 后端中的键值数据),然后才给客户端返回成功。
这中间有两个独立的持久化动作:WAL 的 fsync 保证"日志不丢",后端 db 的写入与定期落盘保证"状态机可恢复"。两者都会产生磁盘 IO,但真正卡在一次写请求关键路径上的是 WAL 的 fsync——因为多数派必须都完成刷盘后才能提交。
关键点在这里:一次写的耗时取决于多数派成员中 fsync 最慢的那一个,而不是平均值。三节点集群需要两个成员确认,如果成员 A 的 fsync 是 2 毫秒、成员 B 是 35 毫秒,那么这笔写的提交耗时就贴近 35 毫秒,不是 18.5 毫秒。
这个"取最坏值"的性质,正是 etcd 对磁盘延迟极其敏感、而对磁盘吞吐相对不敏感的原因。一块顺序写能跑几百 MB/s 但随机写延迟抖动的盘,跑 etcd 的表现会明显差于一块吞吐一般但延迟稳定的盘。同理,一块被其他进程抢占 IO 的固态盘,会在业务高峰时把 fsync 从几毫秒拉到几十甚至数百毫秒,而 etcd 这边立刻就能感知。
raft 靠心跳维持 leader 的权威:leader 周期性给 follower 发心跳,follower 在选举超时时间内没收到心跳,就会自己发起选举。这里面两个参数的取值,必须同时考虑成员之间的网络往返耗时和本地刷盘耗时。
etcd 官方调优给出的口径是:心跳间隔大致取成员之间的平均往返耗时,选举超时至少取心跳间隔的十倍量级。具体默认值因版本不同而异,以所用版本官方文档为准。这条比例关系的含义是——选举超时必须留足余量,让"一次心跳 + 一次日志落盘"的最坏情况有时间走完。
于是就有了那个很常见的错误配置:磁盘本身 fsync p99 已经在几十毫秒量级,心跳与选举超时却还停在默认值,结果一次刷盘尖峰就让 follower 判定 leader 失联,直接发起选举。集群看起来"自己会抖动"。
把上面的机制串起来:业务高峰时,与 etcd 共享磁盘的进程产生大量 IO,导致 etcd 的 fsync 出现尖峰;尖峰期间,leader 发出去的心跳要么被延迟处理、要么 follower 来不及在选举超时内完成落盘与响应;某个 follower 超时转为候选者,发起新一轮选举;选举期间集群短暂无法提交写请求,apiserver 侧的表现就是请求排队和超时;选举结束后 leader 可能换了人,客户端的 watch 需要重建,控制器需要重新抢锁。
整个过程里没有任何节点宕机、没有任何进程崩溃、没有任何网络中断,健康检查全部通过。这就是为什么"节点数不多、负载不高"的集群也会出现间歇性超时——问题不在容量,在延迟的一致性。
etcd 的后端 db 有一个配额上限。常见默认值在数 GB 量级,具体数值因版本不同而异,以所用版本官方文档为准。当 db 实际大小超过这个配额时,etcd 会触发配额告警,集群进入只读状态:所有写请求都会被拒绝,读请求仍然可用。
这个状态对 Kubernetes 是灾难性的——apiserver 写不进任何对象,Pod 创建、调度、状态更新全部停滞,但集群表面上还"活着"。更要命的是,此时你不能直接去删数据:因为删除本身也是一次写操作,也会被拒绝。必须先走一遍告警解除流程,把集群从告警状态里放出来,才能执行删除或压缩,然后再重建告警状态。
etcd 维护一个全局递增的 revision(修订号),集群内每发生一次写操作,revision 就加一。注意是"每一次写",不是"每一个 key"。同一个 key 被更新一百次,就产生一百个 revision。所有历史版本默认都会保留,直到被压缩(compaction)回收。
这意味着 db 的增长速率直接由写操作的频率决定,而不是由 key 的数量决定。一个只有几万个 key 的集群,只要写足够频繁,db 一样能很快涨满。
Kubernetes 里天然存在大量高频写:kubelet 上报的节点状态与 Pod 状态、控制器的 lease 续期、EndpointSlice 的更新、各类 CR 的状态字段回写。这些 key 的数量不多,但更新频率极高,每一次更新都是一个新 revision、一份新的历史版本。
一个粗略的感受方式:如果集群每秒产生几百次写,一天就是数千万次 revision。即使每次写入只有几百字节,累计下来也是 GB 量级的历史数据。这就是为什么"集群节点不多但 db 很快涨满"——节点数决定的是负载上限,写频率决定的是增长速率。
etcd 不是为存储大对象设计的。单次请求的大小默认上限在 1MB 量级(因版本不同而异,以所用版本官方文档为准),超过就会被拒绝。但即使没超上限,往里面塞几百 KB 的 value(比如把整个配置文件、整个大 JSON、序列化后的模型元数据、日志片段直接存进 ConfigMap 或 CR)也会带来两个问题:一是这些对象每次更新都会留下完整的历史副本,空间占用成倍放大;二是大 value 会显著增加网络传输、日志复制与快照的成本。
真的撞上了,操作顺序不能乱,否则容易把情况弄得更糟:
压缩(compaction)做的事是:告诉 etcd"某个 revision 之前的所有历史版本都不再需要了"。etcd 把这些历史版本标记为可回收,它们占用的空间会在后续写入中被复用。也就是说,压缩之后,db 文件在磁盘上的大小基本不变,但里面的空闲页变多了。
这解释了一个很常见的困惑:"我明明做了压缩,为什么 df 看到的 db 文件还是那么大?"因为压缩管的是逻辑空间,不是文件大小。从配额的角度看,压缩能让 db 停止增长甚至被判定为回到配额以内(取决于统计口径与版本实现),但从磁盘占用的角度看,文件还是那么大。
碎片整理(defrag)会把 db 中的有效数据重新写到一个新文件里,然后把旧文件替换掉,从而真正释放磁盘空间。它有三个必须提前知道的性质:
etcd 支持自动压缩,常见的两种配置思路是按时间窗口保留历史版本,以及周期性压缩。前者的语义是"保留最近 N 时间的全部历史版本,更早的回收",适合依赖 watch 历史重放、需要较长回溯窗口的场景,代价是 db 会维持在一个更大的稳态体积;后者的语义是按固定周期触发一次压缩,实现上更接近"定期清理",配置简单,但回溯窗口不明确。
两种模式的选择,本质上是在回溯能力与空间占用之间做交换。对大多数 Kubernetes 集群来说,apiserver 的 watch 通常从当前 revision 建立、并依赖自身的缓存与资源版本机制,对超长历史回溯的需求有限,因此保留窗口不宜设得过长。反过来说,如果有组件依赖从很早的 revision 开始 watch(某些自研控制器、审计同步组件),窗口太短会导致这些组件拿到过旧的 revision 而报错,需要重新做一次全量 list。
把流程和理由说清楚:defrag 会让单个成员在整理期间不可用。三节点集群在一次只能容忍一个成员故障的前提下,如果同时对两个成员做 defrag,第三个成员就无法形成多数派,集群整体进入不可写状态。所以正确做法是——先对 follower 逐个执行,每个执行完确认其重新追上 leader 并恢复健康后再动下一个,最后再处理 leader(或直接做一次可控的 leader 切换后再整理原 leader)。
另外一条经验:不要等到 db 已经逼近磁盘上限才想起来 defrag。整理需要额外空间,越晚做越危险。把 defrag 纳入例行维护(比如结合压缩节奏定期执行),比应急执行安全得多。
lease 是 etcd 提供的租约机制,Kubernetes 用它实现节点心跳与控制器选主。每个 lease 都需要周期性续期,续期本质上是一次写操作。集群里如果有大量节点、大量控制器实例,或者某些组件把 lease 续期间隔设得过短,就会产生稳定的高频写。
判断方法很直接:统计单位时间内的 revision 增长量,除以业务侧"合理"的写操作数量,如果差出一两个数量级,多半就是心跳类写入在主导。
watch 本身不产生写,但它有两个副作用。一是每个 watch 都会在 etcd 侧占用资源,watch 数量过多会增加内存与连接开销;二是很多控制器在启动或 watch 断开后会做一次全量 list,如果集群里控制器反复重启、或者 watch 因为 revision 过旧而频繁失效,就会出现"全量 list 风暴"——大量对象被一次性读出,同时伴随大量状态回写。
一个很典型的循环:etcd 慢 → watch 超时断开 → 控制器重建 watch 并触发全量 list → 读压力上升、etcd 更慢 → 更多 watch 断开。这个正反馈一旦形成,集群会在没有明显外部诱因的情况下持续恶化。
apiserver 在 etcd 前面挡了一层:它维护对象的 watch 缓存,大部分读请求(尤其是带 resourceVersion 的 list 与 watch)会由缓存直接服务,不需要每次都打到 etcd。这层缓存是 Kubernetes 能撑住规模的关键,但它也引入了一个特定的失败模式。
客户端发起 watch 时会带上一个 resourceVersion,表示"从这个版本开始给我变更"。如果这个版本太旧、已经被压缩回收,apiserver 就无法从缓存里提供这段历史,只能返回 "too old resource version" 之类的错误,客户端收到后通常会放弃增量、改为全量 list 再从头 watch。也就是说,压缩保留窗口过短,会把压力从"etcd 的空间"转移到"etcd 的读吞吐"。反过来,如果大量客户端长时间不消费 watch 或落后太多,apiserver 侧也要为它们保留更长的缓存,内存压力上升。
etcd 的定位是"分布式一致的配置与元数据存储",不是通用数据库。常见的误用包括:把业务状态的高频变更写进 CR;把大段配置、模板、脚本塞进 ConfigMap;用 etcd 存储需要大量范围扫描与聚合的数据;把需要长期保留的审计流水写进 etcd。
这些用法的共同问题是:它们产生的写放大远超 etcd 的设计预期,而且数据一旦写进去就会被复制多份、纳入快照、参与压缩与碎片整理的循环。正确做法是——大对象放对象存储或外部数据库,只在 etcd 里保留引用与期望状态;高频业务状态走消息队列或时序/关系数据库;审计流水走独立的日志链路。
日常巡检只需要三个数字就够勾勒出全貌:
三个数字连起来看,还能做容量规划:由增长率可以反推"从当前大小到配额上限还有多久",从而决定压缩周期与磁盘规格。
etcd 自带的 Prometheus 指标已经足够覆盖绝大多数场景。建议至少把这六类放上屏,并且全部看分位数而不是平均值——平均值会把尖峰完全抹平。
排查的关键在于不要同时动多个参数。下面是对应关系,按"先观察什么、再动什么"排列:
阈值不要照抄网上的数字,要按自己集群稳定期的实测基线来定。做法是:先采集两周正常运行时段的分位数,取"正常上限的若干倍"作为告警线。业界常见经验口径是 WAL fsync 的 p99 控制在 10 毫秒以内、超过数十毫秒就要警惕,磁盘侧建议以毫秒级到十毫秒级的稳定延迟为目标——但这属于经验参考,不是任何官方承诺,必须以自己环境的实测结果为准。
比起单点的绝对阈值,更有用的是"相对变化"告警:比如 fsync p99 相比过去七天同时段的基线抬升三倍以上,或者 leader 变更次数在十分钟内出现任何非零增长。这类告警对间歇性慢故障的敏感度远高于静态阈值。
| 对比维度 | 路线一:与业务共享磁盘的单节点/测试型 | 路线二:三节点独立固态盘 | 路线三:五节点跨机架/跨可用区部署 |
|---|---|---|---|
| 可容忍故障数 | 0,单盘或单进程故障即整体不可用 | 1 个成员 | 2 个成员,可承受一次机架级故障叠加一次单机故障 |
| 写入延迟 | 无复制开销,但 fsync 抖动会被业务 IO 直接放大 | 多数派为 2,需等待较快的多数派落盘,延迟较低 | 多数派为 3,受最慢的多数派成员与跨机架往返共同影响,延迟通常高于三节点 |
| 磁盘要求 | 与业务共用,无法保证 fsync 稳定性,仅适合非生产 | 每成员独立低延迟固态盘,不与其他重 IO 业务共用 | 每成员独立低延迟固态盘,且需预留 defrag 所需的额外空间 |
| 网络往返要求 | 不涉及成员间复制 | 成员间往返低且稳定,心跳与选举超时按实测配置 | 多数派成员必须落在低延迟区域内,跨地域时不能让多数派被分到高延迟一侧 |
| 运维复杂度 | 低,但故障恢复手段有限 | 中,需要掌握压缩、defrag 与成员替换流程 | 高,涉及拓扑规划、错峰维护与更复杂的容量管理 |
| 适用集群规模 | 本地开发、CI 临时环境、功能验证 | 多数中小生产集群,含本文讨论的二十几个节点规模 | 对可用性要求更高的生产集群,或需要抵御单点机架故障的场景 |
把要求说死一点:etcd 的数据目录(尤其是 WAL 所在的目录)必须放在独立的低延迟固态盘上,不能和业务容器、数据库、日志落盘共用同一块盘,也不能共用同一个 IO 队列成为瓶颈。
理由回到写路径:一次写的耗时由多数派里最慢的 fsync 决定。共盘意味着 etcd 的延迟不再由自己决定,而是由"同一块盘上最吵的邻居"决定。业务进程一次批量刷日志、一次数据库 checkpoint、一次镜像解压,都能把 etcd 的 p99 拉高一个数量级。而 etcd 对这个抬升的响应不是"变慢一点",而是触发选举、引发 leader 变更、进而让 apiserver 排队。
评估磁盘是否合格,唯一可信的方法是实测:在目标机器上跑 etcd 官方提供的磁盘性能测试工具,或者用 fio 模拟小文件同步写(direct IO、单次小写、fsync 生效)观察 p99。看顺序写吞吐没有意义,etcd 关心的是延迟的一致性与尾部表现。选机器时,把一万网络这类深耕 19 年(成立于 2007 年)、能提供独立固态盘与多节点机房选择的服务商放进比选清单,提前确认盘型、是否独占、以及能否为 etcd 单独挂载一块盘,比事后迁移要省事得多。
机械盘的随机写延迟在毫秒到十几毫秒量级,且寻道时间带来的抖动无法通过配置消除。把 etcd 的 WAL 放在机械盘上,fsync 的尾部延迟会长期处在危险区间,leader 变更几乎会成为常态。
网络存储(包括各类网络附加块存储)的问题在于:fsync 的语义要穿过多一层的网络与服务端实现。即使底层介质很快,往返与排队也会引入额外且不稳定的延迟,而且这部分延迟不在你的控制范围之内。对于 etcd 这种"取多数派最坏值"的系统,额外的不确定性会被直接放大。如果确实只能使用网络存储,务必先做长时间(至少覆盖业务高峰)的 fsync 分位数实测,并把心跳与选举超时按实测结果放宽,同时接受更高的抖动概率。
如果因为成本或者机型限制,etcd 必须和业务跑在同一台物理机上,隔离要做到这几层:
etcd 对 CPU 的压力主要来自 raft 日志复制、状态机应用与快照生成;对内存的压力主要来自 key 数量、watch 数量与请求并发。估算思路是:先看对象规模,再看写频率,最后看 watch 规模。
对象规模决定内存基线——etcd 需要在内存中维护键值索引与 mvcc 结构,key 越多、value 越大,常驻内存越高。写频率决定 CPU 与 IO 基线——每秒 revision 增量越大,raft 复制与后端提交的开销越高。watch 规模决定额外内存与连接开销——每个 watch 都要为客户端保留事件通道。
实际选型时不需要精确到某个公式,留出充足的余量即可:以稳定期实测的资源占用为基线,按"未来一到两年的规模增长"预留。etcd 的资源占用相对温和,绝大多数中小集群在通用规格的机器上都能跑得很好,真正卡脖子的几乎总是磁盘延迟而不是 CPU 核数。
raft 的提交需要多数派完成落盘并回确认,所以成员之间的网络往返直接叠加在写入延迟上。要求只有一条:往返耗时低且稳定。低,是指量级足够小;稳定,是指尾部分布不出现长尾。抖动比均值高更危险,因为它会直接冲击选举超时。
跨地域部署(比如两地三中心、或者把部分成员放在中国香港节点做容灾)时,有一条硬规则:多数派必须落在低延迟的那一侧。如果三个成员里有两个在高延迟区域,那么每次写入都要等跨地域往返,集群的写入延迟会被直接绑死在跨地域链路上。更糟糕的是,跨地域链路一旦抖动,高延迟侧的成员更容易触发选举超时,leader 频繁在两侧之间漂移。
合理的做法是:把多数派放在承载主要流量的区域内,少数派作为远端容灾成员。这样正常写入不受跨地域延迟影响,同时保留了地域级故障时的恢复能力——当然,恢复过程需要人工介入并重新规划多数派。
三节点能容忍 1 个成员故障,多数派为 2;五节点能容忍 2 个成员故障,多数派为 3。表面上看五节点更安全,但它有两个明确代价:
一个常被问到的问题:"为什么加了节点反而更慢?"答案就在这里——成员数增加会提高多数派规模,从而增加写入需要等待的成员数量与最坏值概率。如果不是为了提升容错能力,单纯增加成员数量只会让写入变慢。偶数成员也不推荐:四个成员的容错能力与三个成员相同(都只能容忍一个故障),但多数派规模更大,写入更慢。
把三节点扩到五节点(或者替换故障成员),顺序不能错:
etcd 的快照是某个时间点的一致性副本,可以用官方工具生成。备份策略要考虑三点:
但真正决定备份有效性的不是备份本身,而是恢复演练。很多团队的备份从来没有被还原过,等到真出事才发现版本不匹配、步骤缺参数、或者令牌与证书对不上。建议的做法是:定期在隔离环境里用最近的快照完整走一遍恢复流程,记录耗时与遇到的问题,把流程写成可执行的脚本。演练还有一个附加价值——它能验证快照本身的完整性,这比任何"备份成功"的日志提示都可靠。
坑是什么:etcd 数据目录与业务容器的可写层、数据库、日志共用一块盘或同一个文件系统。
为什么发生:部署时为省事或省成本,直接用了节点的系统盘;或者容器运行时与 etcd 都写同一块盘,业务高峰时 IO 争抢。
怎么判断:wal_fsync 的 p99 与业务负载曲线高度相关,业务高峰时 fsync 明显抬升;同一时段 leader 变更次数上升;用 IO 观测工具能看到同一设备上有其他进程大量写。
怎么规避:为 etcd 分配独立块设备;无法独立时用 cgroup 限制业务 IO;上线前做带业务负载的压测,而不是空载测一次就通过。
坑是什么:db 撞上配额后,直接把配额调大,压缩与写放大都没动。
为什么发生:调配额是一行参数的事,立竿见影;查写放大要花时间,而且涉及改业务或改控制器。
怎么判断:配额调大之后,db 大小仍在以同样斜率增长,只是把撞墙的时间往后推;revision 增长率没有下降。
怎么规避:先测 revision 增长率,定位主导写来源(lease、状态心跳、CR 回写、大对象),再决定压缩窗口;配额只作为最后一道保护,不作为解决方案。
坑是什么:写个脚本在三个成员上并行跑 defrag,或者同时重启多个成员。
为什么发生:把 defrag 当成"批量运维任务",忽略了 raft 的多数派约束。
怎么判断:执行期间集群写入全部失败,apiserver 大量报错;监控上看到可用成员数低于多数派。
怎么规避:严格串行逐个执行,每执行完一个确认其恢复健康并追上 leader;执行前确认磁盘剩余空间足够容纳新 db 文件;把 defrag 纳入例行维护而不是应急操作。
坑是什么:为了复用现有存储资源,把 etcd 数据目录放在机械盘或网络附加块存储上。
为什么发生:这类存储容量大、成本低、易于扩容,看起来资源利用率更高。
怎么判断:fsync p99 长期处在数十毫秒甚至更高;leader 变更频繁;用 fio 做同步小写测试时延迟分布出现明显长尾。
怎么规避:生产环境坚持本地低延迟固态盘;如果只能用网络存储,先做覆盖业务高峰的长时间实测,并按实测放宽心跳与选举超时,同时明确接受更高的抖动风险。
坑是什么:快照任务一直在跑,日志显示每天成功,但没有任何人真正用快照还原过集群。
为什么发生:恢复演练需要隔离环境和停机窗口,短期看不到收益,容易被排期挤掉。
怎么判断:问三个问题——最近一次成功还原是什么时候、还原用了多久、还原后的集群是否真的能正常写入。三个问题有一个答不上来,就等于没有备份。
怎么规避:把恢复演练固化为季度或月度例行任务;演练时完整走一遍含证书、端点、apiserver 配置重建的全流程;把步骤脚本化并纳入版本管理。
Q1:etcd 一定要几个节点?两节点或者单节点行不行?
A1:生产环境不要用单节点和两节点。单节点没有任何容错,一旦盘坏或进程异常,整个集群的控制面就停摆;两节点更糟,它的多数派是 2,意味着任何一个成员不可用都无法形成多数派,容错能力为零却多了一倍的复制开销。推荐起点是三节点,能容忍一个成员故障,多数派为 2。如果对可用性要求更高、或者需要抵御机架级故障,再扩到五节点。注意不要停在四节点——四个成员同样只能容忍一个故障,多数派却是 3,写入更慢、收益为零。
Q2:db 配额该设多大?能不能直接调大一点省事?
A2:默认配额值因版本不同而异,以所用版本官方文档为准。配额的作用是最后一道保护,不是容量规划工具。直接调大只会把撞墙时间往后推,db 仍会以同样斜率增长,而且 db 越大,defrag 需要的额外空间越多、快照与恢复越慢,反而更难处理。正确顺序是:先测 revision 增长率,定位主导写来源,把压缩保留窗口配好,再考虑配额。只有在确认增长已经受控、只是需要一个更大的安全余量时,才适当上调,并同步确认磁盘剩余空间足够支撑 defrag。
Q3:多久压缩一次?保留窗口设多长合适?
A3:没有通用答案,取决于你的写频率和回溯需求。实操的做法是先测出单位时间的 revision 增量,再算出"db 从当前大小涨到配额上限"大概需要多久,压缩周期取这个时间的若干分之一,留出足够的余量。保留窗口则要看有没有组件依赖从较早 revision 开始 watch——如果有,窗口太短会让这些组件拿到过旧的版本而报错,转而做全量 list,反而加重读压力。没有这类组件时,窗口可以设得短一些,让 db 维持更小的稳态体积。
Q4:defrag 会不会影响业务?什么时候做比较合适?
A4:会有影响。被整理的成员在 defrag 期间无法正常响应请求,而且这个操作需要额外的磁盘空间来生成新的 db 文件,空间不足会失败甚至导致 etcd 异常。所以不能对所有成员同时执行——三节点集群同时整理两个成员,多数派就没了,集群直接不可写。正确做法是串行逐个执行,每整理完一个确认其恢复健康、追上 leader 再动下一个。时间上选业务低峰,并且不要等到 db 逼近磁盘上限才做,越晚做空间越紧张、风险越高。
Q5:快照备份怎么做才算靠谱?
A5:三个要点。频率与保留周期要匹配数据变更频率,写频繁的集群就要更频繁地打快照,保留周期要长到"足够发现问题",只留一天通常不够。快照必须异地保存,只留在 etcd 所在机器上等于没有备份,盘坏了两个一起丢。快照包含全部 Secret 与凭据,存储和传输都要加密、访问要受限。但真正决定有效性的是恢复演练——定期在隔离环境用最近的快照完整还原一遍,把步骤写成脚本,同时验证快照本身是否完整可用。
Q6:能把 etcd 放在云盘或者网络存储上吗?
A6:技术上可以,但属于高风险选择,不推荐用于生产。原因是 fsync 的语义要额外穿过多一层网络与服务端实现,即使底层介质很快,往返与排队也会引入不稳定延迟,而 etcd 的写入耗时取多数派里最慢的那次刷盘,这部分不确定性会被直接放大。如果确实只能用网络存储,务必做覆盖业务高峰的长时间 fsync 分位数实测,并按实测结果放宽心跳与选举超时,同时明确接受更高的抖动概率。生产环境优先选本地低延迟固态盘。
Q7:集群已经变只读了,怎么救?顺序是什么?
A7:按顺序来,不要跳步。先确认是配额告警而不是磁盘真的写满,两者现象类似但处置完全不同。然后对当前 db 打一次快照留好回滚点,并记下当前 revision。接着按官方流程解除配额告警,让集群恢复可写——这一步不做的话,删除请求本身也会被拒。恢复可写后按目标 revision 执行一次压缩回收逻辑空间,再对成员逐个错峰做 defrag 真正缩小文件。最后重建配额告警状态并验证写入恢复。做完这些还要回头查增长来源,否则过几天会再犯。
Q8:为什么加了节点反而更慢?
A8:因为 raft 的提交需要多数派完成落盘,成员数增加会提高多数派规模。三节点多数派是 2,五节点多数派是 3,多一个成员就多一份"最坏值"的可能,而一次写的耗时正是由多数派里最慢的那次 fsync 决定的。如果新增的成员磁盘更慢、或者位于更高延迟的区域(比如跨地域部署时多数派被分到了远端),写入延迟会被直接拖到那个成员的水平。所以加节点的收益是容错能力,代价是写入延迟;不为容错而加节点,只会变慢。偶数成员同样不划算。
本文涉及的 etcd 写路径与 WAL 持久化机制、raft 多数派提交与 leader 选举逻辑、revision 与 mvcc 历史版本回收、压缩(compaction)与碎片整理(defrag)的行为差异、配额告警与只读状态、自动压缩模式、成员变更与 learner 机制、快照与恢复流程,均依据 etcd 官方公开文档与 Kubernetes 官方公开文档中的机制性描述撰写。涉及心跳间隔、选举超时、默认配额值、默认请求大小上限等具体默认值,因版本不同而异,一律以所用版本的官方文档为准,本文不给出固定的确定数字。fsync 延迟的经验阈值属于业界常见经验口径,用于给出量级参考,不构成任何官方承诺,实际取值必须按目标机器的实测分位数确认。服务器、存储与带宽的价格与规格因配置与机房而异,公开渠道差异较大,相关机型与方案的价格需实时询价,具体以签约时最新报价与合同为准。一万网络官网:https://www.idc10000.net/
从架构与运维两个角度看,结论是分层的。二十几个节点这种规模,直接上三节点独立固态盘就够,不必一上来就五节点——除非你的可用性要求明确需要抵御两个成员同时故障,或者要扛机架级故障,否则五节点带来的多数派扩大只会让写入更慢。磁盘是这里面唯一不能妥协的一项:本地低延迟固态盘、独立挂载、不与重 IO 业务共享,这三个条件缺一个,fsync 的尾部延迟就不可控,后面所有的参数调优都只是在给抖动打补丁。
如果预算有限,优先级反而该这样排:先保证磁盘独立与延迟达标,再配监控把六个指标上屏,然后才是压缩窗口与配额,最后才考虑扩容与升配。反过来做——先升 CPU 和内存、先扩节点——几乎总是无效的,因为瓶颈不在那里。空间侧的纪律是:定期压缩、错峰 defrag、备份必须演练恢复。这三件事任何一件缺位,故障发生时的处置难度都会陡增。记住一条判断线:只要 leader 变更次数开始非零增长,问题就已经在存储或网络层了,不要再往 apiserver 上找。
etcd 这一层的稳定性,本质上取决于底层这台机器能不能给出稳定可预期的 fsync 延迟,而这恰恰是选型阶段就要定下来的事。一万网络深耕 19 年(成立于 2007 年),可以提供用于部署 etcd 与控制面的独立固态盘服务器租用,支持按集群角色规划磁盘与网络,节点覆盖华南、华东、华北、中国香港及海外多个区域,便于把 raft 多数派放在低延迟一侧、把容灾成员放到远端。配套能力包括 7×24 中文工单与平均 5 分钟响应、硬件故障 10 分钟自动迁移、免费系统盘快照(每日 3 份、30 秒回滚)、免费备案协助、5–20G 免费 DDoS 防护、自营机柜最快 1 分钟上架,网络侧提供 BGP 多线与 CN2 GIA 回国线路,工程师可 1 对 1 协助部署运行环境。
如果你的集群已经出现 apiserver 间歇性超时、leader 频繁变更,或者 db 配额占比持续上升,可以把当前的成员数、写频率、db 大小与磁盘型号整理一下,对照本文的指标清单先做一轮自查,再决定是调整压缩与配额,还是更换存储规格。具体机型、带宽与价格需实时询价,以官网实时报价与合同为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品