上周二下午2点17分,一台承载核心业务的EC2实例突然"假死"——SSH无响应、SSM连不上、ping不通。应用瘫痪,数据库连接池打满,监控告警响了8分钟才被人发现。
团队被迫强制重启。真正的麻烦才开始:一台已经重启过的机器,所有崩溃前的现场证据都被抹掉了。
这个故事的吊诡之处在于:当Grafana仪表盘一片空白、CloudWatch显示"一切正常"时,一套诞生于1985年的Linux工具组合,完整还原了事故全貌。
云厂商说"我没问题",这是最危险的答案
第一反应是甩锅给AWS。合理——硬件故障、虚拟机崩溃、网络分区,云厂商背过的锅还少吗?
工程师拉取了系统状态检查指标。StatusCheckFailed_System(虚拟机监控程序层)和StatusCheckFailed_Instance(操作系统层)在事发前后整整一小时内,读数都是0.0。AWS认为这台实例全程健康。
这个结果比"AWS故障"更棘手——问题出在操作系统内部,但隐蔽到连AWS的基础健康检查都探测不到。
云厂商的"正常"只是缩小了排查范围,不等于真相。很多工程师在这里停步,转而猜测"可能是应用层问题",然后陷入无休止的日志打捞。
EC2串行控制台(Serial Console)相当于服务器的黑匣子。工程师在重启后第一时间抓取输出,却只看到干净的启动序列——缓冲区已被覆盖,没有内核恐慌(Kernel Panic),没有内存耗尽杀手(OOM Killer)的痕迹。
预崩溃证据消失了。这是硬重启的代价:如果能在重启前拿到控制台输出,或许能省下后面三小时的排查。但当时服务器完全不可达,别无选择。
30年前的工具,成了最后的目击者
到这里,典型的云原生工程师已经山穷水尽:Docker日志随重启清空,控制台被覆盖,应用恢复运行,还能查什么?
答案藏在/var/log/sysstat/目录下。sar(System Activity Reporter,系统活动报告器)属于sysstat工具包,默认每10分钟静默采集一次系统指标,写入磁盘。与内存中的指标不同,这些文件 survives 重启。
执行一条命令:
sar -A -f /var/log/sysstat/sa26 -s 14:10:00 -e 14:35:00
输出暴露了全部真相。系统在崩溃前陷入了内存与IO的"死亡螺旋":可用内存从正常水位断崖式下跌,页交换(Page Swap)频率飙升,CPU有70%时间卡在IO等待状态。磁盘读写队列长度在14:23分达到峰值,随后监控数据中断——正是强制重启的时刻。
问题根源指向一个被忽视的配置:某定时任务在14:20分启动,一次性加载了超过物理内存80%的数据集到内存,触发剧烈换页。Linux的内存回收机制(Memory Reclaim)在压力下发疯般扫描页表,CPU被内核态占用,用户态进程(包括SSH守护进程)得不到调度时间片。
从外部看,服务器"死了";从内部看,它还在疯狂运转,只是拒绝一切外部交互。
为什么云监控会集体失明
这场事故暴露了一个认知盲区:现代可观测性栈的设计假设,是"系统还能正常上报指标"。
Grafana依赖的Node Exporter、CloudWatch代理、Datadog Agent,本质都是用户态进程。当内核陷入内存压力风暴,这些代理程序同样被饿死。它们最后上报的可能是"CPU 100%",但真实状态是"内核态100%,用户态0%"——外部看到的"健康"指标,实际是死亡前的回光返照。
AWS的StatusCheckFailed_System检测的是虚拟机能否响应底层心跳,StatusCheckFailed_Instance检测的是实例能否访问网络元数据服务。两者都假设操作系统还能执行基本IO操作。但在这场内存风暴中,内核仍在运转,心跳包仍能发出,只是所有用户态服务已实质停摆。
云监控的盲区,恰恰是传统系统工具的覆盖范围。
sar的设计哲学与云原生时代背道而驰:它不问"应用指标是什么",只记录"内核在做什么"。CPU时间片分配、内存页换入换出、块设备队列深度、进程上下文切换次数——这些底层数据不依赖应用层配合,即使Node Exporter已经饿死,sar的定时采样仍在磁盘上留下足迹。
工程师进一步用dmesg | grep -i "killed process"确认没有OOM介入,用vmstat -s查看历史累积的页换入换出总量,用iostat -x还原磁盘压力曲线。这些工具的共同点是:由内核直接维护统计计数器,不经过用户态中间层。
一个被低估的技能债
事后复盘时,团队意识到一个尴尬事实:负责排查的工程师中,能熟练阅读sar输出的不超过两人。更多人习惯了在Grafana面板上拖拽时间范围,对procfs和sysfs里的原始数据感到陌生。
这不是个体能力问题,是行业趋势。云厂商把基础设施抽象成API和仪表盘,DevOps文化推崇"基础设施即代码",却悄然淡化了对操作系统内核的理解。招聘JD里写满Kubernetes、Prometheus、Terraform,很少出现"精通Linux性能调优"。
但抽象是有泄漏的(Leaky Abstraction)。当云监控集体失效,当容器运行时无法启动,当SSH都连不上时,唯一可靠的调试界面是内核暴露的原始接口。sar、vmstat、iostat、mpstat、pidstat这些工具,本质上是在教你用内核的视角理解系统行为。
这次事故后,团队做了三件事:在所有生产实例启用sar的1分钟粒度采集(默认10分钟太粗)、将sysstat数据纳入定期备份策略、把Linux性能分析加入新工程师的必修清单。
最后一个发现来自/var/log/messages的考古。在崩溃前3分钟,有一条被忽略的警告:kernel: possible SYN flooding on port 443. Sending cookies. 这是连接队列溢出的信号,与内存压力形成叠加效应。应用层的连接风暴加速了内核资源的耗尽,但单独看任何一层都无法解释全貌。
系统故障很少是单点问题,而是多个压力源的共振。云监控擅长展示"发生了什么",但"为什么发生"往往需要穿透抽象层,回到内核现场。
当你们的监控仪表盘下次显示"一切正常"而服务已经不可用时,你们的第一反应会是什么——刷新页面,还是打开终端?
热门跟贴