etcd 数据空间管理¶
etcd 的数据存储的方式,是直接通过 mmap 一个文件到内存中,然后构建 B+树 的方式。如果有数据删除,相关使用的存储空间也不会释放,可能会在其中留下很多空洞。
压缩 etcd 空间也可以减少 etcd 程序的内存占用量,提高 etcd 性能,在没有问题的时候提前进行压缩也是明智的选择
空间配额¶
在 etcd
中空间配额确保集群以可靠方式运作。没有空间配额, etcd
可能会收到低性能的困扰,如果键空间增长的过度的巨大,或者可能简单的超过存储空间,导致不可预测的集群行为。如果键空间的任何成员的后端数据库超过了空间配额, etcd
发起集群范围的警告,让集群进入维护模式,仅接收键的读取和删除。在键空间释放足够的空间之后,警告可以被解除,而集群将恢复正常运作。
默认,etcd
设置适合大多数应用的保守的空间配额,但是它可以在命令行中设置,单位为字节:
空间配额可以用循环触发:
# 消耗空间
$ while [ 1 ]; do dd if=/dev/urandom bs=1024 count=1024 | etcdctl put key || break; done
...
Error: rpc error: code = 8 desc = etcdserver: mvcc: database space exceeded
# 确认配额空间被超过
$ etcdctl --write-out=table endpoint status
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| 127.0.0.1:2379 | bf9071f4639c75cc | 2.3.0+git | 18 MB | true | 2 | 3332 |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
# 确认警告已发起
$ etcdctl alarm list
memberID:13803658152347727308 alarm:NOSPACE
删除多读的键空间将把集群带回配额限制,因此警告能被接触:
# 获取当前修订版本
$ etcdctl --endpoints=:2379 endpoint status
[{"Endpoint":"127.0.0.1:2379","Status":{"header":{"cluster_id":8925027824743593106,"member_id":13803658152347727308,"revision":1516,"raft_term":2},"version":"2.3.0+git","dbSize":17973248,"leader":13803658152347727308,"raftIndex":6359,"raftTerm":2}}]
# 压缩所有旧有修订版本
$ etdctl compact 1516
compacted revision 1516
# 反碎片化过度空间
$ etcdctl defrag
Finished defragmenting etcd member[127.0.0.1:2379]
# 解除警告
$ etcdctl alarm disarm
memberID:13803658152347727308 alarm:NOSPACE
# 测试put被再度容许
$ etdctl put newkey 123
OK
存储告警¶
如果出现了相关的磁盘报警,也说明磁盘空间不够用了,此时要么调整参数,要么进行碎片整理,一般这种错误为日志中出现 etcdserver: mvcc: database space exceeded
这种日志,同时进行 alarm 查看的时候,有NOSPACE.
数据清理完成后可以清楚告警
- 清除告警信息
碎片数据统计¶
具体的空洞文件的大小,可以根据相关的 metric 计算出来,一旦达到了一定阈值,就可以做一次碎片整理。具体计算方式为:
curl -s http://localhost:2379/metrics |grep -iE "^etcd_mvcc_db_total_size_in_bytes|^etcd_mvcc_db_total_size_in_use_in_bytes"
etcd_mvcc_db_total_size_in_bytes 20480
etcd_mvcc_db_total_size_in_use_in_bytes 16384
- etcd_mvcc_db_total_size_in_bytes: etcd的磁盘存储总共占用的空间
- etcd_mvcc_db_total_size_in_use_in_bytes: 实际用于数据存储占用的空间
- etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_in_bytes: 通过碎片整理可以释放出来的空间
历史压缩¶
因为 etcd 保持它的键空间的确切历史,这个历史应该定期压缩来避免性能下降和最终的存储空间枯竭。压缩键空间历史删除所有关于被废弃的在给定键空间修订版本之前的键的信息。这些key使用的空间随机变得可用来继续写入键空间。
键空间可以使用 etcd
的时间窗口历史保持策略自动压缩,或者使用 etcdctl
手工压缩。 etcdctl
方法在压缩过程上提供细粒度的控制,反之自动压缩适合仅仅需要一定时间长度的键历史的应用。
etcd
可以使用带有小时时间单位的 --auto-compaction
选项来设置为自动压缩键空间:
根据实践发现只配置auto-compaction-retention只会做碎片整理,不会实际减少空间大小; 如果需要减少大小还是需要使用etcdctl compact 和 etcdctl defrag清理空间
etcdctl
如下发起压缩工作:
- 先找到最新的revision
$ rev=$(ETCDCTL_API=3 etcdctl --endpoints=:2379 endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9]*')
- 进行一次压缩,释放掉老的版本
在压缩修订版本之前的修订版本变得无法访问:
$ etcdctl get --rev=2 somekey
Error: rpc error: code = 11 desc = etcdserver: mvcc: required revision has been compacted
反碎片化¶
在压缩键空间之后,后端数据库可能出现内部。内部碎片是指可以被后端使用但是依然消耗存储空间的空间。反碎片化过程释放这个存储空间到文件系统。反碎片化在每个成员上发起,因此集群范围的延迟尖峰(latency spike)可能可以避免。
需要注意的是,在整个碎片整理过程中,整个member将处于不可用状态,因此针对多点部署的etcd,在执行碎片整理的时候,要逐台进行整理,并且在整理过程中保证其他节点能够满足quorum需求。
通过留下间隔在后端数据库,压缩旧有修订版本会内部碎片化 etcd
。碎片化的空间可以被 etcd
使用,但是对于主机文件系统不可用。
为了反碎片化 etcd 成员, 使用 etcdctl defrag
命令:
- 测试是否恢复