Linux服务器高负载故障排查实战:从CPU到网络栈的完整诊断链路

服务器在高负载运行中可能出现性能骤降、进程异常退出、系统无响应等问题。定位这类问题需要一套系统化的排查流程,从硬件层到内核层逐层排除。本文以一台实际生产环境中出现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/

(0)
小编小编
上一篇 18小时前
下一篇 18小时前

相关推荐