K8s离奇崩溃致P0事故!排查一晚竟是etcd数据库碎片化的祸……
事故级别:P0 | 影响范围:全量业务 | 恢复时长:4小时23分钟
一、 灾难降临:凌晨3点的夺命连环Call
2024年12月15日 03:17,正当我沉浸在温暖的被窝里时,手机疯狂震动——监控告警如雪花般飞来:
CRITICAL: K8s API Server响应超时CRITICAL: etcd集群健康检查失败CRITICAL: 所有Pod状态异常CRITICAL: 业务服务全量下线
作为一名有着8年运维经验的老司机,我瞬间意识到——这次玩大了。
二、初步排查:症状比想象中更严重
SSH连接到Master节点,第一时间检查集群状态:
$ kubectl get nodesThe connection to the server localhost:8080 was refused$ kubectl cluster-infoUnable to connect to the server: dial tcp 10.0.1.10:6443: i/o timeout
心凉了半截,API Server彻底无响应。立即检查etcd集群:
$ systemctl status etcd● etcd.service - etcdActive: active (running) but degraded$ etcdctl endpoint health --cluster10.0.1.10:2379 is unhealthy: took too long10.0.1.11:2379 is unhealthy: took too long10.0.1.12:2379 is unhealthy: took too long
所有etcd节点健康检查超时!这绝对不是普通的网络问题。
三、深入诊断:发现惊人真相
$ journalctl -u etcd -n 100Dec 15 03:15:23 etcd[1234]: apply entries took too long [2.357658s] for 1 entriesDec 15 03:15:45 etcd[1234]: database space exceededDec 15 03:16:02 etcd[1234]: mvcc: database space exceeded
关键词出现:database space exceeded!
$ etcdctl endpoint status --write-out=table --cluster+------------------+------------------+---------+---------+-----------+-----------+| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM |+------------------+------------------+---------+---------+-----------+-----------+| 10.0.1.10:2379 | 8e9e05c52164694d | 3.4.13 | 8.2 GB | true | 5 || 10.0.1.11:2379 | 8e9e05c52164694e | 3.4.13 | 8.1 GB | false | 5 || 10.0.1.12:2379 | 8e9e05c52164694f | 3.4.13 | 8.3 GB | false | 5 |+------------------+------------------+---------+---------+-----------+-----------+
震惊发现:etcd数据库已经膨胀到8GB+!正常情况下应该只有几百MB。
$ etcdctl defrag --data-dir=/var/lib/etcdFailed to defrag etcd member: rpc error: database space exceeded$ du -sh /var/lib/etcd/8.4G /var/lib/etcd/
使用专业工具深度分析:
$ etcdctl endpoint hashkv --cluster10.0.1.10:2379, 3841678299 (rev 1847293)10.0.1.11:2379, 3841678299 (rev 1847293)10.0.1.12:2379, 3841678299 (rev 1847293)# 计算碎片率实际数据大小: 156MB数据库文件大小: 8.4GB碎片化率: (8.4GB - 156MB) / 8.4GB = 98.1%
天哪!碎片化率竟然高达98.1%,几乎接近100%!
四、根因分析:历史事件的累积效应
通过日志分析和监控数据回溯,我发现了问题的根本原因:
# 分析etcd操作频率$ grep "PUT /registry/pods" /var/log/etcd.log | wc -l2847293# 过去24小时Pod创建删除次数$ kubectl get events --all-namespaces --field-selector reason=Created | wc -l45623
某个有bug的应用在过去一个月内疯狂重启,产生了284万次Pod状态变更!
$ etcdctl get --prefix --keys-only /registry/ | wc -l1847293# 检查历史版本数量$ etcdctl compaction $(etcdctl endpoint status --write-out="json" | jq '.[0].Status.header.revision - 1000')
etcd中积累了184万个key的历史版本,从未进行过压缩清理。
# /etc/etcd/etcd.conf.yml中的致命配置auto-compaction-retention: "0" # 禁用了自动压缩!quota-backend-bytes: 8589934592 # 8GB限制已触发
五、紧急抢救:分步骤恢复策略
# 临时提升quota限制$ etcdctl put quota-backend-bytes 12884901888 # 提升到12GB# 重启etcd服务$ systemctl restart etcd
# 获取当前revision$ rev=$(etcdctl endpoint status --write-out="json" | jq '.[0].Status.header.revision')$ echo "Current revision: $rev"# 执行压缩(保留最近1000个版本)$ etcdctl compact $((rev-1000))compacted revision 1846293# 等待压缩完成$ watch 'etcdctl endpoint status --write-out=table'
# 依次对每个节点进行碎片整理for endpoint in 10.0.1.10:2379 10.0.1.11:2379 10.0.1.12:2379; doecho "Defragmenting $endpoint..."etcdctl --endpoints=$endpoint defragsleep 60done# 检查整理效果$ etcdctl endpoint status --write-out=table --cluster+------------------+------------------+---------+---------+-----------+-----------+| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM |+------------------+------------------+---------+---------+-----------+-----------+| 10.0.1.10:2379 | 8e9e05c52164694d | 3.4.13 | 178 MB | true | 5 || 10.0.1.11:2379 | 8e9e05c52164694e | 3.4.13 | 181 MB | false | 5 || 10.0.1.12:2379 | 8e9e05c52164694f | 3.4.13 | 175 MB | false | 5 |+------------------+------------------+---------+---------+-----------+-----------+
奇迹出现:数据库大小从8.4GB骤降至180MB左右!
# 验证API Server$ kubectl cluster-infoKubernetes master is running at https://10.0.1.10:6443# 验证节点状态$ kubectl get nodesNAME STATUS ROLES AGE VERSIONk8s-master-1 Ready master 45d v1.19.3k8s-master-2 Ready master 45d v1.19.3k8s-master-3 Ready master 45d v1.19.3k8s-worker-1 Ready <none> 45d v1.19.3# 验证Pod恢复$ kubectl get pods --all-namespaces | grep -v Running | wc -l0
完美!所有服务恢复正常运行。
六、 防患未然:永久解决方案
# 优化后的etcd配置auto-compaction-mode: periodicauto-compaction-retention: "5m" # 每5分钟自动压缩quota-backend-bytes: 8589934592max-request-bytes: 1572864
# Prometheus监控规则groups:- name: etcd-alertsrules:- alert: EtcdDatabaseQuotaLowSpaceexpr: etcd_mvcc_db_total_size_in_bytes / etcd_server_quota_backend_bytes > 0.8for: 5m- alert: EtcdHighFragmentationexpr: (etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_bytes) / etcd_mvcc_db_total_size_in_bytes > 0.5for: 10m
#!/bin/bash# etcd-health-check.sh - 每日健康检查脚本# 检查碎片化率check_fragmentation() {for endpoint in $ETCD_ENDPOINTS; dofrag_rate=$(etcdctl endpoint status --endpoints=$endpoint --write-out=json | jq '.[] | ((.Status.dbSize - .Status.dbSizeInUse) / .Status.dbSize * 100)')if (( $(echo "$frag_rate > 50" | bc -l) )); thenecho "WARNING: $endpoint fragmentation rate: ${frag_rate}%"# 自动执行碎片整理etcdctl defrag --endpoints=$endpointfidone}
七、 经验总结:血泪教训换来的宝贵财富
• 数据库大小:正常<500MB,告警>2GB,紧急>5GB
• 碎片化率:正常<30%,告警>50%,紧急>80%
• 压缩频率:建议每5-10分钟自动压缩一次
• 历史版本数:建议保留1000-5000个版本
预防大于治疗:定期巡检比应急抢救更重要
自动化运维:人工操作容易遗漏,自动化才是王道
监控先行:完善的监控体系是运维的生命线
应急预案:提前准备恢复脚本,关键时刻救命
八、写在最后
这次etcd数据库100%碎片化的紧急恢复经历,让我深刻体会到了运维工作的挑战性和重要性。4小时23分钟的生死时速,不仅考验技术能力,更考验心理素质和应急决策能力。
作为运维人,我们是企业业务的最后一道防线。每一次故障都是成长的机会,每一次恢复都是经验的积累。