干运维这些年,最常被问的一个问题是:同样是看告警、排故障,为什么有人半小时定位问题,有人折腾一宿还找不着北?我一直觉得,差别不在经验多少,而在脑子里有没有一套清晰的运维故障排查思路。今天想聊的,就是这套思路里最核心的两条原则:先定位后解决,先硬件后软件。
这两句话看着朴素,但实操中绝大多数翻车现场,根子上都是把顺序搞反了。要么上来就猜“是不是配置改坏了”,然后一头扎进配置里翻半天;要么不管三七二十一先把服务重启一遍,看着恢复了就收工,结果第二天凌晨又被同样的告警叫醒。故障排查不是玄学,它是有方法论、有优先级、有固定动作的。把这个顺序捋顺了,你会发现很多告警根本不需要“救火式”处理,几分钟就能锁定根因。
这篇内容是写给谁的呢?主要是运维工程师、SRE、后端开发里需要自己顶上排查问题的人,也适合刚入行、面对告警不知道从哪下手的萌新。同时,如果你只是在家修自己的电脑、服务器,这套思路同样管用。因为“先定位后解决,先硬件后软件”本质上是一套通用的排查框架,设备可以换,系统可以换,框架不用换。
1. 先搞清楚一件事:绝大多数排查失误,都坏在“想当然”
1.1 为什么“先定位后解决”能救命
先说个场景。某天线上报了一个告警,某个服务接口超时率飙升。新手的第一反应往往是赶紧打开服务端日志,看看是不是代码抛异常了。运气好,日志里确实有报错,于是顺着报错往上追,折腾两小时后发现——报错来自下游数据库,数据库本身因为磁盘满了正在只读。这就是典型的定位缺失。
如果先做定位,你要回答的是几个更基础的问题:这个故障影响了谁?是所有请求都超时,还是只有一部分?是从哪个时间点开始的?在故障发生前后有没有发布、变更、扩容?有没有规律性,比如每小时的某个整点就抖一下?这些问题不需要任何深入分析,只需要看监控、翻告警、问同事,往往几分钟就有答案。但它们能直接决定你下一步该往哪个方向走。
我见过太多排查事故,问题其实不大,但处理的人没有先定位,上来就“基于经验”动手:觉得是缓存穿透,就把缓存调大;觉得是GC太频繁,就改了一堆JVM参数。一顿操作猛如虎之后发现,现象还在。等到实在没辙了才去看监控大盘,才发现是上游某个流量入口的负载均衡器在重启。绕了一大圈,原理很简单:没有定位就直接解决,本质上是拿猜测代替证据。
定位的意义在于把“一个模糊的故障陈述”翻译成“一组明确的问题边界”。只有边界清晰了,解决方案才能精准。否则你所有的排查动作都是在“打地鼠”,按下一个,起来一个。
1.2 “先硬件后软件”的顺序,不是教条,而是性价比最高的一条路
“先硬件后软件”这条原则,很多新手理解成了“把所有硬件都检查一遍再碰软件”。这不是本意,至少不是字面上的顺序。它的核心意思是:在排查过程中,优先排除掉那些位于底层、一旦出问题会让所有上层现象都变得“不可信”的变量。
打个比方。你家里灯不亮了,你大概率不会先拆开开关研究电路设计,也不会上来就怀疑灯泡品牌有问题。你会先看是不是跳闸了,再看灯泡是不是烧了,最后才考虑开关和线路。为什么?因为越底层的变量,越容易出问题,也越容易被上层故障的表象掩盖。硬件就是这么个存在。内存坏了,业务进程会段错误,看起来像代码bug;网卡丢了,服务端口全连不上,看起来像防火墙策略错了;磁盘IO抖动,数据库查询慢得像蜗牛,看起来像慢SQL变多。你说,如果不先把硬件嫌疑排除,你在软件层分析半天,分析得再漂亮,不还是被表象带着跑吗?
更重要的是,现在服务器的硬件层排查成本极低。带外管理、事件日志、SMART信息,一条命令就能拉出来。花两分钟确认硬件没有异常,再进入软件排查,总比在软件层瞎转两小时、最后发现是内存故障香得多。这不是死板的流程,而是基于成本收益比做出的最优选择。
2. 先定位后解决:把故障钉死在最小范围内
2.1 定位的四个维度:时间、范围、变更、复现条件
我把定位这件事拆成四个维度,做排查时按顺序过一遍,基本能锚定问题。这四件事与具体技术栈无关,什么系统都适用。
第一个维度是时间。故障是什么时候开始出现的?是持续性的还是间歇性的?如果是间歇性,有没有固定周期?时间维度最大的价值,是让你能把故障和某些动作关联起来。比如故障发生在凌晨两点,而两点刚好有定时任务在跑,那就是很高的嫌疑线索。再比如故障从某次重启之后开始,那新内核、驱动加载顺序、服务自启项都是重点方向。
第二个维度是范围。到底哪些用户、哪些接口、哪些节点受到了影响?是所有地域的请求都失败,还是只有某个机房?是所有实例都异常,还是单台?范围能帮你快速判断故障的“传播路径”。比如全部实例同时异常,多半是依赖的下游公共组件出问题了;单台实例异常,那就要重点看这台机器的系统状态。
第三个维度是变更。故障时间点前后,有没有做过发布、配置修改、扩容缩容、硬件变更?我见过不少排查两小时没结论的案例,最后发现是最早的时候网络设备升级,回切没回干净。变更对故障排查而言,是最有指向性的信号。很多公司把“先检查变更”定为铁律,不是没有道理的。
第四个维度是复现条件。这个问题能不能稳定复现?复现需要什么操作?如果能稳定复现,那排查难度会直线下降——你可以在测试环境操作一次,对比一下正常和异常的过程,差异点往往就是问题所在。如果不能复现,那就需要靠监控、日志和现场信息来做推断,难度会大得多,但也更能体现定位功夫。
这四个维度过完,你手里应该有一张相对完整的“故障画像”了。后续不管你查硬件还是查软件,都是在这张画像的指引下进行,而不是大海捞针。
2.2 收集证据的三个层次:现象、日志、指标
定位不是拍脑袋,它靠的是证据。证据也是有层级的,从低到高分别是:现象、日志、指标。
现象是最原始的证据,比如“页面打不开”“接口报超时”“机器响蜂鸣器”。现象是所有人第一眼看到的,但它也是最容易误导人的。超时可能是网络延迟,可能是线程池耗尽,也可能是GC停顿,现象背后对应的原因太多了。所以现象只能作为出发点,不能作为结论依据。
日志是系统的“留痕”。应用日志、系统日志、硬件日志,每一类日志都在讲述不同层面发生的事,这就是我说“运维故障排查思路”里最基础的一环——让系统替你把故事讲完整。查日志有两条经验:第一,先看时间戳对齐,把所有相关日志按时序排列,你会发现很多看似无关的记录其实是因果链;第二,别只盯着ERROR级别,WARNING、INFO、DEBUG里的上下文信息往往更重要,因为报错只能告诉你“哪里坏了”,上下文才能告诉你“为什么坏”。
指标是量化证据,来自监控系统。CPU、内存、磁盘IO、网络流量、GC耗时、线程数、连接池用量,这些指标能客观反映系统的负载状态和变化趋势。当你说“系统很卡”的时候,如果CPU只有5%,那你所谓的“卡”就值得重新定义了——到底是哪一层卡?指标的作用,是把模糊的主观感受变成可比对的数据。
我的习惯是:现象记录到手,日志按时间线拉出来,指标对着时间线回放。三者能对上,定位就完成了一大半。
2.3 用排除法缩小边界,而不是直接猜原因
定位到一定阶段后,剩下的问题往往就是二选一:A组件有问题还是B组件有问题。这时候最忌讳的是在两个方向之间反复横跳,一会儿查A,一会儿查B。应该做的是设计一套“可证伪”的测试,每次只排除一个变量,快速逼近根因。
比如一套前后端分离的系统,接口报错。是前端的问题还是后端的问题?最简单的做法就是直接请求后端接口,绕过前端。如果后端接口正常,那问题大概率落在前端代码或前后端交互上;如果后端接口也报同样的错,那问题就锁定在后端范围内了。这就是一个很典型的分流测试。
再比如翻数据库慢日志,发现一条SQL很慢。是不是这条SQL的问题?先把它单独拿出来跑一遍,加上索引再跑一遍,对比执行计划。如果加了索引就快了,说明优化SQL是对的;如果加了索引依然慢,那可能是表数据量膨胀、硬件IO能力不足,或者数据库配置有问题。一次实验只验证一个变量,才能得到可信的结论。
这种排除法的好处是,你的每一步行动都有明确的逻辑支撑,排查过程是可回溯的。哪怕最后没找到根因,别人也能沿着你的排查路径继续往前走,而不是从头再来。
3. 先硬件后软件:四层检查法按顺序走
3.1 第一层:供电与物理链路
我自己排查故障有个习惯,不管问题多“像”软件问题,都先花几十秒过一遍“物理层”。因为物理层出问题的概率不低,但被忽略的概率极高。
先说供电。服务器突然重启、业务进程突然消失、存储设备报写入失败,这些场景里,供电不稳是很常见的“隐形杀手”。如果是机房托管,常见的是PDU(电源分配单元)插口松动、双路电源只接了一路,或者那一路上游跳闸了。如果是自己家里的NAS或工作站,那就是插线板老化、电源适配器功率不够。排查时别嫌麻烦,看一眼电源指示灯、听一下风扇声音、用万用表量一下供电电压,都比在系统里翻日志更快。
再说物理链路。网线松了、光纤插头脏了、模块松动,都会让网络看起来“时通时断”。特别是那种ping一下通,过几秒又不通的现象,软件排查再久也没用,因为问题不在系统,在链路。我习惯先用设备管理口去看网卡状态,看link是否反复up/down,如果真是这样,就直接让人去机房换线、重新插拔光模块。
很多人觉得这些都是“最基础的东西”,不屑于查。但故障排查恰恰是“先易后难”的活,物理层检查成本极低、收益极高,查一下不亏。
3.2 第二层:硬件健康状态
物理链路确认没问题之后,下一步就是确认硬件本身到底健不健康。这里的数据来源很丰富,而且绝大多数不需要重启系统就能拿得到。
在服务器场景,BMC/IPMI是最重要的信息来源。通过带外管理口,你可以直接查硬件事件日志。命令大概是这样的:
ipmitool sel list ipmitool sel elist ipmitool sensor listsel list里如果出现Memory、ECC、Fault、Critical之类的关键字,那这台机器的硬件基本就有嫌疑了。更具体的还有:
dmesg | grep -i -E "edac|mce|memory|hardware|error" dmesg -T | grep -i -E "error|fail|critical" | tail -50dmesg是内核级日志,硬件层面的错误往往会在里面留下痕迹。比如内存有不可纠正错误(Uncorrected Error),dmesg(或者mcelog)里会记录得很清楚。磁盘健康度则用SMART信息来看:
smartctl -a /dev/sda重点关注Reallocated_Sector_Ct、Current_Pending_Sector、Offline_Uncorrectable这三项,只要有一项数值异常偏高,这块盘就不能再继续承担生产负载了。还有很多商用服务器自带检测工具,比如戴尔的racadm、惠普的ssacli、联想的storcli,都可以查阵列卡和物理盘状态。
3.3 第三层:固件与驱动
硬件本身没坏,不代表硬件就“没问题”。固件版本或者驱动不兼容,同样会制造出一堆看似无解的故障。这一层最经典的现象就是:系统负载很低,但IO性能上不去;网卡无故丢包;GPU计算任务间歇性失败。
排查这一层需要做两件事。第一件事是核对固件版本和已知问题清单。比如某款网卡固件在特定内核版本的驱动下会发生死锁,某款SSD固件在持续高负载下会掉盘,这些信息厂商通常会在发布说明里写明。你只要把当前版本拿出来一对照,就能判断是不是踩了已知的坑。第二件事是看看驱动日志里有没有异常。
ethtool -i eth0 dmesg | grep -i -E "driver|firmware|ixgbe|mlx|link"第三层往往是最容易被忽略的一层。因为它既不像纯硬件故障那么明显,也不像纯软件问题那么“可控”。但正因如此,一旦遇到,排查起来特别耗时。如果硬件和软件都查完了还没结论,记得回来看看固件和驱动版本,说不定真相就在那里。
3.4 第四层:操作系统与业务软件
过完了前面三层,才轮到大多数人第一反应就想查的“软件层”。这一层面的排查方法大家都很熟,无非是看系统资源、看进程状态、看日志、看配置。真正想提醒的是两件事。
第一件事,别在软件层浪费太多时间,一定要确认“软件层的异常是根因还是结果”。比如服务进程挂掉了,这确实是个软件事件,但如果你只看进程为什么挂,很可能会忽略真正的原因——内存坏了、磁盘满了、系统被OOM Killer干掉。很多人排查故障,止步于“服务挂了,重启完事”,从没问过一句“它为什么挂”。这就是典型的把“结果”当“根因”。
第二件事,软件层的日志要按“排查思路”去读,而不是漫无目的地翻。如果是业务服务异常,先看应用日志,再看系统级日志journalctl或/var/log/messages,然后对照监控指标和硬件日志。如果业务日志里报的是连接失败,而系统日志里网卡状态一直正常,那就要往网络策略或者对端服务上去查了。
这四层检查法,本质上是一个“从底层往上层走”的过程。底层先排除,上层问题才会浮现出来。用一张表总结一下:
| 层级 | 检查内容 | 常用工具/命令 | 典型异常信号 |
|---|---|---|---|
| 物理层 | 供电、网线、光纤、接口 | 万用表、设备指示灯、ethool | 网卡link反复up/down、设备突然断电 |
| 硬件层 | CPU、内存、磁盘、阵列卡 | ipmitool、dmesg、smartctl | 内存ECC事件、磁盘SMART异常、传感器告警 |
| 固件/驱动层 | 固件版本、驱动兼容性 | ethtool -i、厂商发布说明 | 驱动死锁、IO性能不达标、异常丢包 |
| 系统/软件层 | 服务状态、日志、配置、代码 | journalctl、应用日志、监控系统 | 进程崩溃、端口无响应、业务超时 |
4. 实操实录:一次数据库服务器“假死”的完整排查
光讲方法论有点干,我拿一个真实的排障经历来说说这套思路长什么样。整个过程不算复杂,但很能说明“先定位后解决,先硬件后软件”这两条原则到底是怎么落地执行的。
4.1 现象确认与信息收集
那天凌晨收到告警,一个核心数据库实例的连接数飙升,端口探测失败。从监控大盘看,实例的CPU、内存、磁盘IO在短时间内都出现了严重飙升,随后业务侧开始报大量“无法获取数据库连接”的错误。
我按定位四维来过了一遍:时间上,故障发生前没有发布和变更窗口;范围上,所有连接这个库的应用都受影响,而不只是某一个服务;复现条件上,是持续故障,不是偶发抖动;变更上,数据库侧和业务侧都没有操作记录。这几个信息综合下来,基本可以把“业务代码变更”从嫌疑名单里划掉了,重点还是落在数据库实例自身身上。
这时候有个坑:CPU和内存都飙升,网络又连不上,很多人会下意识觉得是数据库参数不够、连接池被打满了,或者有慢SQL在拖垮实例。但我没有急着去看数据库配置和慢查询日志,而是决定先把硬件层排除掉。
4.2 硬件层排查
我先通过带外管理口连上这台服务器的BMC,用IPMI查系统事件日志。命令很简短:
ipmitool sel list | tail -30日志里出现了好几条内存相关的记录,其中有两条是关键事件:
3 | 03/05/2024 | 02:13:45 | Memory #0x05 | Correctable ECC | Asserted 4 | 03/05/2024 | 02:13:47 | Memory #0x06 | Uncorrectable ECC | Asserted看到Uncorrectable ECC的时候,我心里基本有数了。可纠正的ECC错误量多,说明内存在持续报错;不可纠正的ECC错误出现,说明已经有数据无法被硬件纠正,系统很容易出现随机性的进程崩溃或内核 panic。这个时间点(02:13)也正好和业务侧感知到故障的时间对上了。
为了进一步确认,我又看了系统日志:
dmesg -T | grep -i -E "error|mce|memory" | tail -50里面同样出现了Kernel panic - not syncing: Machine Check之类的信息,指向硬件级机制触发的系统异常。排查到这里,硬件层的证据已经非常充分了,嫌疑基本锁定在物理内存条上。
4.3 软件层确认,让“受害者”说话
按照原则,硬件证据充分后,软件层还是要做一遍“确认性排查”——不是为了翻天覆地,而是要确保没有第二个根因叠加在里面。我主要看了系统日志里进程的记录,确认是不是数据库进程被系统杀掉,还是整个内核直接panic。这两者性质完全不同。
从日志看,系统在中途发生过内核panic,随后自动重启。重启后数据库服务尝试恢复,但因为内存错误仍在持续,进程反复崩溃,导致端口一直无法正常监听。应用侧看到的表现就是“连接失败”和“CPU飙升”——CPU飙升很可能是内存错误导致的反复重试和系统软中断异常。到这里,软件层的异常都能被硬件层的根因解释通,没有第二个独立问题。
4.4 修复与复盘
定位到根因之后,解决反而是最不费力的一步。联系机房同事,现场指出出问题的内存槽位,更换内存条,重新开机校验:
ipmitool sel clear ipmitool sensor list | grep -i -E "mem|temp"硬件报警消除后,数据库服务正常拉起,业务流量恢复。整个过程里,真正耗时间的不是“解决”,而是“定位”那一步——确认范围、排除干扰、锁定硬件、验证软件是否无辜。
复盘这次故障,有两点印象很深。第一,如果我当时不查硬件,直接按“数据库连接池被打满”去调参数,可能折腾到天亮都解决不了问题,因为根因根本不在那。第二,硬件日志的证据价值极高,一条Uncorrectable ECC基本就是破案的关键证据,比软件层任何日志都简洁有力。这也再次验证了“先硬件后软件”的含金量。
5. 常见问题与排查技巧实录
5.1 几个容易误判的典型场景
日常答疑里,有些“故障”反复出现在不同人身上,我干脆整理成一段。
第一个典型场景是“重启就好了要不要管”。我的建议是:如果不采集证据就重启,等于销毁案发现场。至少先把能拿到的日志、监控、硬件状态截图保存一份,再重启恢复。恢复业务优先级当然高,但留证据同样关乎你后续能不能彻底根治问题。
第二个典型场景是“网络通不代表服务通”。常见的情形:用ping测试机器IP是通的,但业务端口连不上,于是怀疑防火墙。实际上,ping走的是ICMP,和TCP业务端口完全不是一回事。排查时至少要用telnet、nc或者ss去确认端口监听状态和连通性,再结合防火墙策略做判断。
第三个典型场景是“告警时间不等于故障开始时间”。告警是阈值触发的,可能故障已经悄悄酝酿了半小时,指标才突破阈值。回看监控曲线时,要把时间窗口往前推,才能看到故障真正的萌芽点。
第四个典型场景是“多故障叠加”。有些时候,硬件快挂了会导致性能劣化,性能劣化又引发业务超时,业务超时又触发重试风暴,最后整个系统像多米诺骨牌一样全倒。如果你只盯着最表面的业务超时,很容易漏掉底层诱因。所以排查时要把证据链串起来,问一句“这个现象是不是另一个现象的原因导致的结果”,而不是孤零零地处理单个告警。
5.2 常用命令与信息速查表
在服务器上排查时,我习惯把这些命令直接放在手边。这里分享一份速查表,覆盖“刚接到告警时最值得先跑的一批命令”:
| 排查对象 | 命令/工具 | 一句话提示 |
|---|---|---|
| 硬件事件 | ipmitool sel list | 先看带外日志,硬件故障一目了然 |
| 内核/硬件日志 | dmesg -T | grep -iE "error|mce|memory" | 找内存、CPU相关的硬件报错 |
| 系统负载总览 | top、htop、uptime | 看load、CPU、内存整体状态 |
| 磁盘IO | iostat -x 1、iotop | 确认磁盘是否成为瓶颈 |
| 存储/磁盘健康 | smartctl -a /dev/sda、storcli/ssacli | 查物理盘和阵列卡状态 |
| 网络连通/监听 | ss -tlnp、telnet <ip> <port> | 确认服务监听和端口连通性 |
| 系统日志 | journalctl -xe、tail -f /var/log/messages | 看系统级报错,特别是OOM、cgroup、网络 |
| 服务状态 | systemctl status <service>、systemctl --failed | 先看异常服务有哪些 |
| 关键变更记录 | ls -lt /etc/、rpm -qa --last、发布平台记录 | 按时间点反查变更 |
这些命令不是跑一遍就完事,跑完要学会“交叉对照”。比如top里CPU打满,接着看是不是某条SQL、某个进程、某个虚拟机的CPU steal导致的,再往下看是不是宿主机邻居在抢资源,一层一层追。
5.3 最后再分享几个小习惯
说完了方法和案例,还想聊几个我多年实践下来的习惯。
第一个习惯是写排障记录。每次排查完,我会把现象、证据、定位过程、根因、解决办法整理成几行字,按时间归档。这既是给团队沉淀知识,也是在训练自己的排查思维。写记录的过程,其实就是逼自己把“猜”变成“逻辑链”的过程。写得多了,下次遇到相似告警,定位速度会快一大截。
第二个习惯是把排查动作和恢复动作分开。优先恢复业务没错,但每一步操作都要有个记录,至少自己清楚“我动了什么”。尤其是线上环境,改配置前必须先备份,改完要能回滚。见过太多因为恢复操作太粗暴,反而引发二次故障的案例。
第三个习惯是保持怀疑,尤其是对“已知结论”。当所有人都在说“这个模块一直很稳,不可能出问题”的时候,你反而要去检查它。很多故障之所以排查很久,是因为大家下意识地排除掉了“不可能出问题的组件”,但事实恰恰是它出了问题。
第四个习惯是定期做“故障演练”。不一定要多复杂,哪怕每个月挑一个组件,人为制造一个故障,走一遍完整排查流程,都能让团队的故障响应能力有明显提升。纸上谈兵一百次,不如实际断一次网、拔一块盘、杀一个进程。
这些习惯都不难,难的是在压力下依然坚持做。故障排查这件事,本质上拼的不是智商,而是纪律。你越是在慌乱的时候守住“先定位后解决,先硬件后软件”这条线,系统就越不会让你失望。