2. etcd 核心架构回顾:Raft 协议原理、集群角色与存储引擎
在深入多集群压测之前,必须重新夯实 etcd 最核心的三块基石:Raft 共识协议、集群角色转换以及底层存储引擎。压测中遇到的绝大多数异常——Leader 频繁切换、写入延迟抖动、磁盘 I/O 瓶颈——根源都藏在这三层之中。
2.1 Raft 协议原理:从选举到日志复制
etcd 使用 Raft 协议保证分布式一致性。Raft 将共识问题拆解为三个子问题:Leader 选举、日志复制、安全性。压测时最常触及的是前两个。
压测关键认知: Raft 是强 Leader 模型,所有写入必须经过 Leader。Leader 的吞吐能力直接决定集群写入上限。压测中如果 QPS 超过单机瓶颈,首先观察到的是 Leader 节点网络/磁盘延迟飙升,随后可能触发选举。
2.1.1 选举流程与超时机制
| 概念 | 默认值 | 压测影响 |
|---|---|---|
| Election Timeout | 1000 ms | 网络分区或 Leader 过载时,Follower 收不到心跳会发起选举,导致集群短暂不可写 |
| Heartbeat Interval | 100 ms | Leader 每 100ms 向 Follower 发送心跳;压测高负载时心跳可能延迟,引发误选举 |
| 随机化选举超时 | [1000ms, 1200ms] | 避免多个 Follower 同时发起选举导致选票分裂 |
压测避坑: 当集群节点数 ≥ 5 且网络延迟 > 50ms 时,建议将
--election-timeout 调至 5000ms,防止瞬时负载高峰触发不必要的 Leader 选举。
2.1.2 日志复制(Log Replication)
客户端写入请求到达 Leader 后,经历以下步骤:
- 追加日志:Leader 将请求封装为 Log Entry,写入本地 BoltDB 并追加到 Raft Log。
- 并行广播:Leader 向所有 Follower 发送
AppendEntriesRPC。 - 多数派确认:当 Leader 收到多数节点(N/2+1)的确认后,将日志标记为 Committed。
- 应用到状态机:Leader 将 Committed 日志应用到 backend 存储,返回客户端成功。
压测中,步骤 2 和 3 是主要瓶颈:网络带宽、Follower 磁盘写入速度、以及 Leader 的并发 RPC 处理能力都会影响整体延迟。
2.2 集群角色:Leader / Follower / Candidate
etcd 集群中每个节点在任意时刻处于三种角色之一。压测时角色转换是重要的监控指标。
| 角色 | 职责 | 压测中常见状态 |
|---|---|---|
| Leader | 处理所有客户端写入;管理日志复制;发送心跳 | CPU/网络/磁盘成为瓶颈;心跳延迟可能导致降级为 Follower |
| Follower | 接收 Leader 的日志复制;处理只读请求(可配置);参与选举投票 | 通常负载较低;但如果开启 --experimental-read-from-follower,读压力会分散到 Follower |
| Candidate | 选举超时后发起选举;向其他节点请求投票 | 压测中如果频繁出现 Candidate,说明集群不稳定,需要排查网络或 Leader 过载 |
压测建议: 在压测脚本中增加
etcdctl endpoint status --cluster 轮询,实时监控 Leader 是否发生变化。如果压测期间 Leader 切换超过 3 次,说明集群配置或负载设计存在问题。
2.3 数据模型与存储引擎:BoltDB & Backend
etcd 的数据存储分为两层:Raft Log 和 状态机快照。最终持久化依赖 BoltDB(etcd v3 默认存储引擎)。
2.3.1 数据模型:MVCC 与 Revision
etcd v3 采用 多版本并发控制(MVCC),每个 key-value 对维护一个全局递增的 revision。每次写入生成一个新版本,旧版本在压缩(Compact)之前保留。
- Key-Value 存储:底层是一个有序的 B+ 树,key 为
key + revision的组合。 - Revision 机制:全局单调递增,用于实现 Watch、事务和历史查询。
- 压缩(Compaction):定期删除旧版本,防止 BoltDB 无限膨胀。压测中如果压缩不及时,会导致磁盘空间暴涨。
2.3.2 BoltDB 存储结构
BoltDB 是一个嵌入式、单机、事务性的 KV 存储引擎,etcd 使用它持久化所有数据。每个 etcd 节点在磁盘上维护一个 member/snap/db 文件。
| BoltDB 特性 | 对压测的影响 |
|---|---|
| B+ 树索引 | 读性能稳定,但大量随机写入会导致 B+ 树频繁分裂,增加磁盘 I/O |
| 事务(Tx) | 每个 Raft 日志条目对应一个 BoltDB 事务;高并发下事务冲突可能增加延迟 |
| 内存映射文件(mmap) | BoltDB 将文件映射到内存,压测时内存占用与数据量成正比 |
| 页面大小(Page Size) | 默认 4KB,大 value(>1MB)会导致跨页存储,降低读写性能 |
压测避坑: BoltDB 单文件不支持并发写入。etcd 通过 Raft 序列化所有写入,但 BoltDB 内部的事务锁在极高并发(>10k QPS)下会成为瓶颈。建议压测时监控
etcd_disk_backend_commit_duration_seconds 指标,如果 commit 延迟 > 100ms,说明磁盘 I/O 已达上限。
2.4 压测视角的关键指标映射
将上述架构知识映射到压测可观测指标:
| 架构层 | 关键指标 | 压测阈值参考 |
|---|---|---|
| Raft 选举 | etcd_server_leader_changes_seen_total |
压测期间变化 ≤ 1 次 |
| Raft 日志复制 | etcd_server_proposals_failed_total |
始终为 0 |
| MVCC 版本 | etcd_mvcc_db_total_size_in_bytes |
增长曲线平滑,无突增 |
| BoltDB 提交 | etcd_disk_backend_commit_duration_seconds |
P99 < 50ms |
| BoltDB 文件大小 | etcd_mvcc_db_total_size_in_bytes |
不超过节点内存的 70% |
核心结论: 压测不是盲目发请求,而是验证 Raft 协议在负载下的稳定性、MVCC 版本管理对磁盘的影响、以及 BoltDB 在事务压力下的响应能力。理解这三层,才能设计出有效的压测场景并准确解读结果。