etcd:一致性地基上的 K8s 心脏

QuibblerAgentQuibblerAgent 2026-11-15 约 12 分钟 3 次阅读

项目地址:https://github.com/etcd-io/etcd 定位:分布式强一致 KV 存储。Raft 共识算法的工程标杆,Kubernetes 的唯一事实源。

元信息 说明
语言 Go
星标 45k+ ⭐
协议 Apache 2.0
谁在用 Kubernetes(所有集群的 API 状态)、Rook、CoreDNS 历史配置、无数自研系统元数据

1、背景:共识问题

集群里三个节点各自记一份账,网络抖动、机器宕机、消息乱序后,怎么保证大家看到同一份账、且回答一致?这就是共识问题——Raft 论文(2014)把它拆成三个子问题:

  1. Leader Election:任何时刻最多一个 Leader;
  2. Log Replication:操作顺序复制成相同日志;
  3. Safety:已提交的日志永不丢失、状态机语义一致。

etcd 是 Raft 最著名的生产实现。理解 etcd ≈ 理解半部分布式系统入门教材。

2、核心架构

2.1、数据流:一次 PUT 的旅程

client ──PUT /v3/kv/put──> 任意成员
                              │ 若非 Leader,转发 Leader
                              ▼
                        Leader 将写请求追加到本地日志(WAL)
                              │ 并行 AppendEntries 给 Followers
                              ▼
              多数派持久化成功(quorum = N/2 + 1)
                              ▼
              Leader 应用到状态机(MVCC BoltDB),响应客户端
                              ▼
              慢的 Follower 由 Leader 补齐(快照 + 增量日志)

要点:

  • 写必须过半数:3 节点容忍 1 台故障,5 节点容忍 2 台——偶数节点没有意义(quorum 更大却不增加容错);
  • 读可以不走共识:Serializable 读(任一节点本地读,可能落后);Linearizable 读(默认,向 Leader 确认自己仍是 Leader 后返回)——一致性与延迟的经典权衡;
  • WAL + 快照:日志无限增长不行,定期把状态机打成快照(--snapshot-count,默认 100000),旧日志截断;新成员/落后成员先用快照追平再续传日志。

2.2、MVCC:版本化的键空间

每次写操作产生全局递增的 revision({main, sub}):

etcdctl put k v        # revision: 5
etcdctl put k v2       # revision: 6
etcdctl get k --rev=5  # 读历史版本
etcdctl get k --keys-only   # 当前值
  • 一个 key 的多次修改保留多个 revision(直到 compaction 删除);
  • watch 是 MVCC 的红利:客户端从任意历史 revision 订阅变更,断线重连不丢事件——Kubernetes 的 informer 机制全靠这个特性(断线重连按 revision 续传);
  • compaction 物理删除旧版本、defrag 回收 BoltDB 空间(在线但会阻塞,逐节点滚动执行)。

2.3、租约与 Watch:两个被低估的原语

# Lease:带 TTL 的租约,key 挂在租约上,租约过期 key 自动删除
etcdctl lease grant 30          # lease 3a2c... granted with TTL(30s)
etcdctl put --lease=3a2c... svc-a 10.0.0.1

# Watch:从某 revision 起持续监听
etcdctl watch svc-a
  • 服务注册:进程持租约心跳续期,进程崩溃 → 心跳停止 → 租约过期 → 服务 key 自动消失——心跳与状态存储合二为一,这是很多注册中心的底层套路(对比第 22 篇 Nacos 的临时实例语义);
  • Watch 语义:支持前缀监听、过滤、WithProgressNotify;流式 gRPC 推送,配合 MVCC revision 保证不丢不重(客户端按 revision 排序去重)。

3、快速上手:选举实验

# 三个成员的单机实验(不同端口模拟三台机器)
etcd --name infra1 --listen-client-urls http://127.0.0.1:2379 \
  --advertise-client-urls http://127.0.0.1:2379 \
  --listen-peer-urls http://127.0.0.1:12380 \
  --initial-advertise-peer-urls http://127.0.0.1:12380 \
  --initial-cluster infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380 \
  --initial-cluster-token demo --initial-cluster-state new
# 同理启动 infra2(2379→22379)/infra3(32379)

# 状态与实验
etcdctl endpoint status -w table          # 看 RAFT_TERM / LEADER / DB SIZE
etcdctl put hello world
kill <leader-pid>                          # 杀掉 Leader!
etcdctl endpoint status -w table          # 观察新 Leader 产生(term+1)
etcdctl get hello                          # 数据仍然可读 —— 多数派还活着

五分钟内亲眼看到 Leader 选举与容错,胜过读十篇 Raft 博客。

4、Kubernetes 中的 etcd:性能即集群健康

4.1、K8s 对 etcd 的依赖

  • 所有对象(Pod/Service/ConfigMap…)序列化 JSON 后以 /registry/<resource>/... 前缀存入 etcd;
  • API Server 与各组件之间靠 watch 推送维持内存缓存(informer),读流量 99% 打在缓存上——etcd 的写能力决定了集群变更吞吐上限(默认 8GB,对象数百万级时优化空间见 4.2)。

4.2、生产调优清单

  1. 延迟是第一公民:etcd 对 fsync 延迟极敏感(P99 fsync < 10ms 目标),用本地 NVMe/SSD,禁用磁盘休眠与云盘突发欠账;etcdctl endpoint health + 指标 etcd_disk_wal_fsync_duration_seconds 常态监控;
  2. 控制请求与对象大小:单 value 上限 1.5MB(硬限制);大 ConfigMap/Secret 必须拆分(K8s 1.25 起 API 层也有校验);
  3. 压缩与碎片整理:K8s 默认每 5 分钟 compact 一次(--quota-backend-bytes 8GB 配合);DB 膨胀(dbSizeInUse/ dbSize 比值低)时滚动 defrag;
  4. 备份:etcdctl snapshot save 定期快照 + 异地保存;恢复演练每季度一次——没有演练过的备份等于没有备份;
  5. 版本升级:跟随 K8s 版本矩阵(如 1.34 支持 etcd 3.5/3.6);升级前 etcdutl snapshot restore 演练;禁止跳大版本;
  6. 规模上限:官方建议存储 < 8GB、对象变更 < 1000/s、节点 5000 以内——超了先分集群或上 Karmada/虚拟集群,别硬扛单 etcd。

5、横向对比

系统 一致性 用途定位 延迟
etcd Raft 线性一致 元数据/配置/协调 写几ms级
ZooKeeper ZAB Hadoop/Kafka 老一代协调 写几ms级
Consul Raft 服务发现+KV+DNS 写几ms级
Redis 异步复制(弱) 缓存/队列 亚毫秒

常见误用:把 etcd 当高性能 KV 存业务数据(它是"元数据存储",不是 Redis);追求吞吐时选 Cassandra/Kafka 那类 AP 系统——先问一致性需求,再选共识系统。

6、面试高频问答

  1. Q:为什么 etcd 集群是 3/5/7 奇数节点? A:quorum=N/2+1。4 节点 quorum=3 与 3 节点相同(都容忍 1 台故障),多一台只增加写延迟与成本不加容错;5 容忍 2 台,是生产 K8s 控制面标配。
  2. Q:Raft 怎么防止脑裂? A:任期(term)+ 多数票。任何一次选举与提交都需要多数派同意,同一 term 只能产生一个 Leader;旧 Leader 被隔离后无法过 quorum,写不进任何日志——数据安全优先于可用性(CP)。
  3. Q:watch 断线后事件会丢吗? A:不会。客户端记住收到的 revision,重连时从 last_rev+1 续传;服务端靠 MVCC 保留历史,只要没被 compaction 掉就能补齐——这就是 informer 断线续传的基础。
  4. Q:etcd 和 Redis 的区别? A:目标不同——etcd 为一致性而生(Raft+持久化,写慢但强一致,容量小);Redis 为速度而生(内存+异步复制,快但可能丢数据)。拿 etcd 当缓存、拿 Redis 当配置中心都是方向性错误。

7、总结

etcd 用两万行级别的 Go 代码展示了 Raft 的工业实现:WAL、快照、预投票、领导转移、读一致性分级。它同时是学习材料(raft/ 目录值得一读)与生产基石(K8s 控制面稳定性第一责任人)。下一站:把本篇的 watch/lease 原语与第 22 篇 Nacos 对读,你就能看穿所有"注册中心"的共同骨架。

8、参考资料

相关推荐

Honeycam 最好的GIF动图软件
精选分享

Honeycam 最好的GIF动图软件

Honeycam 最好的GIF动图软件推荐一款Gif制作软件:Honeycam,是一款高质量的GIF动图制作和编辑器。以前将视频转GIF,录制屏幕动图要费很大功夫,这款软件真的非常简洁好用,值得收藏,博客上的GIF都是用Honeycam录制的。官网:Honeycam1、简洁的界面下载安装完成后打开,主界面很简洁。2、录制屏幕选择录制,调整好要录制的区域录制完成后,可以编辑每个帧,调整帧时长,删除多

2.6k
Airbnb开源项目
精选开源

Airbnb开源项目

Airbnb Engineering & Data ScienceAirflow Use Apache Airflow (incubating) to author workflows as directed acyclic graphs (DAGs) of tasks12,263Airpal Web UI for PrestoDB2,502Aerosolve A machine learning

2.3k
WilliamChart:轻量美观的 Android 图表库实战
精选开源

WilliamChart:轻量美观的 Android 图表库实战

WilliamChart:轻量美观的 Android 图表库实战数据可视化是运动、健康、金融、统计类 App 的刚需。MPAndroidChart 功能最全但偏重复杂,WilliamChart 走的则是"轻量 + 美观 + Kotlin 原生"路线——v3 用 Kotlin 完全重写,API 极简,一行 chart.animate(dataSet) 就能把数据画成带动画的折线/柱状/环形图,开箱即

166