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 后,经历以下步骤:

  1. 追加日志:Leader 将请求封装为 Log Entry,写入本地 BoltDB 并追加到 Raft Log。
  2. 并行广播:Leader 向所有 Follower 发送 AppendEntries RPC。
  3. 多数派确认:当 Leader 收到多数节点(N/2+1)的确认后,将日志标记为 Committed。
  4. 应用到状态机:Leader 将 Committed 日志应用到 backend 存储,返回客户端成功。

压测中,步骤 2 和 3 是主要瓶颈:网络带宽、Follower 磁盘写入速度、以及 Leader 的并发 RPC 处理能力都会影响整体延迟。

Raft 日志复制流程(多数派提交) Client Leader Follower 1 Follower 2 Follower 3 1. 写入请求 2. AppendEntries 3. 确认 多数派确认:3 节点集群中,Leader 收到至少 2 个 Follower 确认(含自身)即可提交 压测关注点:网络延迟、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 已达上限。
etcd 存储引擎分层架构 客户端请求(gRPC API) Raft 共识层(日志复制 + 选举) MVCC 层(多版本控制 + 事务) Backend 层(事务封装 + Buffer) BoltDB(B+ 树 + mmap 持久化) 压测关注点 • Raft 层:选举频率 • MVCC 层:版本膨胀 • Backend:事务冲突 • BoltDB:磁盘 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 在事务压力下的响应能力。理解这三层,才能设计出有效的压测场景并准确解读结果。