etcd数据存储
在实际生产中使用 ETCD 存储元数据,起初集群规模不大的时候元数据信息不多没有发现什么问题。随着集群规模越来越大,可能引发存储问题。
—auto-compaction-retention
由于ETCD数据存储多版本数据,随着写入的主键增加历史版本需要定时清理,默认的历史数据是不会清理的,数据达到2G就不能写入,必须要清理压缩历史数据才能继续写入。根据业务需求,在上生产环境之前就提前确定,历史数据多长时间压缩一次。
#启动命令 /usr/bin/etcd --auto-compaction-retention '1'
快照
etcd的存储分为内存存储和持久化(硬盘)存储两部分,内存中的存储除了顺序化的记录下所有用户对节点数据变更的记录外,还会对用户数据进行索引、建堆等方便查询的操作。而持久化则使用预写式日志(WAL:Write Ahead Log)进行记录存储。
在WAL的体系中,所有的数据在提交之前都会进行日志记录。在etcd的持久化存储目录中,有两个子目录。一个是WAL,存储着所有事务的变化记录;另一个则是snapshot,用于存储某一个时刻etcd所有目录的数据。通过WAL和snapshot相结合的方式,etcd可以有效的进行数据存储和节点故障恢复等操作。
既然有了WAL实时存储了所有的变更,为什么还需要snapshot呢?随着使用量的增加,WAL存储的数据会暴增,为了防止磁盘很快就爆满,etcd默认每10000条记录做一次snapshot,经过snapshot以后的WAL文件就可以删除。而通过API可以查询的历史etcd操作默认为1000条。
etcd压缩整理
默认存储大小限制是 2GB, 可以通过 --quota-backend-bytes
标记配置; 最大支持 8GB
根据实践发现只配置 auto-compaction-retention只会做碎片整理,不会实际减少空间大小;如果需要减少大小还是需要使用etcdctl compact 和 etcdctl defrag清理空间
若果已经设置默认存储大小为8GB, 还存在 Error: rpc error: code = 8 desc = etcdserver: mvcc: database space exceeded 的报错 请按以下操作手动压缩
master节点执行以下操作(每台都要操作):
获取etcdctl工具,若以下方式获取有问题,可以参考: etcdctl获取
查找当前节点的etcd pod,copy出etcdctl工具
kubectl -n kube-system cp etcd-kcs-euler-125-m-4xk6z:/usr/local/bin/etcdctl ./etcdctl
赋予权限
sudo chmod +x etcdctl && mv etcdctl /usr/local/bin/
若是存量双栈v6优先集群,则需要使用--endpoints=https://[::1]:2379
alias ETCDCTL_VV="/usr/local/bin/etcdctl --endpoints=https://localhost:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key"
查看etcd已使用存储空间
ETCDCTL_VV --write-out=table endpoint status --cluster+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://10.20.0.8:2379 | 1ed28cd2451e3407 | 3.5.6 | 5.9 GB | false | false | 10 | 794275440 | 794275440 | |
| https://10.20.0.9:2379 | 553c78b3da279422 | 3.5.6 | 5.9 GB | true | false | 10 | 794275440 | 794275440 | |
| https://10.20.0.7:2379 | d7f8cf57ef93a58c | 3.5.6 | 5.8 GB | false | false | 10 | 794275440 | 794275440 | |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
执行压缩步骤
1、 获取当前版本
ETCDCTL_VV endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*'
rev=$(ETCDCTL_VV endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*')
2、压缩所有旧版本
ETCDCTL_VV compact $rev
历史版本越多,存储空间越大,性能越差,直到etcd到达空间配额限制的时候,etcd的写入将会被禁止变为只读,影响线上服务,因此这些历史版本需要进行压缩。
数据压缩并不是清理现有数据,只是对给定版本之前的历史版本进行清理,清理后数据的历史版本将不能访问,但不会影响现有最新数据的访问。
手动压缩 etcdctl compact 5。 在 5 之前的所有版本都会被压缩,不可访问
3、整理多余的空间 去碎片化(清理磁盘碎片 defrag)
ETCDCTL_VV defrag
4、取消告警信息
ETCDCTL_VV alarm disarm
5、重新查询 etcd 状态可发现 etcd 空间变化
ETCDCTL_VV endpoint status --cluster --write-out=table +------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://localhost:2379 | d9fe35af000dac45 | 3.5.6 | 4.2 MB | false | false | 5 | 3125010 | 3125010 | |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
参数说明 启动参数
--name etcd-1 // 节点名称
--data-dir /Users/noogel/Debug/data/etcd1 // 数据目录
--initial-advertise-peer-urls http://127.0.0.1:238
--listen-peer-urls http://127.0.0.1:2381
--listen-client-urls http://127.0.0.1:2379
--advertise-client-urls http://127.0.0.1:2379
--initial-cluster-token etcd-lock-cluster-1 // 集群 token
--initial-cluster etcd-1=http://127.0.0.1:2381,etcd-2=http://127.0.0.1:2382,etcd-3=http://127.0.0.1:2383 // 集群节点信息
--initial-cluster-state new // 初始化的集群状态
--heartbeat-interval 1000 // 心跳间隔
--auto-compaction-retention 1 // 开启自动压缩,间隔 1h 执行
--auto-compaction-mode periodic
--quota-backend-bytes 8589934592 // 后端存储大小
--election-timeout 5000 // 选举超时时间
关于自动压缩 https://etcd.io/docs/v3.4/op-guide/maintenance/#defragmentation
--auto-compaction-mode=revision --auto-compaction-retention=1000
每5分钟自动压缩”latest revision” - 1000--auto-compaction-mode=periodic --auto-compaction-retention=12h
每1小时自动压缩并保留12小时窗口。
自动压缩碎片后还需要单独再清理占用的系统存储空间,etcdctl defrag
。
最佳实践
heartbeat timeout 默认为 100ms,推荐配置为 1s;
election timeout 默认为 1000ms,推荐为 5s(election timeout >= 5 * heartbeat timeout);
quota-backend-bytes 默认为 2G(最大值8G),推荐根据集群容量预估调整;
配置 auto-compaction-retention=1 和 auto-compaction-mode=periodic 参数,定期压缩历史数据;
推荐通过 cronjob 定期执行 etcdctl defrag(如果 defrag 执行时间 > election timeout,则集群会进入重新选主模式)
定时任务示例
注意:
- 确保每台master上都有etcdctl工具
- 在master节点上(每一台都部署),部署crontab ,在维护时间段,定时压缩etcd
- 定时脚本存放位置可自行调整
#!/usr/bin/env bashecho $(date "+%Y-%m-%d %H:%M:%S")echo -e "\n[1]===压缩前查询 etcd 状态==\n"export ETCDCTL_API=3alias ETCDCTL_VV="/usr/local/bin/etcdctl --endpoints=https://localhost:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key"ETCDCTL_VV --write-out=table endpoint statusecho -e "\n[2]===获取当前版本===\n"ETCDCTL_VV endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*'
rev=$(ETCDCTL_VV endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*')echo -e "\n[3]===压缩所有旧版本===\n"
ETCDCTL_VV compact $revecho -e "\n[4]===整理多余的空间===\n"
ETCDCTL_VV defrag echo -e "\n[5]===取消告警信息===\n"
ETCDCTL_VV alarm disarmecho -e "\n[6]===压缩整理后 etcd 状态可发现 etcd 空间变化===\n"
ETCDCTL_VV --write-out=table endpoint status
定时任务示例
crontab -e 编写
crontab -l 查看
每周日凌晨1点(示例),建议3个master定时任务间隔一些时间,比如5-10min
0 1 * * 0 sh /opt/cron/etcd_comtact_cron.sh > /opt/cron/etcd_comtact_cron.out 2>&1
每小时(示例)
0 * * * * sh /opt/cron/etcd_comtact_cron.sh > /opt/cron/etcd_comtact_cron.out 2>&1