项目地址:https://github.com/etcd-io/etcd 定位:分布式强一致 KV 存储。Raft 共识算法的工程标杆,Kubernetes 的唯一事实源。
| 元信息 | 说明 |
|---|---|
| 语言 | Go |
| 星标 | 45k+ ⭐ |
| 协议 | Apache 2.0 |
| 谁在用 | Kubernetes(所有集群的 API 状态)、Rook、CoreDNS 历史配置、无数自研系统元数据 |
1、背景:共识问题
集群里三个节点各自记一份账,网络抖动、机器宕机、消息乱序后,怎么保证大家看到同一份账、且回答一致?这就是共识问题——Raft 论文(2014)把它拆成三个子问题:
- Leader Election:任何时刻最多一个 Leader;
- Log Replication:操作顺序复制成相同日志;
- 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、生产调优清单
- 延迟是第一公民:etcd 对 fsync 延迟极敏感(P99 fsync < 10ms 目标),用本地 NVMe/SSD,禁用磁盘休眠与云盘突发欠账;
etcdctl endpoint health+ 指标etcd_disk_wal_fsync_duration_seconds常态监控; - 控制请求与对象大小:单 value 上限 1.5MB(硬限制);大 ConfigMap/Secret 必须拆分(K8s 1.25 起 API 层也有校验);
- 压缩与碎片整理:K8s 默认每 5 分钟 compact 一次(
--quota-backend-bytes8GB 配合);DB 膨胀(dbSizeInUse/ dbSize比值低)时滚动defrag; - 备份:
etcdctl snapshot save定期快照 + 异地保存;恢复演练每季度一次——没有演练过的备份等于没有备份; - 版本升级:跟随 K8s 版本矩阵(如 1.34 支持 etcd 3.5/3.6);升级前
etcdutl snapshot restore演练;禁止跳大版本; - 规模上限:官方建议存储 < 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、面试高频问答
- Q:为什么 etcd 集群是 3/5/7 奇数节点? A:quorum=N/2+1。4 节点 quorum=3 与 3 节点相同(都容忍 1 台故障),多一台只增加写延迟与成本不加容错;5 容忍 2 台,是生产 K8s 控制面标配。
- Q:Raft 怎么防止脑裂? A:任期(term)+ 多数票。任何一次选举与提交都需要多数派同意,同一 term 只能产生一个 Leader;旧 Leader 被隔离后无法过 quorum,写不进任何日志——数据安全优先于可用性(CP)。
- Q:watch 断线后事件会丢吗? A:不会。客户端记住收到的 revision,重连时从
last_rev+1续传;服务端靠 MVCC 保留历史,只要没被 compaction 掉就能补齐——这就是 informer 断线续传的基础。 - Q:etcd 和 Redis 的区别? A:目标不同——etcd 为一致性而生(Raft+持久化,写慢但强一致,容量小);Redis 为速度而生(内存+异步复制,快但可能丢数据)。拿 etcd 当缓存、拿 Redis 当配置中心都是方向性错误。
7、总结
etcd 用两万行级别的 Go 代码展示了 Raft 的工业实现:WAL、快照、预投票、领导转移、读一致性分级。它同时是学习材料(raft/ 目录值得一读)与生产基石(K8s 控制面稳定性第一责任人)。下一站:把本篇的 watch/lease 原语与第 22 篇 Nacos 对读,你就能看穿所有"注册中心"的共同骨架。


