4. 压测沙盘环境搭建:使用 docker-compose 搭建 3 节点 etcd 集群、配置参数详解
在压测沙盘中,一个稳定且可复现的 etcd 集群是故障注入与排查的基础。本章将使用 docker-compose 在单机环境下快速拉起一个 3 节点 etcd 集群,并深入解析影响集群稳定性的核心配置参数:心跳间隔、选举超时与快照策略。
4.1 环境准备与目录结构
在开始之前,确保宿主机已安装 Docker 和 Docker Compose。建议使用以下目录结构来组织沙盘文件:
etcd-sandbox/
├── docker-compose.yml
├── etcd1/
│ └── data/
├── etcd2/
│ └── data/
└── etcd3/
└── data/
4.2 docker-compose.yml 完整配置
以下是一个可直接用于压测沙盘的 3 节点 etcd 集群配置。每个节点使用独立的容器、数据卷和端口映射,并显式配置了关键参数。
version: '3.8'
services:
etcd1:
image: quay.io/coreos/etcd:v3.5.9
container_name: etcd-sandbox-1
hostname: etcd1
ports:
- "23791:2379"
- "23801:2380"
volumes:
- ./etcd1/data:/etcd-data
environment:
- ETCD_NAME=etcd1
- ETCD_DATA_DIR=/etcd-data
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_=etcd-sandbox-
- ETCD_INITIAL_CLUSTER_STATE=new
# 核心参数
- ETCD_HEARTBEAT_INTERVAL=100
- ETCD_ELECTION_TIMEOUT=1000
- ETCD_SNAPSHOT_COUNT=10000
networks:
- etcd-net
etcd2:
image: quay.io/coreos/etcd:v3.5.9
container_name: etcd-sandbox-2
hostname: etcd2
ports:
- "23792:2379"
- "23802:2380"
volumes:
- ./etcd2/data:/etcd-data
environment:
- ETCD_NAME=etcd2
- ETCD_DATA_DIR=/etcd-data
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd2:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_=etcd-sandbox-
- ETCD_INITIAL_CLUSTER_STATE=new
- ETCD_HEARTBEAT_INTERVAL=100
- ETCD_ELECTION_TIMEOUT=1000
- ETCD_SNAPSHOT_COUNT=10000
networks:
- etcd-net
etcd3:
image: quay.io/coreos/etcd:v3.5.9
container_name: etcd-sandbox-3
hostname: etcd3
ports:
- "23793:2379"
- "23803:2380"
volumes:
- ./etcd3/data:/etcd-data
environment:
- ETCD_NAME=etcd3
- ETCD_DATA_DIR=/etcd-data
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd3:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_=etcd-sandbox-
- ETCD_INITIAL_CLUSTER_STATE=new
- ETCD_HEARTBEAT_INTERVAL=100
- ETCD_ELECTION_TIMEOUT=1000
- ETCD_SNAPSHOT_COUNT=10000
networks:
- etcd-net
networks:
etcd-net:
driver: bridge
etcd-sandbox/ 目录下执行 docker-compose up -d,等待约 5 秒后,使用 docker-compose ps 确认三个节点均为 Up 状态。使用 docker exec etcd-sandbox-1 etcdctl endpoint health --cluster 验证集群健康。
4.3 核心配置参数详解
etcd 的稳定性高度依赖 Raft 协议的时间参数与存储策略。以下三个参数是压测沙盘中必须理解并可能调整的关键项。
4.3.1 心跳间隔(Heartbeat Interval)
参数名:--heartbeat-interval(环境变量 ETCD_HEARTBEAT_INTERVAL)
默认值:100 毫秒
作用:Leader 向 Follower 发送心跳消息的时间间隔。心跳用于维持 Leader 权威并防止 Follower 发起不必要的选举。
- 过小(如 50ms):网络开销增大,CPU 占用上升,但 Leader 故障检测更快。
- 过大(如 500ms):网络负载降低,但 Follower 可能因未及时收到心跳而误判 Leader 失效,触发频繁选举。
- 压测建议:在沙盘中保持 100ms 默认值,模拟 Leader 网络分区时可临时调大至 300ms 以观察选举超时行为。
4.3.2 选举超时(Election Timeout)
参数名:--election-timeout(环境变量 ETCD_ELECTION_TIMEOUT)
默认值:1000 毫秒
作用:Follower 等待 Leader 心跳的最大时间。若超时未收到心跳,Follower 转换为 Candidate 并发起选举。
- 选举超时 = 心跳间隔 × 随机因子(默认 1~2 倍)。例如心跳 100ms,选举超时 1000ms,则实际超时在 1000ms~2000ms 之间随机。
- 过小(如 400ms):集群对 Leader 故障敏感,但可能因瞬时网络抖动导致频繁选举,降低可用性。
- 过大(如 3000ms):Leader 故障后集群恢复时间变长,服务中断窗口增大。
- 压测建议:沙盘中保持 1000ms。在模拟 Leader 节点宕机时,可观察约 1~2 秒的不可用窗口,符合预期。
4.3.3 快照策略(Snapshot Count)
参数名:--snapshot-count(环境变量 ETCD_SNAPSHOT_COUNT)
默认值:100000 条
作用:当 etcd 数据存储中累积的变更记录(Entry)达到此数量时,触发一次快照(Snapshot)。快照将当前状态持久化到磁盘,并截断 WAL 日志以释放空间。
- 过小(如 1000):快照频繁,磁盘 I/O 和 CPU 开销增加,但节点重启时恢复速度更快。
- 过大(如 1000000):快照间隔长,WAL 日志膨胀,节点重启时需回放大量日志,启动变慢。
- 压测建议:沙盘中设置为 10000,便于在压测写入时快速触发快照,观察快照对写入延迟的影响。
4.4 参数对比与推荐值
| 参数 | 默认值 | 沙盘推荐值 | 压测调整范围 | 影响维度 |
|---|---|---|---|---|
| 心跳间隔 | 100ms | 100ms | 50ms ~ 500ms | 网络开销、Leader 检测速度 |
| 选举超时 | 1000ms | 1000ms | 400ms ~ 3000ms | 故障恢复时间、选举稳定性 |
| 快照计数 | 100000 | 10000 | 1000 ~ 1000000 | 磁盘 I/O、节点重启速度 |
4.5 集群启动后的验证步骤
- 检查成员列表:
docker exec etcd-sandbox-1 etcdctl member list,应输出 3 个节点。 - 检查集群健康:
docker exec etcd-sandbox-1 etcdctl endpoint health --cluster,所有节点应为healthy。 - 验证 Leader:
docker exec etcd-sandbox-1 etcdctl endpoint status --cluster -w table,查看IS LEADER列。 - 写入测试:
docker exec etcd-sandbox-1 etcdctl put /test/key1 "hello-sandbox",然后get确认。
docker-compose.yml 中的 ETCD_HEARTBEAT_INTERVAL 和 ETCD_ELECTION_TIMEOUT 来模拟“心跳延迟”和“选举超时”故障场景。建议在压测前先使用默认参数运行 5 分钟,观察基线行为。
4.6 3 节点 etcd 集群架构图
下图展示了沙盘中 3 节点 etcd 集群的组件关系与通信路径。Leader 负责处理客户端写入并同步日志到 Follower,Follower 转发读请求或提供线性一致读。
4.7 快照与 WAL 日志关系图
快照策略直接影响 etcd 的存储行为。下图展示了 Entry 累积、快照触发与 WAL 截断的流程。
snapshot-count 设置为 10000 可能导致快照频繁触发(每 2 秒一次),从而引起磁盘 I/O 抖动。此时可适当调大至 50000 以降低快照频率,但需权衡节点重启恢复时间。
4.8 常见问题与避坑
- 端口冲突:宿主机上 2379/2380 端口可能被其他 etcd 或服务占用。使用
23791~23793和23801~23803避免冲突。 - 数据持久化:挂载本地目录时,确保
./etcd1/data等目录存在且具有写权限,否则容器启动失败。 - 网络模式:使用自定义 bridge 网络
etcd-net,确保容器间通过 hostname 互通。不要使用network_mode: host,否则端口映射失效。 - 初始集群状态:首次启动使用
new;若重建集群,需清空数据目录或改为existing。