ETCD 出现高碎片率事件解析

集群频繁触发 etcdDatabaseHighFragmentationRatio 告警,PrometheusRule 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- alert: etcdDatabaseHighFragmentationRatio
annotations:
description: 'etcd cluster "{{ $labels.job }}": database size in use on instance
{{ $labels.instance }} is {{ $value | humanizePercentage }} of the actual
allocated disk space, please run defragmentation (e.g. etcdctl defrag) to
retrieve the unused fragmented disk space.'
runbook_url: https://etcd.io/docs/v3.5/op-guide/maintenance/#defragmentation
summary: etcd database size in use is less than 50% of the actual allocated
storage.
expr: (last_over_time(etcd_mvcc_db_total_size_in_use_in_bytes{job=~".*etcd.*"}[5m])
/ last_over_time(etcd_mvcc_db_total_size_in_bytes{job=~".*etcd.*"}[5m])) <
0.5 and etcd_mvcc_db_total_size_in_use_in_bytes{job=~".*etcd.*"} > 104857600
for: 10m
labels:
severity: warning

相关指标说明

该告警主要涉及以下指标:

  1. etcd_server_quota_backend_bytes:当前后端存储配额大小,单位为字节,默认为 2 GB。
  2. etcd_mvcc_db_total_size_in_bytes:底层数据库实际分配的总大小,包含数据和碎片空间,即 DB SIZE
  3. etcd_mvcc_db_total_size_in_use_in_bytes:底层数据库中逻辑上正在使用的空间大小,不包含碎片空间,即 IN USE

需要注意的是,配置 quota-backend-bytes 后,etcd_mvcc_db_total_size_in_bytes 的大小并不会直接根据该值变化。变化的是 etcd_server_quota_backend_bytes 指标。


为什么会产生碎片

etcd 产生碎片的主要原因如下:

  1. etcd 支持多版本并发控制(MVCC),会记录 keyspace 的历史版本。
  2. 压缩操作是清理历史版本的主要方式,通常可以通过 --auto-compaction-mode--auto-compaction-retention 实现自动压缩。
  3. 压缩操作只会清理历史版本,但清理后的空闲空间并不会立即从文件系统中释放,而是被 etcd 标记为可复用的空闲空间。因此,压缩后 DB 文件仍然会占用磁盘空间。
  4. 如果需要真正释放这部分空闲空间,需要执行碎片整理,也就是 etcdctl defrag
1
etcdctl defrag

是否需要执行碎片整理

针对 etcdDatabaseHighFragmentationRatio 告警,可以参考以下方式判断是否需要进行碎片整理:

  1. 通过 etcd_server_quota_backend_bytes 指标查看当前 etcd Backend DB 的实际配额。
  2. 通过 etcd_mvcc_db_total_size_in_bytes 指标,或通过命令检查 DB SIZE 是否确实较大,并且是否接近 quota-backend-bytes。如果 DB SIZE 并不大,且距离配额仍有较大空间,则通常无需担心。
  3. 如果 DB SIZE 已经较大并接近 quota-backend-bytes,可以进一步统计各类资源数量,确认是否存在大量资源导致 DB SIZE 增长。随后可以通过碎片整理尝试释放空间。如果碎片整理后仍然接近 quota-backend-bytes,则需要考虑增加配额。

统计资源数量:

1
etcdctl get /registry --prefix --keys-only | grep -v ^$ | awk -F '/' '{ h[$3]++ } END {for (k in h) print h[k], k}' | sort -nr

执行碎片整理:

1
etcdctl defrag

通过 etcdctl 查看 DB SIZE 和碎片率

除了 Prometheus 指标,也可以通过 etcdctl endpoint status 获取对应信息:

1
2
3
4
# DB SIZE:etcd Backend DB 文件的实际磁盘大小,包含尚未回收的碎片空间
# IN USE:当前实际使用的数据大小
# PERCENTAGE NOT IN USE:未使用空间占 DB SIZE 的比例,即碎片率
etcdctl endpoint status -w table

示例输出:

1
2
3
4
5
6
7
+----------------------------+------------------+---------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
| ENDPOINT | ID | VERSION | STORAGE VERSION | DB SIZE | IN USE | PERCENTAGE NOT IN USE | QUOTA | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | DOWNGRADE TARGET VERSION | DOWNGRADE ENABLED |
+----------------------------+------------------+---------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
| https://172.16.16.120:2379 | 8af47ddd59a4380d | 3.6.7 | 3.6.0 | 38 MB | 37 MB | 2% | 2.1 GB | false | false | 41 | 223679135 | 223679135 | | | false |
| https://172.16.16.121:2379 | 5c60194b69e150d6 | 3.6.7 | 3.6.0 | 38 MB | 37 MB | 2% | 2.1 GB | true | false | 41 | 223679135 | 223679135 | | | false |
| https://172.16.16.122:2379 | c5794547c5d8917b | 3.6.7 | 3.6.0 | 38 MB | 37 MB | 2% | 2.1 GB | false | false | 41 | 223679135 | 223679135 | | | false |
+----------------------------+------------------+---------+-----------------+---------+--------+-----------------------+--------+-----------+------------+-----------+------------+--------------------+--------+--------------------------+-------------------+
Author

Warner Chen

Posted on

2024-09-14

Updated on

2026-06-24

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.
You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.