2. etcd 基础回顾:核心概念与 Raft 共识

在深入压测之前,必须牢固掌握 etcd 的三大核心抽象:键值存储、Watch 机制和Lease 租约,以及支撑其高可用的 Raft 共识算法。这些概念直接决定了压测场景的设计、指标采集和瓶颈分析方向。

2.1 键值存储 (Key-Value Store)

etcd 是一个分层组织的键值存储系统,所有数据以 key 和 value 的形式存储,并支持按前缀或范围进行高效查询。

  • Key 结构:采用类似文件系统的 / 分隔路径,例如 /config/app/db_host。这种结构天然支持目录式管理和前缀扫描。
  • Value 限制:默认最大 1.5 MiB。超过该限制会触发 etcdserver: request is too large 错误,这是压测中常见的边界条件。
  • 版本号 (Revision):每次写入都会递增全局 revision,用于实现 MVCC 和 Watch 机制。
压测启示:压测时需关注 PUT 和 RANGE 操作的延迟分布。大 Value(接近 1 MiB)会显著增加网络带宽和磁盘 I/O,导致 P99 延迟飙升。

2.2 Watch 机制

Watch 是 etcd 实现事件驱动架构的核心。客户端可以监听某个 key 或前缀,当数据发生变化时,etcd 会实时推送事件。

Watch 类型 触发条件 典型应用场景
Key Watch 单个 key 的创建、更新、删除 服务发现中的单实例状态监听
Prefix Watch 指定前缀下任意 key 的变化 配置中心批量监听 /config/ 下所有配置项
Progress Notification 服务端主动通知客户端当前进度 避免长时间无事件导致连接超时
压测陷阱:大量并发 Watch(尤其是前缀 Watch)会占用服务端大量内存和 goroutine。压测时需监控 etcd_debugging_mvcc_watcher_total 指标,防止 Watch 堆积导致 OOM。

2.3 Lease 租约

Lease 是一种带超时时间的租约,用于实现 key 的自动过期和心跳保活。它是 etcd 实现分布式锁、服务健康检查的基础。

  • 创建 Lease:指定 TTL(例如 10 秒),返回 Lease ID。
  • 绑定 Key:将 key 与 Lease ID 关联,key 的存活时间由 Lease 控制。
  • 续约 (KeepAlive):客户端定期发送心跳,重置 Lease 的 TTL。
  • 过期:若心跳中断超过 TTL,Lease 自动过期,所有关联的 key 被删除。
# 创建 TTL=60s 的 Lease
etcdctl lease grant 60
# 输出:lease 694d7f2b4e7a8b9c granted with TTL(60s)

# 绑定 key
etcdctl put /service/node1 --lease=694d7f2b4e7a8b9c

# 续约(客户端需周期性执行)
etcdctl lease keep-alive 694d7f2b4e7a8b9c

2.4 Raft 共识算法简介

etcd 使用 Raft 算法实现强一致性。Raft 将节点分为三种角色:Leader、Follower 和 Candidate。

Raft 角色状态机与日志复制流程 Raft 角色状态机与日志复制流程 Follower Candidate Leader 选举超时 获得多数票 发现更高任期 Leader 日志复制流程(Leader 处理写请求) 1. 客户端发送写请求给 Leader 2. Leader 将日志条目追加到本地日志 3. Leader 并行发送 AppendEntries RPC 给所有 Follower 4. 多数 Follower 写入成功后,Leader 提交日志并返回客户端

Raft 的核心流程可概括为 Leader 选举和日志复制两个阶段:

  1. Leader 选举:Follower 在选举超时后转为 Candidate,发起投票。获得超过半数(N/2+1)节点投票的 Candidate 成为 Leader。
  2. 日志复制:所有写请求必须经过 Leader。Leader 将日志条目复制到多数 Follower 后,才视为提交成功并返回客户端。
压测关键指标:Raft 的提交延迟受网络往返时间(RTT)和磁盘 fsync 延迟影响。压测时需关注 etcd_server_proposal_commit_duration_seconds 指标,该指标直接反映 Raft 层的性能瓶颈。
etcd 内部架构分层与请求处理路径 etcd 内部架构分层与请求处理路径 gRPC 客户端 API 层 (gRPC Gateway / v3 API) Raft 共识模块 存储层 (boltdb / WAL / Snapshot)

从架构分层看,一个写请求的完整路径为:gRPC 客户端 → API 层 → Raft 共识模块 → 存储层。每一层都可能成为压测瓶颈:

  • API 层:序列化/反序列化开销,大量并发连接时的 goroutine 调度。
  • Raft 层:网络 I/O、Leader 选举抖动、日志复制延迟。
  • 存储层:磁盘 fsync 性能、boltdb 事务锁竞争、WAL 写入带宽。
压测策略:通过分层监控指标(如 etcd_server_proposal_commit_duration_seconds、etcd_disk_wal_fsync_duration_seconds)可以快速定位瓶颈发生在哪一层,从而制定针对性的优化方案。