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 后端数据库大小达到配额上限时,系统会进入配额耗尽模式,触发以下连锁行为:

  1. 触发 Alarm(告警):etcd 自动设置 NOSPACE 告警,该告警会通过 etcd 的 Alarm API 广播给所有客户端。
  2. 拒绝写入请求:所有写操作(Put、Delete、Txn)返回 etcdserver: mvcc: database space exceeded 错误。
  3. 保留读取能力:读操作(Get、Watch)仍然正常服务,保证集群可查询。
  4. Raft 日志停滞:由于写入被拒绝,Raft 日志无法追加,集群进入只读状态。
注意:配额耗尽后,即使执行 etcdctl compaction 压缩历史版本,数据库文件大小也不会立即缩小。必须先执行 etcdctl defrag 释放空间,然后通过 etcdctl alarm disarm 解除告警,集群才能恢复写入。
配额耗尽状态机 正常写入 配额未满 告警触发 NOSPACE Alarm 拒绝写入 只读模式 达到配额 自动触发 压缩 + 整理 compact + defrag 解除告警 alarm disarm 恢复写入 正常模式 运维介入 空间释放 告警清除 恢复路径说明: 1. 执行 etcdctl compaction 压缩历史版本 → 2. 执行 etcdctl defrag 回收磁盘空间 → 3. 执行 etcdctl alarm disarm 解除告警 → 4. 集群自动恢复写入

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 操作会阻塞该节点的读写,建议在业务低峰期执行,且不要在集群所有节点同时执行。对于多节点集群,应逐个节点串行整理。