2. etcd 核心原理回顾:Raft 协议、Leader 选举、读写路径、MVCC、事务与租约机制
在构建多集群 etcd 压测沙盘与 CAPI 指标告警体系之前,必须深入理解 etcd 的内部运行机制。etcd 作为云原生架构中的“协调中枢”,其核心原理直接决定了集群的可用性、一致性与性能瓶颈。本节将系统回顾 Raft 共识协议、Leader 选举、读写路径、MVCC、事务与租约机制,为后续的压测场景设计与告警分层奠定理论基础。
2.1 Raft 共识协议
Raft 是一种易于理解的分布式共识算法,etcd 使用它来保证集群中数据的一致性和高可用性。Raft 将共识问题分解为三个子问题:Leader 选举、日志复制和安全性。
Raft 集群中的每个节点有三种状态:
- Leader:处理所有客户端请求,管理日志复制。
- Follower:被动响应 Leader 和 Candidate 的请求。
- Candidate:用于选举新 Leader 的过渡状态。
日志复制流程如下表所示:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 客户端请求 | 写请求发送到 Leader |
| 2 | 追加日志 | Leader 将条目追加到本地日志 |
| 3 | 并行复制 | Leader 向所有 Follower 发送 AppendEntries RPC |
| 4 | 多数确认 | Follower 写入本地日志后回复确认 |
| 5 | 提交应用 | Leader 收到多数确认后提交日志,并应用到状态机 |
| 6 | 响应客户端 | Leader 将结果返回给客户端 |
2.2 Leader 选举
Leader 选举是 Raft 协议的核心机制之一,确保集群在 Leader 故障时能够快速恢复写入能力。选举过程基于随机超时时间和任期号。
选举流程如下:
- 超时触发:Follower 在选举超时内未收到 Leader 的心跳,转为 Candidate。
- 发起投票:Candidate 增加任期号,向其他节点发送 RequestVote RPC。
- 投票规则:每个节点在一个任期内只能投一票,且优先投票给日志更新的 Candidate。
- 赢得选举:Candidate 获得多数投票后成为 Leader,并立即发送心跳确立权威。
2.3 读写路径
etcd 的读写路径设计直接影响性能与一致性。写路径必须经过 Raft 日志复制,而读路径则可以通过多种方式优化。
写路径
- 序列化:Leader 将请求序列化为 Raft 日志条目。
- 复制:日志条目并行复制到 Follower。
- 持久化:节点将日志写入磁盘(WAL)。
- 提交:多数节点确认后,Leader 提交日志。
- 应用:日志应用到 MVCC 存储引擎。
读路径
etcd 提供三种读模式,适用于不同的一致性要求:
| 读模式 | 一致性 | 性能 | 适用场景 |
|---|---|---|---|
| 线性一致性读 | 强一致 | 低(需 Raft 确认) | 关键配置读取 |
| 串行化读 | 最终一致 | 高(本地读取) | 监控数据、非关键状态 |
| 允许陈旧读 | 弱一致 | 最高 | 缓存、日志 |
2.4 MVCC(多版本并发控制)
etcd 使用 MVCC 机制管理键值对的历史版本,支持事务和快照操作。每个键的每次修改都会生成一个新的版本号(revision),旧版本不会被立即删除,而是保留一段时间。
MVCC 的核心数据结构:
- treeIndex:内存中的 B-tree,维护键到最新版本的映射。
- boltDB:底层持久化存储,按版本号存储键值对。
- revision:全局递增的版本号,由主版本号和子版本号组成。
MVCC 的压缩机制(Compaction)用于清理历史版本,避免存储膨胀:
| 压缩类型 | 操作 | 影响 |
|---|---|---|
| 历史版本压缩 | 删除指定 revision 之前的所有版本 | 释放存储空间,但无法读取历史数据 |
| 碎片整理 | 重新整理 boltDB 文件,回收空闲页 | 减少磁盘占用,提升读性能 |
etcd_db_total_size_in_bytes 和 etcd_compaction_revision,确保压缩及时执行,避免磁盘空间耗尽。
2.5 事务与租约机制
事务
etcd 支持基于 if-then-else 模型的事务操作,允许在单个原子操作中执行多个条件判断和键值修改。事务的原子性由 Raft 协议保证。
事务结构示例:
// 事务:如果 key1 的值为 "v1",则更新 key2,否则删除 key3
Txn:
compare:
- target: "value"
key: "/key1"
result: "EQUAL"
value: "v1"
success:
- request_put:
key: "/key2"
value: "v2"
failure:
- request_delete_range:
key: "/key3"
事务的典型应用场景:
- 分布式锁:通过比较创建 revision 实现锁的获取与释放。
- 配置更新:确保配置的原子性更新,避免部分写入。
- 服务注册:结合租约实现服务的健康检查与自动摘除。
租约机制
租约(Lease)是 etcd 中的一种时间租约机制,用于管理键值对的生存周期。租约与键绑定,租约过期时,所有关联的键会被自动删除。
租约的核心属性:
| 属性 | 说明 | 默认值 |
|---|---|---|
| TTL | 租约的生存时间(秒) | 用户指定 |
| ID | 租约的唯一标识 | 自动生成 |
| KeepAlive | 客户端定期续约,防止租约过期 | 需要主动调用 |
2.6 核心原理总结
etcd 的核心原理构成了分布式协调服务的基础,也是压测沙盘设计的关键依据。下表总结了各机制对压测的影响:
| 机制 | 压测关注点 | 相关告警指标 |
|---|---|---|
| Raft 协议 | 日志复制延迟、多数派故障 | etcd_raft_proposal_failed_total, etcd_server_leader_changes_seen_total |
| Leader 选举 | 选举耗时、频繁切换 | etcd_server_leader_election_duration_seconds |
| 读写路径 | 读写延迟、吞吐量 | etcd_disk_wal_fsync_duration_seconds, etcd_network_client_traffic_in_bytes |
| MVCC | 版本堆积、压缩延迟 | etcd_db_total_size_in_bytes, etcd_compaction_revision |
| 事务与租约 | 事务冲突、租约风暴 | etcd_txn_total, etcd_lease_expired_total |