ETCD 配额/空间告警模拟方案

目录


概述

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:默认 etcd
  • ETCDCTL_ENDPOINTS:默认 http://127.0.0.1:2379
  • ETCDCTL_USER / ETCDCTL_PASSWORD:默认 root / johnny
  • PARALLEL_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 环境(脚本使用了 mkfifopkillpgrep 等命令;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(更新时用)
  • ddwcawksedgrepmktempmkfifopkillpgrep
相关推荐
CHENKONG_CK6 小时前
晨控CK-LR08-E00与汇川H5U系列PLC配置MODBUSTCP通讯连接手册
linux·服务器·网络
天荒地老笑话么6 小时前
静态 IP 规划:掩码/网关/DNS 的正确组合
网络·网络协议·tcp/ip·网络安全
猫头虎6 小时前
基于信创openEuler系统安装部署OpenTeleDB开源数据库的实战教程
数据库·redis·sql·mysql·开源·nosql·database
爬山算法6 小时前
MongoDB(1)什么是MongoDB?
数据库·mongodb
Tadas-Gao6 小时前
TCP粘包现象的深度解析:从协议本质到工程实践
网络·网络协议·云原生·架构·tcp
Nandeska6 小时前
17、MySQL InnoDB ReplicaSet
数据库·mysql
AI_56786 小时前
SQL性能优化全景指南:从量子执行计划到自适应索引的终极实践
数据库·人工智能·学习·adb
IOsetting6 小时前
金山云主机添加开机路由
运维·服务器·开发语言·网络·php
数据知道6 小时前
PostgreSQL 性能优化:分区表实战
数据库·postgresql·性能优化