当前位置: 首页 > news >正文

【Linux从入门到精通】第49篇:服务器故障排查终极指南——思路决定出路

目录

一、排查框架:接到告警后第一件事做什么

1.1 黄金5分钟:建立全局认知

1.2 快速定位方向:看vmstat决定下一步

二、场景一:CPU飙升100%

2.1 现象

2.2 排查流程

2.3 CPU排查总结

三、场景二:内存泄漏排查

3.1 现象

3.2 排查流程

3.3 内存泄漏排查总结

四、场景三:磁盘满了但找不到大文件

4.1 现象

4.2 排查流程

4.3 磁盘排查总结

五、综合排查速查表

六、本篇小结

动手练习

七、下篇预告


一、排查框架:接到告警后第一件事做什么

1.1 黄金5分钟:建立全局认知

半夜被报警叫醒,你最不该做的就是随机敲命令乱试。没有明确方向的排查,只会浪费宝贵的恢复时间。前5分钟,只做一件事:建立全局认知,锁定问题范围

标准流程只有五条命令:

bash

# 1. 系统整体负载(1分钟/5分钟/15分钟平均负载) uptime # 2. 内存概况(available是最关键的指标) free -h # 3. 磁盘空间(满了什么都做不了) df -h # 4. 系统整体负载分解(r=CPU,b=I/O,wa=等待I/O) vmstat 2 5 # 5. 最近的系统日志(内核、服务、OOM等异常) journalctl -p err --since "30 min ago"

做完这五条,回答自己三个问题

  1. 负载高吗?(uptimevs CPU核心数)

  2. 负载是哪来的?(vmstatr列还是b列高?wa有多高?)

  3. 最近有什么异常事件?(OOM Killer?服务重启?磁盘错误?)

1.2 快速定位方向:看vmstat决定下一步

text

vmstat 2 │ ├── r 列持续 > CPU核心数 ──→ CPU瓶颈 │ ├── b 列持续 > 0 ──→ I/O瓶颈 │ ├── si/so 持续 > 0 ──→ 内存瓶颈(正在换页) │ └── 三者都正常 ──→ 网络或应用层问题

这4个判断足够覆盖90%的生产故障。方向错了,后面的所有排查都是浪费时间。接下来,我们按三种最经典的故障场景,逐一展开完整的排查流程。

二、场景一:CPU飙升100%

2.1 现象

监控告警:某台服务器的CPU使用率突然飙升到100%,且vmstat确认r列远大于CPU核心数。

2.2 排查流程

第一步:找出吃CPU的进程

bash

top -c # 按 P 确保按CPU排序 # 记下排在最前面的PID和进程名

假设PID为12345,进程名是java(某个Java应用)。

第二步:细化到线程级别

对于多线程应用(Java、MySQL),一个进程的CPU高通常是某几个线程导致的:

bash

# 查看进程内每个线程的CPU使用率 top -H -p 12345 # 记下最高CPU的线程ID(TID),假设为 12389

第三步:将线程ID转十六进制

bash

printf "%x\n" 12389 # 输出:3065

第四步:查看该线程的调用栈

bash

# jstack是Java专用工具,输出进程内所有线程的调用栈 # 用十六进制TID(3065)搜索对应的线程 jstack 12345 | grep -A 20 3065 # 如果是其他应用(非Java),用`perf`采样CPU调用栈 sudo perf top -p 12345

输出会显示线程当前正在执行的函数名。从调用栈中的函数名可以判断:

  • 频繁GC(垃圾回收)→ 内存不够,检查堆大小或排查内存泄漏

  • 正则表达式匹配 → 可能是正则回溯问题或恶意输入

  • 业务代码的死循环 → 代码逻辑bug

  • 加密/压缩等计算密集函数 → 正常的计算任务,考虑优化算法或限流

2.3 CPU排查总结

text

top → 找高CPU进程 top -H -p PID → 找高CPU线程(多线程应用) jstack/perf top → 看调用栈找根因

三种常见根因:

  • 死循环:业务代码bug

  • 频繁GC:内存不足或内存泄漏导致

  • 正常计算密集:加密/压缩/转码等,考虑加CPU或限流

三、场景二:内存泄漏排查

3.1 现象

服务器内存使用率持续增长,即使业务低谷期也不下降。重启后恢复正常,但运行几天后又涨回去。这是典型的内存泄漏特征。

3.2 排查流程

第一步:确认内存分布

bash

free -h # available持续减少,buff/cache没有增加 → 匿名页(程序堆/栈)在增长

buff/cache是文件缓存,涨了不意味着泄漏。如果used不断增加而buff/cache基本不变,说明应用在持续申请匿名内存。

第二步:找出内存大户

bash

ps aux --sort=-%mem | head -10 # 或者用更精确的PSS统计 sudo smem -p -s pss | head -10

假设PID为12345的进程内存占用不停增长。smem的PSS(Proportional Set Size,比例共享大小)比RSS更准确,因为它把共享库的内存按比例分摊给了各个使用它的进程。

第三步:查看该进程的内存增长趋势

bash

# 每10秒打印一次内存使用,持续观察 while true; do echo "$(date +%H:%M:%S) $(smem -p -c "pid pss" -P 12345 | tail -1)" sleep 10 done

如果PSS持续增长 → 确认泄漏存在于该进程中。

第四步:查看进程内存分配细节

bash

pmap -x 12345 | tail -1 # 或者 cat /proc/12345/status | grep -E "VmRSS|VmSize"

pmap显示该进程的虚拟内存映射——每一段内存的起始地址、权限、大小和来源(映射的是哪个文件还是匿名分配)。如果某段匿名内存(anon)异常大(比如占总内存的80%以上),可以基本确认是程序内部在持续申请内存而不释放。

第五步:使用valgrind深入分析(开发环境)

bash

# Valgrind的memcheck工具会模拟执行程序,追踪每一块内存的分配和释放 # 注意:这会使程序运行速度减慢10-20倍,只能在开发环境使用! valgrind --leak-check=full --log-file=valgrind.log ./my_app cat valgrind.log | grep "definitely lost"

输出会精确指出代码中哪个文件、哪一行分配的哪块内存没有被释放。这个信息交给开发人员,可以精确定位泄漏点。

3.3 内存泄漏排查总结

text

free -h → 确认内存增长类型 ps/smem → 找到内存增长进程 pmap/proc/PID/status → 确认进程中哪部分内存异常(匿名页还是共享内存) valgrind(开发环境)→ 定位到具体代码行

常见根因

  • 应用代码bug:忘记释放内存、循环中反复分配

  • 缓存未设上限:进程内缓存(如HashMap)无限增长

  • 线程泄漏:线程创建后未正确回收,每个线程默认占用约8MB栈空间

四、场景三:磁盘满了但找不到大文件

4.1 现象

df -h报告磁盘使用率90%以上,但用du -sh /*逐层排查,所有目录加起来的大小远小于df显示的已用空间。

为什么dfdu结果对不上?

  • df是从文件系统元数据中直接读取的块使用量,反映的是磁盘块分配情况

  • du是遍历目录树,把每个可见文件的大小累加起来

  • 如果有文件被删除了但进程还持有它的文件描述符,du统计不到,但df知道这些磁盘块没有被释放

4.2 排查流程

第一步:确认df和du的差异

bash

df -h / du -sh / 2>/dev/null # 如果df显示40G已用,du显示30G,但加起来确实找不到后10G在哪

这种悬殊差异(差了几个GB而目录遍历完全找不到对应文件),说明有被删除但仍在被进程持有的文件。

第二步:找出“已删除但仍被占用的文件”

bash

sudo lsof | grep deleted | awk '{print $1, $2, $NF}' | sort -u # 或者更精确地显示文件大小 sudo lsof +L1

+L1是lsof的专用参数,表示“列出所有链接计数小于1的文件”,即被删除但进程仍打开着的文件。输出示例:

text

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME java 12345 app 12w REG 253,1 8589934592 0 56789 /var/log/app.log (deleted)

这条输出显示:进程java(PID 12345)的文件描述符12w,指向一个已被删除的文件/var/log/app.log,它占用了8.5GB的磁盘空间。那个“(deleted)”标记就是罪魁祸首——文件已不在目录中,但内核因为进程还打开着它,不会释放它的磁盘块。

第三步:释放空间

bash

# 如果是日志文件,直接清空 sudo truncate -s 0 /proc/12345/fd/12 # 或者让进程重新打开日志文件(更优雅,需要进程支持) kill -HUP 12345 # 发送SIGHUP,许多守护进程会重新打开日志文件 # 如果不关心这个文件的内容,直接杀掉进程 sudo kill 12345

truncatevskilltruncate -s 0通过/proc/PID/fd/文件描述符来截断文件内容,进程无感知,不会中断服务。kill会终止进程,如果这个进程是关键服务,可能造成宕机。因此优先用truncate

4.3 磁盘排查总结

text

df -h → 确认分区已用空间 du -sh /* → 找到空间占用大的目录 df和du结果悬殊 → 被删除文件仍被占用(lsof +L1) lsof +L1 → 找到进程和文件描述符 truncate -s 0 /proc/PID/fd/FD → 释放空间

常见根因

  • 日志轮替不当:应用在持续写入,logrotate脚本用rm删了文件但没有用kill -HUP通知应用重新打开日志句柄。文件虽删,数据继续往内核的旧inode里写

  • 临时文件未清理:应用创建的临时文件被删除,但句柄未关闭

  • 大文件仍被进程持有:有人rm了一个大文件但不知道有进程还在用它

五、综合排查速查表

现象第一步命令第二步命令关键判断
负载高uptime+vmstat 2r高→第三列,b高→第四列r>CPU核数=CPU瓶颈,b>0=I/O瓶颈
CPU高top -ctop -H -p PID+jstack/perf top找吃CPU的线程和调用栈
内存高free -hsmem -p -s pssavailable持续下降=内存不足
内存泄漏smem观察趋势pmap -x PID+valgrind进程PSS只涨不跌=泄漏
磁盘满df -hdu -sh /* 2>/dev/null逐层深入df和du结果悬殊=被删文件仍被占用
磁盘满(隐形)df -hvsdu -shlsof +L1查(deleted)文件并清空或kill -HUP
网络异常ping -c 4 网关ss -tanp确认连通性和端口状态

六、本篇小结

排查黄金法则

  1. 先宏观后微观:先看全局(uptime/vmstat/df),锁定方向后再深入细节

  2. 先排除最简单的原因:磁盘满了、服务挂了、内存溢出了——这些远比代码bug更常见

  3. 一次只验证一个假设:不要同时改三个配置,改完一个就验证,否则不知道哪个生效了

  4. 每一步保存证据script命令记录终端操作,sar历史数据回溯问题发生时的系统状态

三个高频故障的完整链路

  • CPU飙升top找进程 →top -H找线程 →jstack/perf top看调用栈

  • 内存泄漏smem找进程 →pmap确认泄漏区域 →valgrind(开发环境)定位代码行

  • 磁盘隐形占用dfvsdu发现差异 →lsof +L1找(deleted)文件 →truncatekill -HUP释放

动手练习

bash

# 1. 完整跑一次系统体检流程 uptime && free -h && df -h && vmstat 2 5 # 2. 模拟“删除了文件但空间不释放”的场景 dd if=/dev/zero of=/tmp/bigdel bs=1M count=100 exec 3<>/tmp/bigdel # 打开一个文件描述符持有文件 rm /tmp/bigdel # 删除文件 df -h /tmp # 注意空间没释放 lsof +L1 | grep bigdel # 找到这个“幽灵”文件 exec 3>&- # 关闭文件描述符,空间释放 df -h /tmp # 验证空间已恢复 # 3. 观察进程的内存变化 smem -p -s pss | head -10

七、下篇预告

这是专栏的倒数第二篇文章。我们走过了50篇的技术学习——从第1篇的“为什么要学Linux”到第48篇的集群高可用,从最基础的cdls命令到内核函数级别的动态追踪。

最后一篇《专栏总结与Linux学习之路的未来展望》将回顾整条学习路径,你可以对照每一篇的标题检查自己是否掌握核心操作和排查思路。我们将梳理Linux在当前技术生态中的角色演变——从传统的服务器操作系统,到云计算的基础镜像、Kubernetes的容器运行时、AI训练平台的底层支撑;并为你规划后续的深入方向:容器编排、可观测性体系、内核开发等领域的学习路线图。这是整个专栏的终点,也是你Linux技能持续生长的起点。

http://www.jsqmd.com/news/743190/

相关文章:

  • 全面掌握AMD内存性能:ZenTimings监控工具完全指南
  • HiFiBerry OS:专为树莓派打造的高品质音频播放系统
  • 2026年直流电源价格,哪家更实惠? - mypinpai
  • Ethereal Style for Zotero:让你的文献管理变得生动有趣
  • 高效智能电话号码归属地定位工具:技术原理与实战应用指南
  • 2026年AI智能照明哪家好:技术与应用选择解析 - 品牌排行榜
  • 现在不看就晚了:C语言OTA配置中未声明volatile的Flash写操作,已在3款量产设备引发批量掉站事故(附JTAG取证报告)
  • RimWorld伤害机制全解析:从代码层面理解为什么你的小人总被一枪秒
  • SDR新手避坑指南:为什么你的dump1090收不到飞机?从RSP1到HackRF的硬件选择与软件调试
  • Mycroft智能音箱集成YouTube播放技能:从yt-dlp依赖到语音交互全解析
  • MoDA框架:动态混合注意力机制在深度学习中的应用
  • 2026年专业的论文初稿生成平台有哪些 - 品牌排行榜
  • 零样本学习框架实战:基于zero_nlp快速构建中文NLP应用
  • 从零构建个人LLM应用:基于Qwen-7B与FastAPI的完整实践指南
  • 运算放大器振荡器设计与传感器应用解析
  • 百度网盘高速下载终极指南:Python解析工具突破官方限制
  • Arm GICv5 ITS架构与Fast Models调试实践
  • 3步掌握OpenSpeedy:免费开源的游戏变速神器
  • 论文初稿生成工具哪个好用?2026年实用工具测评 - 品牌排行榜
  • 2026年论文开题报告撰写网站有哪些 - 品牌排行榜
  • 多AI助手配置统一管理:基于符号链接的集中化解决方案
  • Obsidian PDF++终极教程:3步打造你的智能PDF知识库
  • Bili2text终极指南:3步将B站视频转文字稿,学习效率提升10倍!
  • 用AI生成论文初稿怎么样?2026年高效写作新方式 - 品牌排行榜
  • docx2tex:Word到LaTeX转换的终极解决方案
  • 2026智能照明灯具厂家:AI节能与健康光技术新发展 - 品牌排行榜
  • 3G无线网络性能测量与优化实战指南
  • 终极QQ音乐文件解码指南:3分钟掌握qmcdump使用技巧
  • AI智能体技能库:模块化设计、核心技能与集成实践
  • CV微调新思路:为什么说卷积比线性更好?从Mona的多尺度视觉滤波器设计讲起