3. 配额(Quota)机制详解
3.1 etcd 的存储配额是什么
etcd 的存储配额(Quota)是一个硬性上限,用于限制整个 etcd 数据目录(通常为 /var/lib/etcd/member)所能占用的最大磁盘空间。该配额由启动参数 --quota-backend-bytes 控制,默认值为 2 GiB(即 2147483648 字节)。
配额的计算范围包括:
- 键值数据:所有存储的 key-value 对。
- 历史版本:未被压缩的旧版本数据(MVCC 机制)。
- 元数据:索引、事务日志、内部状态等。
- 预写日志(WAL):WAL 文件虽不在后端数据库中,但配额会预留空间给 WAL 增长。
关键指标:当 etcd 后端数据库文件(
member/snap/db)大小接近配额时,系统会提前触发告警。实际生产环境中,建议将配额设置为磁盘容量的 60%-70%,并配合定期压缩(etcdctl compaction)和碎片整理(etcdctl defrag)使用。
3.2 为什么需要配额
配额机制的存在是为了解决以下三个核心问题:
| 问题 | 无配额的后果 | 配额的作用 |
|---|---|---|
| 磁盘写满 | etcd 进程崩溃,无法恢复,集群不可用 | 在磁盘写满前主动拒绝写入,保护进程稳定 |
| 性能退化 | 后端数据库膨胀,查询和写入延迟飙升 | 强制限制数据量,维持可预测的延迟 |
| 集群不一致 | 部分节点磁盘满导致 Raft 日志复制失败 | 统一拒绝写入,保持集群状态一致 |
配额本质上是一种优雅降级策略:与其让 etcd 在磁盘满时突然崩溃,不如在达到阈值时主动拒绝写入,同时保留读取能力,让运维人员有窗口进行扩容或清理。
3.3 配额耗尽后的行为
当 etcd 后端数据库大小达到配额上限时,系统会进入配额耗尽模式,触发以下连锁行为:
- 触发 Alarm(告警):etcd 自动设置
NOSPACE告警,该告警会通过 etcd 的AlarmAPI 广播给所有客户端。 - 拒绝写入请求:所有写操作(Put、Delete、Txn)返回
etcdserver: mvcc: database space exceeded错误。 - 保留读取能力:读操作(Get、Watch)仍然正常服务,保证集群可查询。
- Raft 日志停滞:由于写入被拒绝,Raft 日志无法追加,集群进入只读状态。
注意:配额耗尽后,即使执行
etcdctl compaction 压缩历史版本,数据库文件大小也不会立即缩小。必须先执行 etcdctl defrag 释放空间,然后通过 etcdctl alarm disarm 解除告警,集群才能恢复写入。
3.4 配额相关参数与命令
| 参数/命令 | 说明 | 推荐值/用法 |
|---|---|---|
--quota-backend-bytes |
设置存储配额上限 | 默认 2GiB,生产建议 4-8GiB |
etcdctl alarm list |
查看当前告警状态 | 检查是否有 NOSPACE 告警 |
etcdctl alarm disarm |
解除告警 | 在压缩和整理后执行 |
etcdctl compaction |
压缩历史版本 | 定期执行,保留最近 1-2 小时版本 |
etcdctl defrag |
碎片整理,回收空间 | 压缩后执行,单节点串行操作 |
etcdctl endpoint status |
查看数据库大小 | 监控 dbSize 字段是否接近配额 |
3.5 压测中的配额陷阱
常见压测问题:在压测过程中,如果未提前调整配额或未配置自动压缩,很容易在短时间内触发配额耗尽,导致压测中断。以下为典型场景:
- 默认配额过小:2GiB 在密集写入压测下可能几分钟内耗尽。
- 未启用自动压缩:历史版本持续堆积,加速配额消耗。
- 压测后未整理碎片:即使压缩了,数据库文件大小不变,下次压测仍可能触发告警。
压测前建议执行的操作:
# 1. 调整配额为 8GiB(根据磁盘容量)
etcd --quota-backend-bytes=8589934592
# 2. 启用自动压缩(每 30 分钟压缩一次)
etcd --auto-compaction-retention=30m
# 3. 压测前确认当前配额和数据库大小
etcdctl endpoint status --write-out=table
# 4. 压测结束后执行碎片整理
etcdctl defrag --cluster
避坑提醒:
etcdctl defrag 操作会阻塞该节点的读写,建议在业务低峰期执行,且不要在集群所有节点同时执行。对于多节点集群,应逐个节点串行整理。