云主机系统异常分析方法?
- 来源:纵横数据
- 作者:中横科技
- 时间:2026/5/6 15:31:34
- 类别:新闻资讯
做了这么多年运维,我渐渐发现一个很有意思的现象:同样是面对系统异常,老手和新手最大的区别不在于掌握了多少命令,而在于“怎么想”。新手往往看到什么现象就直奔某个方向去了,比如CPU高了就查进程,内存高了就怀疑泄漏。而老手会在脑子里先转几圈,把各种可能性排个序,然后有条不紊地逐个验证。这中间的差别,就是分析方法。
今天我想跟你聊的,不是那些具体的命令和工具,而是面对云主机系统异常时,我们到底应该怎么“分析”。也就是如何在杂乱无章的线索中,找到那个真正的原因。我会结合自己这些年经历过的真实案例,把那些管用的分析思路和框架掰开揉碎了讲给你听。
先建立一个“系统正常”的心智模型
很多人分析异常之所以效率低,是因为他根本不知道“正常”是什么样子的。好比你去朋友家做客,朋友让你帮忙找一下遥控器,但你从来没见过他家的遥控器长什么样,只能满屋子乱翻。放在系统分析上也是一样,如果你不清楚一台云主机在正常情况下CPU多少、内存占用几何、磁盘IO大概什么水平、响应时间的基线是多少,那当异常发生时,你就缺少了一个最重要的参照物。
我养成了一个习惯,每接手一台云主机,头一个星期什么都不做,就是老老实实地观察它的各项指标。用监控系统记录下来一周的CPU使用率曲线,看看高峰期在什么时候,低谷期在什么时候。看看磁盘使用量的增长趋势,是每天涨一点还是基本稳定。看看网络流量的模式,是不是有规律性的突发。这套“正常画像”建立起来之后,当异常出现时,我就能很快地判断出是真异常还是假报警。
有一次,监控突然报警说某台云主机的磁盘使用率从百分之四十跳到了百分之七十。按照一般的思路,肯定是有什么东西在大量写数据。但我看了一眼那台机器正常的画像,发现它每个月月底都会有类似的跳涨,因为业务系统会在月底生成大量的统计报表,报表生成之后会自动归档压缩,磁盘使用率又会降回去。这不是一个需要紧急处理的异常,而是一个可以预期的周期性行为。如果没有那个“正常画像”,我可能就要半夜爬起来折腾一番了。
区分“症状”和“病因”
这是分析系统异常时最容易被忽略的一点,也是最关键的一点。症状是你看到的表面现象,比如CPU高了、响应慢了、报错了。病因是导致这些现象的根本原因。把症状当成病因去治,是最常见的错误。
有一个让我印象深刻的例子。一台云主机的CPU使用率一直保持在百分之九十以上,第一个接手的人认为是进程太多,逐个杀了一些次要进程,CPU降下去了一会儿,但又涨上来了。第二个人认为是CPU核心数不够,升级到了双倍核数,CPU使用率降到了百分之六十,但过了一个星期又回到了百分之九十。最后我接手分析,没有急着去动任何东西,而是先收集了一组数据。top看到有一个java进程占了百分之八十的CPU。再用strace跟踪这个进程的系统调用,发现它在一秒钟内调用了成千上万次futex。进一步分析,这是一个多线程程序,线程之间通过忙等待的方式同步,而不是使用合适的等待机制。说白了,是代码写得有问题,导致CPU在空转。真正的病因是“同步机制设计错误”,而不是“进程太多”或者“核数不够”。修复了代码之后,同样的云主机,CPU使用率降到了百分之二十以下。
怎么才能避免把症状当病因呢?一个实用的技巧是连续追问“为什么”。CPU高了为什么?因为某个进程消耗了大量CPU。这个进程为什么消耗大量CPU?因为它在一个循环里不停地做无意义的计算。为什么会有这个循环?因为开发者用了忙等来代替条件变量。问到第三层、第四层,通常就能触摸到真正的病因了。
对比分析法
对比分析是我个人用起来最顺手的方法之一。当一台云主机出现异常,而另一台正常的云主机做同样的事情,把两台机器放在一起对比,差异往往就是问题的答案。
我有一次遇到一个诡异的问题:两台配置完全一样的云主机,部署了相同的应用代码,也承受着差不多的请求量,但是A机器的响应时间比B机器慢了一倍。监控上看CPU、内存、磁盘、网络都差不多,找不到任何明显差异。我决定做一个对比实验。在两台机器上同时执行同一个API请求,用tcpdump抓包,然后用Wireshark对比分析。结果发现,A机器在处理请求的过程中,多了一次DNS查询,而这次查询每次都要等待三秒钟的超时。进一步检查A机器的/etc/resolv.conf,发现它的DNS服务器配置里有一个不可达的IP地址,每次解析域名时都会先尝试那个地址,超时之后才换到第二个可用的。B机器没有这个问题。把这个无效的DNS服务器从配置里移除之后,A机器的响应时间立刻降到了和B机器一样的水平。
对比分析还可以用于不同时间段的对比。比如今天系统变慢了,你可以拿今天的监控数据和昨天同一时段的监控数据做对比。看看是哪个指标出现了显著的变化。有可能是慢查询的数量突然增加了,有可能是某个接口的调用量翻了好几倍。这种时间维度上的对比,能让你快速定位异常发生的时间点,从而关联当时有没有做什么变更。
还有一次,客户反馈说凌晨两点到三点之间,云主机的磁盘IO非常高。我们拿这个时间段的监控数据和前一天的同一时段做对比,发现并没有什么异常。但是把时间范围扩大到凌晨两点到早上八点,发现IO高峰其实是从凌晨一点开始的,而且逐天提前。最后定位到是某个数据清理任务的cron配置出错,执行时间在漂移。如果没有做这种时间窗口的对比分析,根本发现不了这个规律。
演绎法推理
很多时候,我们手头的线索不足以直接指向结论,这时候就需要用演绎法。简单来说,就是从已知的规律和事实出发,逐步推导出可能性,然后用新的证据来验证或推翻这些可能性。
有一台云主机的网络连接经常性断开,每次持续几分钟后自动恢复。客户怀疑是云平台的问题。我问他有没有规律,他说似乎总是在上午十点左右发生。我脑子里开始演绎:如果是云平台底层网络抖动,那同一宿主机上的其他云主机应该也有类似现象。于是检查了同可用区其他几台云主机的网络监控,发现它们都正常。这个可能性被排除了。如果是云主机被DDoS攻击,那入方向带宽应该会明显升高。但监控显示带宽正常。这个可能性也被排除了。如果是ARP攻击或者IP冲突,那应该会和某个特定的时间点或者事件相关。我让他回忆了一下,每次断网的时候,办公室那边在做什么。他说,好像是财务部门在做银行对账的时候会出问题。突然明白了,财务对账会触发一个脚本,这个脚本会从这台云主机上拉取大量数据,瞬间把带宽占满,然后因为连接数过多触发了云主机的网络限流。问题不在云平台,而在这个脚本没有做流控。调整了脚本的限速参数之后,断网问题再也没有出现过。
演绎法的核心是建立假设,然后用证据去验证。每一条证据要么让某个假设变得更可信,要么直接推翻它。不要手软,一个假设被推翻了是好事,因为它让你离真正的答案更近了。
时间轴分析法
当系统异常已经发生了,而且你还来不及做实时监控的时候,时间轴分析法就非常管用。把异常发生前后的事件按照时间顺序列出来,把所有的变更、告警、日志关键信息都填进去,看看能不能发现因果关系。
我处理过一起非常棘手的数据丢失事件。客户说他们的某个目录下的文件丢了,不确定是被人删了还是程序误操作。我首先检查了该目录所在文件系统的挂载选项和磁盘空间,一切正常。然后我开始构建时间轴。从文件系统的atime和mtime入手,用find命令找出了该目录下最后修改时间在事发前后的所有文件。同时翻阅了系统的历史命令记录、sudo日志、cron日志、应用的访问日志。把这些信息按照时间顺序排列出来之后,发现了一个关键线索:在文件丢失前五分钟,有一个自动部署脚本运行了。这个脚本里有rm -rf命令,虽然它本来应该只清理临时目录,但因为脚本中一个变量在特定条件下变成了空字符串,导致rm -rf执行在了意外的路径上。我找到了这个bug,修复了它,并且从备份里把丢失的文件恢复了。
时间轴分析还有一个妙用,就是判断异常是突发性的还是渐进性的。如果CPU使用率在过去一个小时里突然从百分之二十跳到了百分之九十,这说明有一个突发的事件触发了它,比如某个定时任务开始运行、某个用户执行了复杂查询、或者被攻击了。如果CPU使用率在过去两周里从百分之二十慢慢涨到了百分之九十,那更可能是一个渐进的过程,比如业务量在持续增长,或者存在内存泄漏导致GC越来越频繁。这两种情况的分析方向完全不同。
关联分析法
云主机上的各个子系统不是孤立存在的。CPU、内存、磁盘、网络、应用程序之间有着千丝万缕的关联。关联分析法,就是当一个指标出现异常时,主动去查看其他相关指标有没有同步的变化。
以一个实际案例来说明。一台数据库云主机的响应时间突然从三十毫秒暴涨到了八百毫秒。如果你只盯着数据库的查询日志看,可能会觉得是有慢查询在作祟。但用关联分析的方法,我同时打开了几个监控面板。我注意到,在响应时间暴涨的同时,磁盘的await指标也同步飙升,从两毫秒涨到了一百五十毫秒。但是数据库的QPS和TPS并没有明显变化。这说明问题不在数据库的逻辑层,而在IO层。进一步查看云监控,发现这块云盘在同一时间的IOPS达到了它的规格上限。也就是说,数据库的读写请求量并没有增加,但是每个请求的IO变大了,或者说有其他程序在同时使用这块盘。最终排查出来,是服务器上另一个数据备份进程在这个时间点启动了,它读取了大量历史数据文件,和数据库争抢磁盘IO资源。调整了备份进程的调度时间,避开了业务高峰期,问题解决。
关联分析法的另一个典型应用是定位CPU sys高的原因。sys高意味着内核态CPU占用多,通常是系统调用频繁导致的。这时候你应该去看磁盘IO是不是很大,因为读写文件会触发系统调用。去看网络收发包是不是很多,因为网络收发也会触发系统调用。去看进程的上下文切换次数是不是很高,因为频繁的进程切换也消耗内核时间。我曾经通过关联分析发现,一台云主机CPU sys高的根本原因,是它的控制台日志输出到了一个非常慢的网络存储上,每一行日志都触发了一次昂贵的write系统调用。把日志输出关闭之后,sys CPU从百分之四十降到了百分之二。
分层分析法
云主机的系统栈可以分为多个层次:硬件和虚拟化层、内核层、系统服务层、应用层。分层分析法就是从最底层开始,一层一层向上验证,或者反过来从最顶层开始向下深挖。每一层都有自己的接口和现象,跨层去猜测往往效率很低。
有一次,一个Web服务间歇性的出现连接超时。我们采用自顶向下的分层分析。首先,应用层看日志,发现Tomcat在处理请求时偶尔会卡住十几秒,但没有任何异常栈。再往下,系统服务层看Tomcat的线程状态,用jstack发现大量线程处于BLOCKED状态,在等待一个锁。再往下,内核层用strace跟踪其中一个阻塞的线程,发现它在等待一个文件锁。再往下,文件系统层看锁定的文件是什么,原来是一个共享的配置文件。最后发现,Tomcat应用在每次请求时都会读取这个配置文件,而配置文件所在的目录被NFS挂载,NFS服务器偶尔有高延迟。整个链条是这样的:NFS延迟导致文件读取变慢,文件锁被长时间持有,其他线程排队等待,请求响应超时。最终修复不是改代码,而是把那个配置文件从NFS迁移到了本地磁盘。
自底向上的分层分析也有用武之地。比如云主机无法ping通,你先验证物理网络和虚拟化层。去云控制台看看云主机是否处于运行状态,VPC的网络是否正常。然后验证内核层,通过VNC登录进去,用ip addr看看网卡有没有IP地址,用iptables -L看看有没有拦截ICMP的规则。再验证系统服务层,看看sshd或者ICMP响应相关的服务有没有开。最后验证应用层,虽然ping本身不涉及应用,但如果云主机上装了某些安全软件,它们可能会在应用层拦截ICMP包。一层一层验证,比在某一层上盲目折腾要有效得多。
数据化和量化每一个假设
分析过程中,我们会有各种各样的假设。但这个假设到底对不对,需要用数据来证明,而不是用感觉。养成“先测量,后下结论”的习惯。
我遇到过一位同事,他花了三个小时去调整Nginx的缓存参数,因为他觉得“缓存太小了,所以导致性能差”。但我用ab压测工具做了一组对照实验。在修改缓存参数之前,先测一次QPS和平均延迟。修改参数之后,再测一次。两次结果显示,性能几乎没有变化。这证明了他的假设是错误的。后来我们用perf工具采样,发现瓶颈根本不在缓存,而在upstream连接的后端服务上。如果没有数据,他可能会继续在错误的方向上浪费时间。
再举个例子,有人说“这台云主机负载高,因为云平台太差了”。这种归因没有数据支持。我让他做一个对照实验:同时启动一台同配置的新云主机,什么都不要部署,看看负载是多少。如果新主机负载也高,那可能是云平台的问题。如果新主机负载正常,那问题应该在他的应用或者系统配置上。实验结果是新主机完全正常,结论不言而喻。
一个我经常用的小技巧:在提出任何一个假设时,都问自己一句话,“我有什么数据能证明这个假设是对的?”如果答不上来,那这个假设就不值得花时间去验证,或者你需要先收集相关数据。
把分析过程记录下来
最后一点,也是很多人忽略的一点:把你的分析过程写下来。不是为了别人,是为了你自己。
我每次处理完一个复杂的系统异常,都会花十分钟写一个简短的分析报告。包括异常现象是什么、我做了哪些假设、用了什么方法来验证、最终找到了什么原因、以及修复了什么。这些记录积累起来,就是一个非常宝贵的个人知识库。过了半年或者一年,遇到类似的现象,我直接翻开笔记本,几分钟就能定位到问题,而不用重新走一遍弯路。
有一次,一台云主机出现了和半年前一模一样的症状,网络延迟偶发性升高。我翻出当时的记录,直接定位到是同一类问题——基线路由器的ECMP哈希不均。我甚至连排查的命令都是复制粘贴的,十分钟就确认了根因,然后和网络团队沟通解决了。如果没有那份记录,我可能又要花上半天。
而且,把分析过程写下来,还能帮你在事后发现当初分析中的疏漏。比如写报告的时候,你会重新审视自己的推理链条,可能会发现“当时走了一条弯路,其实看到那个日志就应该直接跳到第三步的”。这种反思,才是真正的成长。
总结
云主机系统异常的分析,在我看来,更像是一门侦探工作。你面对的是一个已经发生过的事件,手里有着零零散散的线索,你需要用自己的逻辑、经验和方法,把它们拼成一副完整的画面。
建立“正常”的心智模型,让你能区分异常和假象。区分症状和病因,让你不会头痛医头、脚痛医脚。对比分析,让你能从差异中找到突破口。演绎法,让你能系统地测试各种可能性。时间轴分析,让你能理清事件发生的先后顺序。关联分析,让你能看到不同指标之间的联系。分层分析,让你能准确定位问题发生在栈的哪一层。数据化假设,让你不会靠感觉做判断。而记录分析过程,则让你每一次的脑力劳动都能沉淀为未来的财富。




使用微信扫一扫
扫一扫关注官方微信 

