4. etcd 架构深度解析:Raft共识算法、集群节点角色与数据存储

etcd 是 Kubernetes 集群的“大脑”,所有集群状态、配置信息、服务发现数据都存储在 etcd 中。理解 etcd 的底层架构,是进行故障域隔离设计和灾难恢复的前提。本章将深入剖析 etcd 的核心——Raft 共识算法、节点角色分工以及数据持久化机制。

4.1 Raft 共识算法:分布式一致性的基石

etcd 使用 Raft 共识算法来保证集群中多个节点之间的数据一致性。Raft 将复杂的一致性问题分解为三个关键子问题:领导者选举(Leader Election)、日志复制(Log Replication)和安全性(Safety)。

核心原则: 只要集群中超过半数(N/2+1)的节点存活且正常通信,etcd 集群就能对外提供一致性的读写服务。这是 etcd 高可用设计的数学基础。

4.1.1 领导者选举与任期

  • Term(任期): Raft 将时间划分为任意长度的任期,每个任期以一次选举开始。任期号单调递增,作为逻辑时钟。
  • 选举触发: Follower 节点如果在“选举超时时间”内未收到 Leader 的心跳,则转换为 Candidate 状态,发起选举。
  • 投票机制: Candidate 向其他节点发送 RequestVote RPC。每个节点在一个任期内只能投一票,先到先得。获得超过半数投票的 Candidate 成为新 Leader。
  • 脑裂防护: 如果出现平票,则进入新一轮选举。Raft 通过随机化选举超时时间(150-300ms)来降低平票概率。

4.1.2 日志复制与提交

  1. 客户端请求: 所有写请求必须发送给 Leader。Leader 将请求封装为一条日志条目(Log Entry),包含任期号和索引。
  2. 并行复制: Leader 将日志条目通过 AppendEntries RPC 并行发送给所有 Follower。
  3. 日志匹配: Follower 收到日志后,检查前一条日志的任期和索引是否匹配。匹配则追加到本地日志。
  4. 提交(Commit): 当 Leader 确认日志条目已被超过半数的节点复制(持久化)后,该条目进入“已提交”状态。Leader 将提交索引推进,并通知 Follower。
  5. 应用到状态机: 已提交的日志条目最终被应用到 etcd 的持久化存储(BoltDB)中,完成数据写入。
关键指标: 日志复制延迟直接影响 etcd 的写入性能。在故障域隔离设计中,应尽量保证 Leader 与多数 Follower 之间的网络延迟在 10ms 以内,以避免频繁的选举超时和性能抖动。
Raft 日志复制流程 Raft 日志复制流程 客户端 Leader Follower 1 Follower 2 写请求 AppendEntries 日志条目(Log Entries) Term 1 Term 1 Term 2 Term 2 Term 3 commitIndex 状态机应用 → BoltDB 持久化存储 应用到状态机

4.2 etcd 集群节点角色:Leader / Follower / Candidate

etcd 集群中的每个节点在任意时刻都处于以下三种角色之一。角色转换由 Raft 算法自动驱动,无需人工干预。

角色 职责 状态特征 故障影响
Leader 处理所有客户端写请求;管理日志复制;发送心跳维持权威。 定期向所有 Follower 发送心跳(默认 100ms)。 Leader 宕机触发新选举,集群在选举期间不可写入。
Follower 被动复制 Leader 的日志;响应 Leader 和 Candidate 的 RPC 请求;处理客户端读请求(可配置)。 被动接收心跳;如果超时未收到心跳,转换为 Candidate。 少数 Follower 宕机不影响集群读写;多数 Follower 宕机导致 Leader 降级,集群不可用。
Candidate 发起领导者选举;向其他节点拉票。 临时状态;选举成功后转为 Leader,失败则退回 Follower。 Candidate 本身不处理业务请求,选举期间集群短暂不可用。
故障域隔离要点: 在跨可用区部署时,应避免将多数 etcd 节点部署在同一个故障域(如一个机架、一个交换机或一个可用区)。如果 Leader 和多数 Follower 同时位于同一故障域,该域故障将直接导致集群失去法定人数(Quorum),造成全局不可用。
etcd 节点角色转换状态机 etcd 节点角色转换状态机 Follower 被动复制日志 Candidate 发起选举 Leader 处理写请求 选举超时 获得多数票 发现更高任期 Leader 选举失败 / 发现合法 Leader

4.3 数据存储与快照机制

etcd 的数据存储分为两层:内存中的逻辑视图(Tree Index)和磁盘上的物理存储(BoltDB + WAL)。理解这两层的关系,对于诊断数据损坏和制定恢复策略至关重要。

4.3.1 存储架构分层

层级 组件 作用 持久化方式
内存层 Tree Index (B-tree) 维护 key 到 revision 的映射,支持高效的范围查询和 MVCC。 不持久化,重启后从 BoltDB 重建。
磁盘层 BoltDB (backend) 存储实际的 key-value 数据,以 revision 为主键组织。 持久化到 member/snap/db 文件。
预写日志 WAL (Write-Ahead Log) 记录所有 Raft 日志条目,用于故障恢复和数据一致性校验。 持久化到 member/wal/ 目录。
快照 Snapshot 压缩 WAL 日志,记录某一时刻的完整状态,加速重启和恢复。 持久化到 member/snap/ 目录。

4.3.2 快照(Snapshot)的工作原理

随着写入量的增加,WAL 日志会无限增长。etcd 通过定期创建快照来控制日志大小。快照记录了某一时刻的完整数据库状态。

  • 触发条件: 当 WAL 日志条目数量达到 --snapshot-count(默认 100,000)时,自动触发快照。
  • 创建过程: etcd 将当前 BoltDB 状态持久化为一个 .snap 文件,并记录该快照包含的最后一条日志的索引和任期。
  • 日志压缩: 快照创建完成后,该快照之前的所有 WAL 日志可以被安全删除。
  • 恢复加速: 新节点加入或节点重启时,先加载最新的快照文件,然后只回放快照之后的 WAL 日志,大大缩短恢复时间。
灾难恢复关键: 在 etcd 数据损坏或丢失时,member/snap/ 目录下的快照文件和 member/wal/ 目录下的 WAL 日志是恢复数据的唯一来源。务必对这两个目录实施定期备份(如每小时一次快照备份)。

4.3.3 数据目录结构

# etcd 数据目录典型结构(默认 /var/lib/etcd/)
/var/lib/etcd/
├── member/
│   ├── snap/
│   │   ├── 0000000000000001-0000000000000001.snap   # 快照文件
│   │   └── 0000000000000002-0000000000000002.snap
│   ├── wal/
│   │   ├── 0000000000000000-0000000000000000.wal     # WAL 日志文件
│   │   └── 0000000000000001-0000000000000001.wal
│   └── backend/
│       └── db                                        # BoltDB 数据库文件
└── etcd.conf                                         # 配置文件

4.4 本章小结

  • Raft 共识算法 通过领导者选举和日志复制,保证了 etcd 在多数节点存活时的强一致性。
  • 节点角色(Leader/Follower/Candidate)由算法自动管理,故障域隔离设计必须确保法定人数(Quorum)跨故障域分布。
  • 数据存储 采用内存索引 + BoltDB 磁盘存储 + WAL 预写日志 + 快照的四层架构,快照机制是控制日志增长和加速恢复的核心。
  • 在后续的演练章节中,我们将基于这些底层原理,设计针对 etcd 故障的隔离策略和租户恢复方案。