Skip to content

入门: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 释放空间。
  • Watchetcdctl 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 型协调器,但设计哲学不同:

维度etcdZooKeeper
共识协议Raft(易理解,2014)ZAB(Zookeeper Atomic Broadcast,2008)
语言/部署Go,单二进制,轻量Java(JVM),重型
数据模型扁平 KV + prefix树形 znode(路径树)
Watch流式,持续(基于 revision)一次性(触发后要重新注册,3.6 后有持续 Watch)
跨 DC需集群联邦观察者节点(手动配置)
主要用户K8s、CoreDNS、RookHadoop、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 的详细对比。