K8s离奇崩溃致P0事故!排查一晚竟是etcd数据库碎片化的祸……

马哥Linux运维 2025-11-25 09:44:21
事故级别:P0 | 影响范围:全量业务 | 恢复时长:4小时23分钟

 

一、 灾难降临:凌晨3点的夺命连环Call

 

2024年12月15日 03:17,正当我沉浸在温暖的被窝里时,手机疯狂震动——监控告警如雪花般飞来:

 

CRITICAL: K8s API Server响应超时
CRITICAL: etcd集群健康检查失败  
CRITICAL: 所有Pod状态异常
CRITICAL: 业务服务全量下线

 

作为一名有着8年运维经验的老司机,我瞬间意识到——这次玩大了。

 

二、初步排查:症状比想象中更严重

 

SSH连接到Master节点,第一时间检查集群状态:

 

$ kubectl get nodes
The connection to the server localhost:8080 was refused
$ kubectl cluster-info
Unable to connect to the server: dial tcp 10.0.1.10:6443: i/o timeout

 

心凉了半截,API Server彻底无响应。立即检查etcd集群:

 

$ systemctl status etcd
● etcd.service - etcd
   Active: active (running) but degraded
   
$ etcdctl endpoint health --cluster
10.0.1.10:2379 is unhealthy: took too long
10.0.1.11:2379 is unhealthy: took too long  
10.0.1.12:2379 is unhealthy: took too long

 

所有etcd节点健康检查超时!这绝对不是普通的网络问题。

 

三、深入诊断:发现惊人真相

 

第一步:检查etcd日志

 

$ journalctl -u etcd -n 100
Dec 15 03:15:23 etcd[1234]: apply entries took too long [2.357658s] for 1 entries
Dec 15 03:15:45 etcd[1234]: database space exceeded
Dec 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/etcd
Failed to defrag etcd member: rpc error: database space exceeded
$ du -sh /var/lib/etcd/
8.4G    /var/lib/etcd/

 

使用专业工具深度分析:

 

$ etcdctl endpoint hashkv --cluster
10.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%!

 

四、根因分析:历史事件的累积效应

 

通过日志分析和监控数据回溯,我发现了问题的根本原因:

 

1、 频繁的Pod重启风暴

 

# 分析etcd操作频率
$ grep "PUT /registry/pods" /var/log/etcd.log | wc -l
2847293
# 过去24小时Pod创建删除次数
$ kubectl get events --all-namespaces --field-selector reason=Created | wc -l
45623

 

某个有bug的应用在过去一个月内疯狂重启,产生了284万次Pod状态变更!

 

2、历史版本堆积

 

$ etcdctl get --prefix --keys-only /registry/ | wc -l
1847293
# 检查历史版本数量
$ etcdctl compaction $(etcdctl endpoint status --write-out="json" | jq '.[0].Status.header.revision - 1000')

 

etcd中积累了184万个key的历史版本,从未进行过压缩清理。

 

3、配置不当

 

# /etc/etcd/etcd.conf.yml中的致命配置
auto-compaction-retention: "0"    # 禁用了自动压缩!
quota-backend-bytes: 8589934592   # 8GB限制已触发

 

五、紧急抢救:分步骤恢复策略

 

阶段一:紧急扩容存储空间(15分钟)

 

# 临时提升quota限制
$ etcdctl put quota-backend-bytes 12884901888  # 提升到12GB
# 重启etcd服务
$ systemctl restart etcd

 

阶段二:手动压缩历史数据(45分钟)

 

# 获取当前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'

 

阶段三:数据库碎片整理(180分钟)

 

# 依次对每个节点进行碎片整理
for endpoint in 10.0.1.10:2379 10.0.1.11:2379 10.0.1.12:2379; do
    echo "Defragmenting $endpoint..."
    etcdctl --endpoints=$endpoint defrag
    sleep 60
done
# 检查整理效果
$ 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左右!

 

阶段四:服务恢复验证(23分钟)

 

# 验证API Server
$ kubectl cluster-info
Kubernetes master is running at https://10.0.1.10:6443
# 验证节点状态
$ kubectl get nodes
NAME           STATUS   ROLES    AGE   VERSION
k8s-master-1   Ready    master   45d   v1.19.3
k8s-master-2   Ready    master   45d   v1.19.3
k8s-master-3   Ready    master   45d   v1.19.3
k8s-worker-1   Ready    <none>   45d   v1.19.3
# 验证Pod恢复
$ kubectl get pods --all-namespaces | grep -v Running | wc -l
0

 

完美!所有服务恢复正常运行。

 

六、 防患未然:永久解决方案

 

1、自动化压缩配置

 

# 优化后的etcd配置
auto-compaction-mode: periodic
auto-compaction-retention: "5m"    # 每5分钟自动压缩
quota-backend-bytes: 8589934592
max-request-bytes: 1572864

 

2、监控告警升级

 

# Prometheus监控规则
groups:
- name: etcd-alerts
  rules:
  - alert: EtcdDatabaseQuotaLowSpace
    expr: etcd_mvcc_db_total_size_in_bytes / etcd_server_quota_backend_bytes > 0.8
    for: 5m
    
  - alert: EtcdHighFragmentation  
    expr: (etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_bytes) / etcd_mvcc_db_total_size_in_bytes > 0.5
    for: 10m

 

3、自动化运维脚本

 

#!/bin/bash
# etcd-health-check.sh - 每日健康检查脚本
# 检查碎片化率
check_fragmentation() {
    for endpoint in $ETCD_ENDPOINTS; do
        frag_rate=$(etcdctl endpoint status --endpoints=$endpoint --write-out=json | jq '.[] | ((.Status.dbSize - .Status.dbSizeInUse) / .Status.dbSize * 100)')
        if (( $(echo "$frag_rate > 50" | bc -l) )); then
            echo "WARNING: $endpoint fragmentation rate: ${frag_rate}%"
            # 自动执行碎片整理
            etcdctl defrag --endpoints=$endpoint
        fi
    done
}

 

七、 经验总结:血泪教训换来的宝贵财富

 

1、关键指标监控清单

 

• 数据库大小:正常<500MB,告警>2GB,紧急>5GB

 

• 碎片化率:正常<30%,告警>50%,紧急>80%

 

• 压缩频率:建议每5-10分钟自动压缩一次

 

• 历史版本数:建议保留1000-5000个版本

 

2、最佳实践总结

 

  • 预防大于治疗:定期巡检比应急抢救更重要
  •  
  • 自动化运维:人工操作容易遗漏,自动化才是王道
  •  
  • 监控先行:完善的监控体系是运维的生命线
  •  
  • 应急预案:提前准备恢复脚本,关键时刻救命

 

八、写在最后

 

这次etcd数据库100%碎片化的紧急恢复经历,让我深刻体会到了运维工作的挑战性和重要性。4小时23分钟的生死时速,不仅考验技术能力,更考验心理素质和应急决策能力。

 

作为运维人,我们是企业业务的最后一道防线。每一次故障都是成长的机会,每一次恢复都是经验的积累。

 

作者丨马哥Linux运维

来源丨公众号:马哥Linux运维(ID:magedu-Linux)

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

 

最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告