服务器在高负载运行中可能出现性能骤降、进程异常退出、系统无响应等问题。定位这类问题需要一套系统化的排查流程,从硬件层到内核层逐层排除。本文以一台实际生产环境中出现load飙升的Linux服务器为例,演示完整的诊断路径。
系统负载异常的快速判断
当监控系统告警load average异常时,第一步是区分计算瓶颈和I/O瓶颈。通过uptime和vmstat快速判断:
# 查看系统负载
uptime
# 输出示例: load average: 32.15, 28.40, 15.20
# 查看CPU逻辑核心数
nproc
# 输出: 16
# 负载32远超核心数16,进入详细诊断
# vmstat查看进程队列状态
vmstat 1 5
# procs列: r=运行队列, b=阻塞队列(D状态)
# 如果r持续>16,计算资源不足
# 如果b持续偏高,I/O等待严重
r列代表正在运行和等待CPU的进程数,b列代表处于不可中断睡眠状态(通常等待I/O)的进程数。r持续高于CPU核心数指向计算瓶颈,b偏高指向磁盘或网络I/O瓶颈。
CPU性能瓶颈深度定位
确认计算瓶颈后,使用perf和pidstat定位具体消耗源:
# 查看CPU占用最高的进程
pidstat -u 1 5 | sort -k8 -rn | head -10
# 查看进程内各线程CPU占用
pidstat -t -p $(pgrep -d ',' java) 1 3
# 使用perf抓取CPU热点函数
perf record -ag -- sleep 10
perf report --stdio | head -50
# 快速查看CPU各状态占用比例
mpstat -P ALL 1 5
# %usr: 用户态CPU
# %sys: 内核态CPU
# %iowait: I/O等待
# %soft: 软中断
%sys偏高(超过20%)通常指向系统调用频繁或锁竞争。%iowait偏高指向磁盘瓶颈。%soft偏高指向网络中断过载,可考虑调整网卡中断亲和性或开启RPS/RFS。
对于Java应用,%sys偏高时抓取线程栈分析锁竞争:
# 导出Java线程栈
jstack $(pgrep -f 'java.*app') > /tmp/thread_dump.txt
# 统计BLOCKED状态线程
grep "java.lang.Thread.State" /tmp/thread_dump.txt | sort | uniq -c | sort -rn
BLOCKED线程数量异常时,需检查同步代码块范围是否过大,或是否存在死锁。使用async-profiler生成火焰图可直观定位CPU热点方法。
内存泄漏与OOM排查实战
进程内存持续增长但不释放是典型的内存泄漏。排查流程:
# 监控进程RSS变化
while true; do
pid=$(pgrep -f 'java.*app')
rss=$(cat /proc/$pid/status | grep VmRSS | awk '{print $2}')
echo "$(date '+%H:%M:%S') RSS: ${rss}KB"
sleep 30
done
# 查看系统内存分配概况
cat /proc/meminfo | grep -E "MemFree|MemAvailable|Slab|SUnreclaim"
# 查看进程内存映射中最大的匿名映射
cat /proc/$pid/smaps_rollup
# 详细查看各内存段占用
cat /proc/$pid/smaps | awk '/^[0-9a-f]/{seg=$1} /Rss:/{print seg, $2}' | sort -k2 -rn | head -10
当RSS持续单调增长且不随GC回落时,基本可判定为内存泄漏。对于Java应用,使用jcmd生成堆dump:
# 触发GC后立即dump
jcmd $(pgrep -f 'java.*app') GC.run
sleep 5
jcmd $(pgrep -f 'java.*app') Dump.heap /tmp/heap_dump.hprof
# 使用MAT (Memory Analyzer Tool) 分析
# 重点关注: Dominator Tree, Leak Suspects Report
# 常见泄漏模式:
# - HashMap作为缓存未设置过期和容量上限
# - ThreadLocal未remove导致线程池复用时泄漏
# - 静态集合持续持有对象引用
磁盘I/O问题诊断与优化
磁盘I/O问题常表现为系统响应缓慢、日志写入延迟。诊断工具链:
# iostat查看各磁盘I/O指标
iostat -dxm 1 5
# 重点关注:
# %util > 80%: 磁盘接近饱和
# await > 20ms (SSD) / > 50ms (HDD): 响应延迟高
# r/s + w/s: 当前IOPS
# iotop定位I/O最高的进程
iotop -oP -d 1
# 查看进程正在读写的文件
lsof -p $(pgrep -f 'java.*app') | grep -E "REG|DIR" | awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
%util持续80%以上时,优化方向包括:将随机写转为顺序写(日志框架批量刷盘)、使用IO调度器调整(deadline适用于SSD,cfq适用于HDD)、将热点数据迁移到SSD或内存。对于数据库场景,调整innodb_flush_method为O_DIRECT可绕过page cache减少双缓冲开销。
网络栈调优与丢包分析
高并发场景下的网络丢包和重传问题容易被忽略。排查链路:
# 查看网卡统计信息,关注drop和error
ethtool -S eth0 | grep -E "drop|error|discard"
# 查看TCP协议栈统计
ss -s
netstat -s | grep -E "overflow|drop|reset|retrans"
# 查看网卡队列和中断分布
cat /proc/interrupts | grep eth0
# 查看socket buffer配置
sysctl net.core.rmem_max net.core.wmem_max net.core.netdev_max_backlog
rx_dropped或tx_dropped持续增长时,常见原因及对策:网卡队列满(增大netdev_max_backlog)、应用处理慢导致socket buffer满(增大rmem_max/wmem_max)、CPU软中断处理不过来(开启RPS将软中断分散到多核)。调整示例:
# 增大socket buffer
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.core.netdev_max_backlog=5000
# 开启RPS(假设16核CPU)
for i in /sys/class/net/eth0/queues/rx-*/rps_cpus; do
echo ffff > $i
done
# 持久化配置写入/etc/sysctl.d/99-network-tune.conf
调整后持续监控retrans率变化,retrans持续高于1%时还需检查MTU设置和中间网络设备是否有丢包。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-gao-fu-zai-gu-zhang-pai-cha-shi-zhan-cong/