Linux服务器故障排查入门:从现象到根因的分步操作指南

作为一名接触运维也有五六年的老兵,见过太多新人遇到服务器故障时手忙脚乱的样子:要么漫无目的地乱敲命令,要么上来就直接重启服务器,不仅经常错过最佳排查时机,甚至还会把故障现场破坏得一干二净,最后问题到底出在哪也说不清楚。

其实Linux服务器故障排查根本不是靠运气猜,而是一套有标准流程、有明确步骤的方法论。只要你跟着我下面讲的步骤一步步来,90%以上的常见故障都能在半小时内定位并解决。我会把每个步骤的操作命令、判断标准、甚至避坑要点都写得明明白白,你直接照着做就行。


排查前先记三个黄金原则

在你敲下任何命令之前,先把这三个原则刻在脑子里,能帮你少犯80%的低级错误:
1. 先止血,再排查:如果故障已经影响线上业务,第一时间先做恢复操作(比如重启服务、切流量到备用节点、回滚最近的变更),把业务影响降到最低,再慢慢排查根因。
2. 先外后内,先整体后局部:不要一上来就直接登服务器翻日志,先从外部验证故障现象,确认影响范围,再逐步缩小排查范围。
3. 不要破坏现场:排查过程中不要随便修改配置、删除文件、重启服务,除非你已经确定这么做是对的。很多时候关键证据就藏在当前的运行状态里,重启之后就没了。


第一步:故障现象确认(不要上来就登服务器)

这一步是最容易被跳过的,但恰恰是最重要的。很多人故障一发生就立刻登服务器乱翻,结果折腾了半小时才发现是用户那边的网络问题,或者只是CDN节点故障,服务器本身根本没问题。

先做这几个非侵入式测试

你甚至不需要登录服务器,先在本地或者跳板机执行这几个命令,就能对故障有个基本判断:

  1. 测试网络层连通性
ping -c 4 <服务器IP>

如果能ping通且丢包率为0,说明物理链路和网络层基本没问题;如果ping不通或者丢包严重,大概率是网络层面的故障(比如服务器宕机、网线掉了、交换机故障、运营商线路问题)。
⚠️ 注意:ping不通不一定是服务器挂了,很多服务器会禁ICMP协议,这时候需要结合其他命令判断。

  1. 测试端口是否开放
nc -zv <服务器IP> <端口>
# 或者用telnet(需要安装telnet包)
telnet <服务器IP> <端口>

比如测试SSH端口就是nc -zv 192.168.1.100 22,测试Web服务就是nc -zv 192.168.1.100 80。如果提示连接成功,说明端口是开放的;如果提示连接拒绝,要么是服务没启动,要么是防火墙拦截了。

  1. 模拟业务请求
    如果是Web服务或者HTTP接口,直接用curl测试:
curl -v -o /dev/null -s -w "状态码: %{http_code}\n总耗时: %{time_total}s\nDNS解析耗时: %{time_namelookup}s\n连接耗时: %{time_connect}s\n" <业务URL>

这个命令会返回请求的详细耗时分解和状态码,你可以直接看到是DNS解析慢、TCP建立连接慢、还是服务器响应慢,以及返回的是502、504还是403错误,这些都是非常关键的线索。

同时确认这几个信息

  • 故障影响范围:是所有用户都访问不了,还是只有部分地区的用户?是单个接口有问题,还是整个服务都挂了?是单台服务器故障,还是整个集群都出问题了?
  • 最近的变更记录:故障发生前30分钟内有没有做过发布、配置修改、网络策略调整、证书更新、系统升级?很多故障都是变更导致的,先看变更记录能帮你少走很多弯路。
  • 监控大盘数据:立刻去看Prometheus/Grafana/Zabbix的监控曲线,CPU、内存、磁盘、网络流量、错误率这些指标有没有异常突增?监控不会撒谎,这些数据是最客观的证据。

第二步:系统全局状态快速扫描

确认需要登录服务器排查后,不要一上来就翻日志,先花1分钟看一下系统的整体”生命体征”,判断系统是不是处于”濒死”状态。

1. 系统负载检查

uptime

返回结果类似这样:

14:32:45 up 126 days, 21:43,  1 user,  load average: 0.28, 0.19, 0.12

重点看最后三个数字:1分钟、5分钟、15分钟的平均负载。判断标准很简单:
– 如果1分钟负载远大于服务器CPU核数(比如4核机器负载到了20),说明系统已经严重过载,任务正在排队,响应肯定会很慢。
– 如果1分钟负载 < 5分钟负载 < 15分钟负载,说明负载在下降,故障可能正在自愈。
– 如果1分钟负载 > 5分钟负载 > 15分钟负载,说明负载还在上升,故障正在恶化。

如果负载很高,直接看top命令的详细信息:

top
# 推荐用更直观的htop(需要安装)
htop

P键可以按CPU占用率排序,按M键按内存占用率排序,快速找到占用资源最高的进程。特别注意%wa这个指标(IO等待),如果这个值超过30%,说明CPU在空转等磁盘IO,瓶颈不在CPU而在存储。

2. 内存与交换分区检查

free -h

返回结果:

               total        used        free      shared  buff/cache   available
Mem:           7.8Gi       2.3Gi       3.1Gi        98Mi       2.4Gi       5.1Gi
Swap:          2.0Gi          0B       2.0Gi

重点看available列,这才是真正可用的内存,不要看free(因为Linux会把空闲内存拿来做缓存,free低不代表内存不够)。如果available很小,而且Swap的used列有值甚至很高,说明物理内存已经不够用了,系统正在用磁盘当虚拟内存,性能会断崖式下跌。

3. 磁盘空间检查

# 查看磁盘空间使用
df -hT
# 查看inode使用(很多时候"磁盘满"其实是inode用完了)
df -ih

如果某个分区使用率超过90%,就需要注意了;如果100%满了,那很多服务都会写不了日志、存不了数据,直接报错。inode满的情况比较隐蔽,虽然磁盘还有空间,但已经没法创建新文件了,常见于小文件特别多的场景(比如缓存目录、日志目录)。

4. 内核日志检查

# 查看最近50条内核日志,带时间戳
dmesg -T | tail -n 50

这里能看到很多底层的硬件错误、磁盘错误、OOM Killer(内存溢出杀进程)的记录。比如Java应用莫名其妙退出了,你大概率能在这里看到Out of memory: Killed process xxxx (java)的记录,这就是系统因为内存不够把Java进程杀了。


第三步:常见故障场景的排查SOP

下面我把运维工作中最常遇到的9种故障场景的排查步骤都整理好了,你遇到对应的问题直接照着步骤走就行。


场景1:服务启动失败/反复崩溃

现象systemctl status显示服务是failed状态,或者反复重启,业务接口返回502/503错误。

排查步骤:

  1. 先看服务状态和最近的报错:
sudo systemctl status <服务名> --no-pager
# 比如看nginx状态:sudo systemctl status nginx --no-pager

这里通常会直接显示启动失败的原因,比如配置文件语法错误、端口被占用、权限不足等等。

  1. 看服务的详细日志:
# 查看该服务最近30分钟的日志
sudo journalctl -u <服务名> --since "30 min ago" --no-pager
# 如果是反复重启,看上一次启动失败的日志
sudo journalctl -u <服务名> -b -1 --no-pager

90%的启动失败问题都能从日志里找到答案,比如配置文件某一行写错了、依赖的其他服务连不上、证书过期了、磁盘满了写不了文件等等。

常见根因:

  • 配置文件语法错误(改完配置记得先校验,比如nginx -thttpd -t
  • 端口被其他进程占用(用ss -tulnp | grep <端口>查看)
  • 权限不足(服务运行用户没有配置文件或数据目录的访问权限)
  • 依赖的数据库、Redis等服务不可达
  • 证书过期或格式错误
  • 磁盘满或者inode满

临时处理:

如果需要快速恢复业务,先回滚最近的配置变更或者版本,再重启服务:

sudo systemctl restart <服务名>

⚠️ 注意:重启前最好保留现场,比如导出Java进程的堆栈信息(jstack <PID> > jstack.log),方便事后复盘根因。


场景2:网络不通/延迟高/丢包

现象:服务能正常启动,但外部访问不了,或者访问超时、丢包严重。

排查步骤:

  1. 先看网卡和IP配置:
# 查看网卡状态和IP地址
ip addr
# 查看路由表
ip route show

确认网卡是UP状态,IP地址配置正确,默认网关存在。

  1. 测试到网关的连通性:
ping -c 4 <网关IP>

如果连网关都ping不通,大概率是本机网卡或者内网交换机的问题。

  1. 测试DNS解析:
# 查看DNS配置
cat /etc/resolv.conf
# 测试域名解析
nslookup <域名>
# 或者更详细的dig命令
dig <域名>

如果DNS解析失败或者解析到错误的IP,那业务肯定访问不了外部服务。

  1. 链路追踪定位丢包点:
mtr --report <目标IP>

mtr是ping和traceroute的结合体,会显示数据包经过的每一跳的丢包率和延迟,能帮你精准定位是哪一个节点出了问题,是内网交换机、还是运营商骨干网、还是目标机房的问题。

  1. 查看TCP连接状态:
# 查看TCP连接统计摘要
ss -s
# 查看所有监听的端口
ss -tulnp
# 查看所有已建立的连接
ss -tn state established

如果TIME-WAIT状态的连接特别多(比如几万甚至几十万),说明短连接频繁创建销毁,可能需要调整内核参数tcp_tw_reuse来复用连接;如果CLOSE-WAIT太多,说明应用程序没有正确关闭连接,存在代码层面的资源泄露。

进阶:抓包分析

如果以上步骤都没找到问题,可以用tcpdump抓包分析:

# 抓取eth0网卡上80端口的流量,保存为pcap文件
tcpdump -i eth0 -s 0 -w traffic.pcap port 80

把pcap文件下载到本地用Wireshark打开,可以直观地看到有没有丢包、重传、协议错误等问题,这是网络排查的终极武器。


场景3:磁盘空间满/No space left on device

现象:服务写不了日志,上传文件失败,报错”No space left on device”。

排查步骤:

  1. 先确认是空间满还是inode满:
df -hT
df -ih

如果是inode满,说明小文件太多,需要清理小文件;如果是空间满,继续往下找大文件。

  1. 定位大文件和大目录:
# 查看/var目录下各子目录的大小,按大小排序
sudo du -xh /var --max-depth=1 | sort -h | tail -20
# 查找大于500M的文件
sudo find / -type f -size +500M -exec ls -lh {} \; | sort -k5 -h

通常大文件都在日志目录(/var/log)、数据目录、或者临时目录(/tmp)下。

  1. 检查”已删除但仍被占用”的文件:
    很多时候你把大文件删了,但df还是显示空间满,这是因为文件被删除了,但还有进程持有它的句柄在写入,空间没有释放:
sudo lsof | grep deleted

这个命令会列出所有已删除但仍被进程占用的文件,找到对应的PID,重启对应的进程就能释放空间了。
⚠️ 注意:不要直接rm正在被应用写入的日志文件,应该用echo > 日志文件的方式清空内容,这样不会导致句柄泄漏。

处理建议:

  • 日志清理优先用logrotate或者应用自身的日志滚动配置,不要手动rm日志。
  • systemd日志占满空间的话,用这个命令清理更安全:
# 查看journal日志占用的空间
sudo journalctl --disk-usage
# 只保留最近7天的日志
sudo journalctl --vacuum-time=7d
# 或者只保留1G的日志
sudo journalctl --vacuum-size=1G

场景4:系统卡顿/Load高/响应慢

现象:系统负载很高,业务响应很慢,甚至SSH登录都卡。

排查步骤:

  1. 先判断瓶颈在哪:
vmstat 1 5

重点看这几个指标:
us:用户态CPU占用率,如果很高说明是应用进程消耗了大量CPU。
sy:内核态CPU占用率,如果很高说明系统调用或者内核层面有问题。
wa:IO等待率,如果超过30%说明瓶颈在磁盘IO。
si/so:swap换入换出,如果这两个值不为0,说明物理内存不够用了,系统在频繁换页。

  1. CPU瓶颈定位:
# 查看每个CPU核心的负载情况
mpstat -P ALL 1
# 查看每个进程的CPU占用
pidstat -u 1

如果某个CPU核心100%而其他核心空闲,说明存在单线程瓶颈(比如单线程应用、死循环)。

  1. 磁盘IO瓶颈定位:
# 查看磁盘IO负载
iostat -dx 1
# 查看哪个进程在占用IO
sudo iotop -o

如果%util接近100%,说明磁盘已经饱和,成为瓶颈;await过高说明磁盘响应太慢。

  1. 内存瓶颈定位:
    如果vmstat的si/so不为0,说明内存不够了,用top或者ps找到占用内存最高的进程,看是不是内存泄漏。

场景5:权限不足/Permission denied

现象:服务启动时报Permission denied,或者程序读不了文件、写不了目录。

排查步骤:

  1. 先看文件/目录的权限和所有者:
ls -l <文件或目录路径>

比如结果是-rw-r--r-- 1 root root 4096 Jun 10 14:32 app.conf,说明这个文件的所有者是root,只有root能写,其他用户只能读。如果你的服务是用www用户运行的,那肯定写不了这个文件。

  1. 看运行服务的用户权限:
id <用户名>

确认用户所属的用户组,有没有对应的访问权限。

  1. 检查ACL权限(如果启用了ACL):
getfacl <文件或目录路径>

如果设置了ACL,权限控制会更复杂,需要用这个命令查看详细的ACL规则。

  1. 特殊情况:SELinux拦截
    如果你确认权限配置都对,但还是报Permission denied,那大概率是SELinux的问题:
# 查看SELinux状态
getenforce
# 如果返回Enforcing,说明SELinux是开启的
# 查看SELinux的拒绝日志
sudo ausearch -m AVC,USER_AVC -ts recent

临时验证是不是SELinux的问题可以先把它设为宽容模式:

sudo setenforce 0

如果问题解决了,就说明确实是SELinux的拦截,不要直接把SELinux关了,正确的做法是生成对应的策略:

sudo ausearch -c "<服务名>" --raw | audit2allow -M my_service_policy
sudo semodule -i my_service_policy.pp
sudo setenforce 1

场景6:SSH登录失败

现象:SSH连接服务器被拒绝,或者提示Permission denied。

排查步骤:

  1. 先测试22端口是否通:
nc -zv <服务器IP> 22

如果端口不通,要么是sshd服务没启动,要么是防火墙拦截了,要么是服务器本身挂了。

  1. 查看sshd服务状态:
# CentOS/RHEL
sudo systemctl status sshd --no-pager
# Ubuntu/Debian
sudo systemctl status ssh --no-pager

如果服务没启动,启动即可:sudo systemctl start sshd

  1. 查看SSH登录日志:
# CentOS/RHEL
sudo journalctl -u sshd --since "30 min ago" --no-pager
# Ubuntu/Debian
sudo journalctl -u ssh --since "30 min ago" --no-pager
# 或者看auth日志
tail -n 50 /var/log/auth.log

日志里会明确写登录失败的原因:是密码错误、密钥不匹配、还是用户被禁止登录。

  1. 检查密钥文件权限(密钥登录的情况):
    如果是用密钥登录,密钥文件的权限必须是严格的600,.ssh目录权限必须是700,否则SSH会认为不安全拒绝登录:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_rsa

场景7:高CPU占用

现象:CPU使用率持续100%,系统响应慢。

排查步骤:

  1. 找到占用CPU最高的进程:
top -c
# 或者pidstat
pidstat -u 1

记下高CPU进程的PID。

  1. 分析进程的CPU消耗在哪里:
# 查看该进程的线程CPU占用
pidstat -u -p <PID> 1
# 追踪进程的系统调用,看卡在哪一步
strace -p <PID> -T -tt
# 更专业的性能分析用perf
perf top -p <PID>

strace会显示进程执行的每一个系统调用和耗时,能直接看到是卡在读取文件、连接数据库,还是在死循环。


场景8:服务假死/无响应

现象:服务进程还在,但不响应请求,或者响应超时。

排查步骤:

  1. 看进程是不是还在运行:
ps aux | grep <进程名>

如果进程存在,继续往下查。

  1. 查看进程打开的文件和连接:
lsof -p <PID>

看是不是文件句柄耗尽了(Too many open files),或者TCP连接数太多。默认的文件句柄限制是1024,高并发服务很容易达到这个限制。

  1. 查看进程的系统调用:
strace -p <PID> -T -tt

通常假死的进程会卡在某个系统调用上,比如read读取一个很慢的磁盘文件,或者connect连接一个已经挂掉的下游服务,从strace的输出能直接看到卡在哪个调用。

  1. 导出进程堆栈(Java/Python等应用):
    如果是Java应用,导出jstack看线程是不是死锁了:
jstack <PID> > jstack_$(date +%Y%m%d%H%M).log

如果是Python应用,用py-spy工具可以直接查看运行中的Python进程的调用栈,不需要重启进程。


场景9:时间不同步

现象:日志时间不对,接口请求验签失败,数据库主从同步异常。

排查步骤:

  1. 查看系统时间:
date

和标准时间对比,看差了多少。

  1. 查看时间同步服务状态:
# systemd-timesyncd(大多数系统默认)
systemctl status systemd-timesyncd
# 或者ntpd
systemctl status ntpd
# 或者chronyd
systemctl status chronyd
  1. 手动同步时间:
# 用timesyncd同步
sudo timedatectl set-ntp true
# 或者用ntpdate手动同步(需要安装ntpdate包)
sudo ntpdate ntp.aliyun.com

时间不同步的问题虽然不常见,但一旦出现会引发很多莫名其妙的问题,比如JWT令牌验签失败、分布式锁异常、日志时序混乱等等,排查的时候很容易忽略。


故障处理后的收尾工作

故障解决了不代表事情就完了,下面这几步是一个专业运维和”救火队员”的区别:
1. 验证修复效果:故障处理完后,一定要做回归测试,确认业务完全恢复正常,监控指标回到正常水位,至少观察10-30分钟没问题再走。
2. 记录故障文档:把故障发生时间、现象、排查过程、根因、解决方案都记录下来,方便后续查阅,也可以给团队其他成员分享。
3. 复盘改进:思考为什么这个故障没有提前发现?监控是不是有遗漏?告警阈值是不是设置得不合理?有没有办法避免同类故障再次发生?比如加监控、加告警、完善SOP、做自动化巡检等等。


给新手的几个建议

  1. 不要迷信”重启大法”:重启确实能解决很多问题,但你永远不知道根因是什么,下次还会遇到同样的问题。重启前尽量保留现场,事后一定要搞清楚为什么重启能解决问题。
  2. 操作前先备份:修改配置文件、删除文件、执行危险命令前,先做个备份,比如cp nginx.conf nginx.conf.bak,改坏了还能回滚。
  3. 生产环境操作前先在测试环境验证:不要在生产环境试错,不确定的命令先在测试环境跑一遍,确认没问题再到生产执行。
  4. 善于查日志:90%的问题答案都藏在日志里,学会看日志、会搜日志,排查效率会提升不止一倍。

故障排查是一个经验积累的过程,见得多了自然就熟了。把这篇文章收藏好,下次遇到故障的时候翻出来照着步骤走,慢慢你也能成为别人眼里的”运维大神”。

📂 分类:兴趣文娱 / 体育资讯