入门:etcd 定义、Raft 共识与 K8s 底座
基于 etcd 3.5 · 核于 2026-08
速查
- 定义:etcd 是 CoreOS(现 CNCF)开源的分布式强一致键值存储,用 Raft 共识算法保证所有写都过半复制、读可线性一致,专为「分布式系统配置/元数据/协调」设计。一个 Go 二进制,HTTP/gRPC API。
- 核心定位:etcd 是「构建分布式协调与注册中心的底座」,不是开箱即用的注册中心。它只提供原子 KV + Watch + Lease,上层应用自己拼「服务发现/锁/选举」语义。
- K8s 唯一状态存储:Kubernetes 把所有集群状态(Pod/Service/Deployment/ConfigMap)都存进 etcd,apiserver 是唯一读写入口。etcd 挂了 = K8s 集群挂了,所以 K8s 生产部署对 etcd 的可用性与备份要求极严。
- Raft 共识:etcd 用 Raft 算法——集群有 1 个 Leader(处理所有写)、N 个 Follower;客户端写 Leader → Leader 写日志 → 复制到过半节点 → 提交 → 返回客户端。Leader 宕机则 Follower 重新选举。过半提交保证一致性,奇数节点(3/5/7)保证多数派。
- 三大核心机制:①MVCC 多版本(每次写产生新修订 revision,保留历史,支持按 revision 读旧值);②Watch(监听 key/prefix 变化,基于 revision 的流式推送,秒级实时);③Lease 租约(带 TTL 的租约,绑定 key,到期自动删除——做存活检测/领导选举/分布式锁)。
- 线性一致读(Linearizable Read):默认读请求也要走 Leader 确认当前自己是 Leader(通过 ReadIndex),保证读到最新已提交数据。可选
serializable(本地读,快但可能读到旧值,即 stale read)。 - 事务(TXN):
etcdctl txn原子执行「if key 条件 then 操作 else 操作」,基于 compare-and-swap,做乐观锁、选举。 - CP 定位:etcd 是 CP(强一致优先)——网络分区时少数派不可写,保证不丢数据。这与 Redis(AP,内存优先)、Nacos 默认 AP 不同。
- 奇数节点:3 或 5 个节点(奇数为了 Raft 多数派 = (N/2)+1,3 节点容忍 1 个故障,5 节点容忍 2 个)。
- 历史背景:etcd 2013 年由 CoreOS 创建,对标 ZooKeeper(Yahoo 2008,用 ZAB 协议),目标是更轻量、更易运维、用 Raft(比 ZAB 更易理解)。现 K8s 默认底座,CNCF 毕业项目。
- 进阶顺序:Raft 共识与一致性 → Kubernetes 与工程用法 → 参考。
一、etcd 是什么:分布式协调的底座
分布式系统里,多个节点常需要就「同一个事实」达成一致:谁是主?配置值是多少?哪个节点还活着?如果各节点自己记,会出现脑裂(split-brain)。etcd 就是一个让所有节点就 KV 数据达成强一致的服务:
客户端 A: PUT /config/leader node-1
客户端 B: GET /config/leader
│
┌───────┴───────┐
│ etcd 集群 │ ← Raft 保证所有节点看到同样的值
│ Leader Follower│ 写要过半确认,读线性一致
│ Follower │
└───────────────┘- KV 模型:数据是扁平的 key-value(如
/services/order/instance-1→{ip:10.0.0.5}),不像关系库有表结构。 - 强一致:所有写都过半节点复制后才算成功,读默认线性一致(读到最新已提交值)。
- 底座定位:etcd 自己不做「服务发现」,但它提供 KV + Watch + Lease,让上层能拼出服务发现(CoreDNS、Registrator)、分布式锁、领导选举。K8s 就是把整个集群状态建模成 etcd KV。
一句话:etcd 是 CP 型的分布式 KV 协调底座,Raft 保证强一致,是 K8s 的「数据库」。
二、Raft 共识:Leader + 过半提交
etcd 用 Raft 算法保证一致性。Raft 的核心是「Leader 说了算 + 过半提交」:
客户端:PUT /x = 1
│
▼
┌─── Leader ──────┐ 日志 term=5, index=10: PUT /x=1
│ (node-1) │
└──┬─────────┬────┘
│ 复制 │ 复制
▼ ▼
Follower Follower
(node-2) (node-3)
│ │
└────┬────┘
▼
过半(2/3)确认 → Leader 提交 → 返回客户端「成功」- Leader 唯一:任一时刻只有 1 个 Leader,所有写都先到 Leader。Leader 把写追加到自己的日志(带 term 任期号 + index 日志序号),然后并行复制给所有 Follower。
- 过半提交:Leader 收到过半节点(含自己,N/2+1)的 ack 后,把这条日志标记为「已提交(committed)」,返回客户端成功。提交的日志不可撤销。
- Follower 跟随:Follower 接收 Leader 的日志复制,按相同顺序追加。Leader 持续发心跳维持 Leader 地位。
- Leader 选举:Leader 宕机 → Follower 超时没收到心跳 → 转为 Candidate → 请求其他节点投票 → 拿过半票成为新 Leader。
- 奇数节点:3 节点容忍 1 个故障(多数派 2);5 节点容忍 2 个(多数派 3)。偶数节点没意义(4 节点也只能容忍 1 个故障,多数派仍是 3,反而增加运维成本)。
三、K8s 底座:所有状态的真相源
K8s 把整个集群状态都存在 etcd 里,这是 etcd 最重的身份:
kubectl create -f deployment.yaml
│
▼
apiserver(唯一读写入口)──→ etcd
│ /registry/deployments/default/nginx
│ /registry/pods/default/nginx-xxx
│ /registry/services/default/nginx-svc
│
controller-manager / scheduler Watch etcd
kubelet Watch etcd → 在 node 上拉起 Pod- apiserver 是唯一入口:所有组件(kubectl、controller、kubelet)都通过 apiserver 读写 etcd,不直连 etcd。
- 资源 = KV:每个 K8s 资源(Deployment/Pod/Service)在 etcd 里是一条 KV,key 是层级化路径(
/registry/pods/<ns>/<name>)。 - Watch 驱动控制循环:controller-manager、scheduler、kubelet 都 Watch etcd 里关心的 key 前缀,etcd 一变就推送,组件据此做出反应(如 scheduler 看到新 Pod → 分配节点)。这是 K8s 声明式(看实际状态趋近期望状态)的根基。
- 可用性 = K8s 可用性:etcd 挂了,apiserver 无法读写,整个 K8s 集群瘫痪(已有 Pod 继续跑,但不能创建/删除/调度)。所以生产 K8s 必须部署 etcd 集群(3/5 节点)+ 定期备份(snapshot)。
四、MVCC + Watch + Lease:三大核心机制
| 机制 | 作用 | 典型用法 |
|---|---|---|
| MVCC 多版本 | 每次写产生新 revision(全局递增),保留历史版本 | 读旧版本、审计、Watch 增量 |
| Watch | 监听 key/prefix 变化,基于 revision 流式推送 | K8s 控制循环、配置热更新 |
| Lease 租约 | 带 TTL 的租约,绑定 key,到期自动删 | 存活检测、领导选举、分布式锁 |
- MVCC revision:etcd 给每次写分配一个全局递增的 revision(如 revision=100)。读时可指定 revision,读到那个历史版本。compact 操作可清理旧 revision 释放空间。
- Watch:
etcdctl watch /config/监听该前缀所有 key 变化。Watch 基于revision——客户端记录上次收到的 revision,断线重连从该 revision 续看,不丢事件。K8s 的 controller 全靠这个。 - Lease:创建租约(
etcdctl lease grant 30,TTL 30s),把 key 绑定到租约(etcdctl put /leader node-1 --lease=xxx)。持有者周期性lease keep-alive续约;持有者宕机不续约 → 30s 后租约过期 → 绑定的 key 自动删除 → 其他节点能重新抢占。这是领导选举与存活检测的基础。
五、与 ZooKeeper 的历史对比
etcd(2013)对标 ZooKeeper(2008),两者都是 CP 型协调器,但设计哲学不同:
| 维度 | etcd | ZooKeeper |
|---|---|---|
| 共识协议 | Raft(易理解,2014) | ZAB(Zookeeper Atomic Broadcast,2008) |
| 语言/部署 | Go,单二进制,轻量 | Java(JVM),重型 |
| 数据模型 | 扁平 KV + prefix | 树形 znode(路径树) |
| Watch | 流式,持续(基于 revision) | 一次性(触发后要重新注册,3.6 后有持续 Watch) |
| 跨 DC | 需集群联邦 | 观察者节点(手动配置) |
| 主要用户 | K8s、CoreDNS、Rook | Hadoop、Kafka(旧版)、HBase |
| 现状 | CNCF 毕业,活跃 | 渐被 etcd 替代,新项目少用 |
- Raft vs ZAB:两者都是 Leader-based 的过半提交协议,本质相似。Raft 的优势是论文写得极清晰("In Search of an Understandable Consensus Algorithm"),易教学、易实现、易调试,催生了 etcd、Consul、TiKV 等多个实现。ZAB 更早但论文不透明,实现门槛高。
- etcd 渐替代 ZK:K8s 选 etcd 后,新分布式项目(TiKV、CockroachDB 的协调、Rook)多选 etcd/Raft,ZK 主要留在 Hadoop/Kafka 生态。
下一步
理解了 etcd 的定位与三大机制后,下一步深入Raft 共识与一致性——Leader 选举全过程、日志复制、过半提交、脑裂防护、线性一致读,以及Kubernetes 与工程用法——K8s 状态存储、Watch 实战、与 ZooKeeper 的详细对比。