目录
概述
etcd-quota-simulator.sh 是一款用于模拟 ETCD 数据库高使用率、触发 NOSPACE 空间告警等场景的测试脚本。
核心功能
- 并发写入/更新 - 支持高并发数据写入和更新,显著缩短将 ETCD 推到接近配额/触发告警的时间
- 自愈脚本验证 - 验证自愈脚本对 ETCD 空间告警的识别与处理能力
- 碎片整理链路验证 - 验证
defrag(碎片整理)与清告警(alarm disarm)链路 - 可控终止 - 压测过程中支持可中断、可停止能力,避免人工到处
kill
适用场景
- ETCD 空间告警模拟与自愈演练
- 验证碎片整理和告警清除流程
- 测试 ETCD 配额限制下的系统行为
- 压测 ETCD 性能与稳定性
快速开始
步骤 1:确认连接
bash
bash etcd-quota-simulator.sh status
步骤 2:制造现场(不清理)
适用于需要保留现场给自愈脚本跑的场景:
bash
bash etcd-quota-simulator.sh simulate --size 60 --updates 1000 --parallel 10
步骤 3:闭环演练(制造 + 恢复)
适用于完整的测试闭环:
bash
bash etcd-quota-simulator.sh full --size 60 --updates 1000 --parallel 10
步骤 4:随时中止
另开终端执行:
bash
bash etcd-quota-simulator.sh stop
功能参考
命令总览
| 类别 | 命令/功能 | 说明 | 适合场景 | 使用示例 |
|---|---|---|---|---|
| 帮助 | help |
查看脚本说明、命令、参数、性能参考 | 初次使用、查参数 | bash etcd-quota-simulator.sh help |
| 初始化 | init |
检查容器是否存在/运行;检查容器内 etcdctl 是否可用;创建备份目录;记录 PID |
开始前环境自检 | bash etcd-quota-simulator.sh init |
| 备份 | backup |
备份容器 inspect、环境变量、(尽力)记录 db 文件大小 |
操作前留档,便于回溯 | bash etcd-quota-simulator.sh backup |
| 查看配置 | config |
打印 ETCD 相关环境变量、db 大小、当前配额(ETCD_QUOTA_BACKEND_BYTES) |
核对配额/环境变量 | bash etcd-quota-simulator.sh config |
| 修改配置(可选) | modify + --quota |
通过重建容器注入新配额/压缩参数(脚本的 full/simulate 中默认注释了自动 modify) | 需要主动降低配额以更快触发告警 | bash etcd-quota-simulator.sh modify --quota 104857600 |
| 并发写入 | write + --size + --parallel |
并发写入 key(按前缀 /test-simulation/),更快把 db 推高;统计成功/失败和速率 |
快速制造高使用率/逼近配额 | bash etcd-quota-simulator.sh write --size 50 --parallel 20 |
| 并发更新 | update + --updates + --parallel |
并发更新同一 key(key1)触发历史版本增长;统计成功/失败和速率 |
制造版本膨胀、碎片,为 defrag/自愈验证做准备 | bash etcd-quota-simulator.sh update --updates 3000 --parallel 30 |
| 状态检查 | status |
查看 alarm list(关注 NOSPACE)、endpoint status、db 文件大小、配额、使用率 |
判断是否触发告警/是否接近配额 | bash etcd-quota-simulator.sh status |
| 清理数据 | cleanup |
按前缀删除测试数据:/test-simulation/ |
压测后回收空间 | bash etcd-quota-simulator.sh cleanup |
| 碎片整理 | defrag |
优先执行 /data/health_check/etcd-defrag.sh;不存在则 etcdctl defrag |
清理碎片、验证碎片整理链路 | bash etcd-quota-simulator.sh defrag |
| 清告警 | clear |
执行 alarm disarm 清除告警 |
NOSPACE 后恢复写入能力/恢复健康 | bash etcd-quota-simulator.sh clear |
| 一键模拟(不清理) | simulate |
init→backup→write→update→check_alarms→check_db_status(不清理) | 需要保留现场给自愈/排查使用 | bash etcd-quota-simulator.sh simulate --size 60 --updates 1000 --parallel 15 |
| 一键完整(含清理) | full |
在 simulate 基础上:cleanup→defrag→clear→复查状态 | 演练"制造问题→恢复环境"闭环 | bash etcd-quota-simulator.sh full --size 80 --updates 2000 --parallel 20 |
| 停止任务 | stop |
停止正在运行的压测(PID 文件 + kill/清理子进程);脚本也对 SIGINT/SIGTERM 做了清理 | 并发任务卡住/需要紧急中止 | bash etcd-quota-simulator.sh stop |
参数说明
命令行参数:
--quota <bytes>:测试配额(用于modify,默认104857600= 100MB)--size <mb>:写入目标大小(默认60;脚本内部按size_mb * 10条 key 估算)--updates <num>:更新次数(默认1000)--parallel <num>:并发数(默认10)
使用示例:
bash
bash etcd-quota-simulator.sh simulate --quota 104857600 --size 80 --updates 3000 --parallel 20
环境变量
以下环境变量可覆盖默认值:
ETCD_CONTAINER_NAME:默认etcdETCDCTL_ENDPOINTS:默认http://127.0.0.1:2379ETCDCTL_USER/ETCDCTL_PASSWORD:默认root/johnnyPARALLEL_JOBS:默认10(也可用--parallel覆盖)
使用示例:
bash
ETCD_CONTAINER_NAME=my-etcd \
ETCDCTL_ENDPOINTS=http://10.0.0.1:2379 \
ETCDCTL_USER=root ETCDCTL_PASSWORD=xxxx \
bash etcd-quota-simulator.sh status
使用场景
场景 A:保留现场给自愈脚本跑
目标 :制造高使用率/可能触发 NOSPACE,但不清理,方便在现场运行自愈流程验证效果。
bash
bash etcd-quota-simulator.sh simulate --size 60 --updates 2000 --parallel 10
然后运行你的自愈脚本/监控验证;最后再手工恢复:
bash
bash etcd-quota-simulator.sh cleanup
bash etcd-quota-simulator.sh defrag
bash etcd-quota-simulator.sh clear
bash etcd-quota-simulator.sh status
场景 B:闭环演练(制造问题 + 恢复)
目标:一条命令跑完,结束后环境尽量回到"可用状态"(测试数据清理 + defrag + clear)。
bash
bash etcd-quota-simulator.sh full --size 60 --updates 1000 --parallel 10
场景 C:只做单点验证
只压写入:
bash
bash etcd-quota-simulator.sh write --size 50 --parallel 20
只压更新(制造碎片/版本膨胀):
bash
bash etcd-quota-simulator.sh update --updates 5000 --parallel 20
故障排查
输出与文件说明
脚本会创建/使用以下路径:
- 日志 :
/var/log/etcd-simulation.log - 备份目录 :
/tmp/etcd-simulation-backup - PID 文件 :
/tmp/etcd-simulation.pid(用于stop) - 临时结果文件 :
mktemp动态生成(写入/更新完成后会删除)
常见错误处理
问题 1:permission denied(日志无法写入 /var/log)
现象 :启动就报权限问题或 tee 失败。
处理:
- 使用 sudo 执行:
sudo bash etcd-quota-simulator.sh status - 或临时把脚本里的
LOG_FILE改到可写目录(如/tmp/etcd-simulation.log)
问题 2:jq: command not found / bc: command not found / xxd: command not found
处理 :安装对应工具包(不同发行版命令不同),或先用 init/write/update 等不依赖 jq/bc 的部分功能(但多数状态展示会缺失/报错)。
问题 3:并发压测速度很慢或大量失败
建议:
- 降低并发:
--parallel 5或--parallel 10 - 先跑
status看是否已经触发NOSPACE - 检查 endpoint、用户密码是否正确
- 检查宿主机 IO 是否瓶颈、ETCD 是否健康
问题 4:需要立刻停掉脚本
优先使用:
bash
bash etcd-quota-simulator.sh stop
或直接 Ctrl+C(脚本已对信号做了清理)
常见问题
Q:为什么 simulate/full 里没有自动执行 modify?
A:脚本默认注释了 modify_config 调用,避免误操作重建容器。若你确实需要脚本自动降低配额触发告警,可自行取消注释或单独先执行 modify。
Q:执行 modify 会不会丢数据?
A:脚本会删除并重建容器,但仍挂载 -v /data/etcd:/data,理论上数据目录复用;风险在于容器重建参数、环境变量、镜像等差异可能带来不可预期行为,务必先在演练环境验证并备份。
Q:如何选择并发数?
A:从 10 起步观察宿主机与 ETCD 负载;若只是触发告警不追求极限速度,10~20 往往足够。
附录
附录A:ETCD 原生命令参考
本节列出脚本中使用的核心命令,方便你手动执行、调试或在无法运行脚本时进行故障排查。
A.1 容器管理命令
检查容器状态
bash
# 查看所有容器(包括停止的)
docker ps -a | grep etcd
# 查看运行中的容器
docker ps | grep etcd
# 查看容器详细配置
docker inspect etcd
# 查看容器环境变量
docker inspect etcd | jq -r '.[0].Config.Env[]'
docker inspect etcd | jq -r '.[0].Config.Env[]' | grep ETCD
启动/停止容器
bash
# 启动容器
docker start etcd
# 停止容器
docker stop etcd
# 删除容器(注意:会丢失未持久化数据)
docker rm etcd
重建容器(修改配额示例)
bash
# 获取当前镜像
IMAGE=$(docker inspect etcd | jq -r '.[0].Image')
# 停止并删除容器
docker stop etcd
docker rm etcd
# 重建容器(设置 100MB 配额,禁用自动压缩)
docker run -d \
--name etcd \
--network host \
--restart always \
-v /data/etcd:/data \
-e "ETCD_QUOTA_BACKEND_BYTES=104857600" \
-e "ETCD_AUTO_COMPACTION_RETENTION=0" \
${IMAGE}
A.2 ETCD 健康与状态检查
健康检查
bash
# 检查 endpoint 健康状态
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint health
# 多 endpoint 检查
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379,http://127.0.0.1:2380 \
--user=root:johnny \
endpoint health
状态查询
bash
# 查看 endpoint 状态(表格输出)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint status --write-out=table
# JSON 格式输出(便于脚本解析)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint status --write-out=json
数据库大小查询
bash
# 查看 db 文件大小(容器内)
docker exec etcd du -sb /data/etcd/member/snap/db
# 人类可读格式
docker exec etcd du -sh /data/etcd/member/snap/db
# 宿主机路径(如果挂载到宿主机)
du -sh /data/etcd/member/snap/db
A.3 告警管理
查看告警
bash
# 列出所有告警
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm list
# 检查是否有 NOSPACE 告警
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm list | grep NOSPACE
清除告警
bash
# 清除所有告警(在 defrag 之后执行)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm disarm
A.4 数据写入与删除
写入单个 key
bash
# 写入简单 key-value
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
put /test-simulation/key1 "test-value"
# 写入大 value(100KB 随机数据,用于快速增大 db)
dd if=/dev/urandom bs=1024 count=100 2>/dev/null | \
docker exec -i -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
put /test-simulation/key1
读取 key
bash
# 读取单个 key
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
get /test-simulation/key1
# 按前缀读取
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
get /test-simulation/ --prefix
删除 key
bash
# 删除单个 key
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
del /test-simulation/key1
# 按前缀删除(清理测试数据)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
del /test-simulation/ --prefix
A.5 碎片整理(Defrag)
执行碎片整理
bash
# 对当前 endpoint 执行 defrag
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
defrag
# 对多个 endpoint 执行(集群场景)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379,http://127.0.0.1:2380,http://127.0.0.1:2381 \
--user=root:johnny \
defrag
# defrag 前后对比 db 大小
echo "Before defrag:"
docker exec etcd du -sh /data/etcd/member/snap/db
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
defrag
echo "After defrag:"
docker exec etcd du -sh /data/etcd/member/snap/db
A.6 压缩(Compaction)
手动压缩历史版本
bash
# 查看当前 revision
REVISION=$(docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint status --write-out=json | jq -r '.[0].Status.header.revision')
echo "Current revision: $REVISION"
# 压缩到当前 revision(保留最新状态)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
compact $REVISION
# 推荐流程:compact → defrag → alarm disarm
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
compact $(docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint status --write-out=json | jq -r '.[0].Status.header.revision')
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
defrag
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm disarm
A.7 配额查询与计算
查看当前配额设置
bash
# 从容器环境变量获取
docker inspect etcd | \
jq -r '.[0].Config.Env[] | select(startswith("ETCD_QUOTA_BACKEND_BYTES=")) | split("=")[1]'
# 或使用 grep
docker inspect etcd | grep ETCD_QUOTA_BACKEND_BYTES
计算使用率
bash
# 获取 db 大小(字节)
DB_SIZE=$(docker exec etcd du -sb /data/etcd/member/snap/db 2>/dev/null | awk '{print $1}')
# 获取配额(字节)
QUOTA=$(docker inspect etcd | \
jq -r '.[0].Config.Env[] | select(startswith("ETCD_QUOTA_BACKEND_BYTES=")) | split("=")[1]')
# 计算使用率
USAGE=$(echo "scale=2; $DB_SIZE * 100 / $QUOTA" | bc)
echo "数据库使用率: ${USAGE}%"
# 转换为 MB
DB_SIZE_MB=$(echo "scale=2; $DB_SIZE / 1024 / 1024" | bc)
QUOTA_MB=$(echo "scale=2; $QUOTA / 1024 / 1024" | bc)
echo "DB 大小: ${DB_SIZE_MB} MB / 配额: ${QUOTA_MB} MB"
A.8 TLS 支持(生产环境推荐)
如果你的 ETCD 启用了 TLS,需要在命令中添加证书参数:
bash
# 带 TLS 的健康检查
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/path/to/ca.crt \
--cert=/path/to/client.crt \
--key=/path/to/client.key \
--user=root:password \
endpoint health
# 或使用环境变量
docker exec \
-e ETCDCTL_API=3 \
-e ETCDCTL_CACERT=/path/to/ca.crt \
-e ETCDCTL_CERT=/path/to/client.crt \
-e ETCDCTL_KEY=/path/to/client.key \
etcd etcdctl --endpoints=https://127.0.0.1:2379 \
--user=root:password \
endpoint health
A.9 快速故障排查命令组合
场景 1:NOSPACE 告警后的恢复
bash
# 1. 确认告警
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm list
# 2. 删除不必要的测试数据(可选)
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
del /test-simulation/ --prefix
# 3. 执行压缩
REV=$(docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint status --write-out=json | jq -r '.[0].Status.header.revision')
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
compact $REV
# 4. 执行碎片整理
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
defrag
# 5. 清除告警
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm disarm
# 6. 验证恢复
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
endpoint status --write-out=table
场景 2:快速制造空间压力(手动模拟)
bash
# 1. 记录当前状态
docker exec etcd du -sh /data/etcd/member/snap/db
# 2. 批量写入大 value(示例:写入 100 条 100KB 数据)
for i in {1..100}; do
dd if=/dev/urandom bs=1024 count=100 2>/dev/null | \
docker exec -i -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
put /test-simulation/key${i}
echo "写入 key${i}"
done
# 3. 频繁更新触发版本增长(示例:更新 500 次)
for i in {1..500}; do
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
put /test-simulation/key1 "value-${i}-$(date +%s%N)"
[ $((i % 50)) -eq 0 ] && echo "已更新 ${i} 次"
done
# 4. 检查告警
docker exec -e ETCDCTL_API=3 etcd \
etcdctl --endpoints=http://127.0.0.1:2379 \
--user=root:johnny \
alarm list
A.10 环境变量与参数说明
以下环境变量可在命令中替换为你的实际值:
| 变量 | 默认值 | 说明 |
|---|---|---|
ETCDCTL_API |
3 |
使用 API v3(必须) |
--endpoints |
http://127.0.0.1:2379 |
ETCD endpoint 地址 |
--user |
root:johnny |
用户名:密码(按需替换) |
| 容器名 | etcd |
Docker 容器名称 |
ETCD_QUOTA_BACKEND_BYTES |
8589934592 (8GB) |
后端存储配额 |
| db 路径(容器内) | /data/etcd/member/snap/db |
数据库文件路径 |
提示:以上命令均可直接在终端执行,无需依赖脚本。建议先在测试环境验证后再在生产环境使用。
附录B:设计说明
- 并发控制 :使用
mkfifo+ 文件描述符信号量限制并发任务数量。 - 写入/更新结果 :每个任务向临时结果文件写入
1/0,最终统计成功/失败并计算速率。 - 可控终止 :
trap捕获SIGINT/SIGTERM/SIGHUP,清理子进程、临时文件与 PID 文件。
附录C:风险提示与依赖清单
风险提示(务必阅读)
- 强烈建议仅在测试/演练环境使用;生产环境执行高并发写入/更新可能导致 ETCD 或宿主机 IO/CPU 压力上升。
modify命令会停止并删除 现有 ETCD 容器并重建(数据目录通过/data/etcd挂载复用)。使用前请确认风险与回滚方案。- 脚本默认日志写入
LOG_FILE=/var/log/etcd-simulation.log;在某些环境下可能需要 root 权限,否则会出现无法写日志的问题。
依赖与前置条件
环境要求:
- Linux 环境(脚本使用了
mkfifo、pkill、pgrep等命令;Windows 下请在 WSL 或 Linux 主机运行) - 已安装并可用:
docker - ETCD 以容器方式运行,且容器内包含
etcdctl - 容器使用 host 网络或可通过
ETCDCTL_ENDPOINTS访问到 endpoint(默认http://127.0.0.1:2379) - ETCD 启用了用户名密码认证(脚本默认
root/johnny,可通过环境变量覆盖)
常用外部命令:
脚本中会用到以下工具(不同功能覆盖不同工具):
jq:解析docker inspect输出(backup/config/status等)bc:计算 MB、速率、使用率(输出展示用)xxd:生成随机 value(更新时用)dd、wc、awk、sed、grep、mktemp、mkfifo、pkill、pgrep