面试官:线上cpu飙升至100%的时候怎么处理?

1,404 阅读3分钟

当 CPU 使用率突然飙升至 100% 时,需快速定位原因并解决。以下是 ​分步排查方法 和 ​应急处理方案,适用于 Linux/Unix 系统:


一、快速定位 CPU 瓶颈

1. 定位高 CPU 进程

# 实时查看进程 CPU 占用(按 %CPU 排序)
top
# 或使用更直观的 htop(需安装)
htop

# 快速过滤高 CPU 进程(示例:显示前5个)
ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -n 6

2. 分析进程内的线程

# 查看指定进程的线程 CPU 占用(替换 PID)
top -H -p <PID> 
# 或使用 ps 按线程查看
ps -T -p <PID> -o tid,pcpu,cmd

3. 生成线程堆栈(Java 应用专用)​

# 生成线程转储(需 JDK)
jstack <PID> > jstack.log

# 结合 top 找到的高 CPU 线程 ID(转成16进制)
printf "%x\n" <TID>  # 输出如 1b3e
# 在 jstack.log 中搜索 "nid=0x1b3e" 定位线程代码

二、常见原因及应急处理

1. 代码死循环或低效算法

  • 现象:某个线程长期占用 CPU。

  • 解决

    1. 通过 jstack 或 gdb 分析线程堆栈,定位代码位置。
    2. 重启服务或关闭问题接口(临时方案)。
    3. 优化算法(如避免嵌套循环、减少递归深度)。

2. 频繁 GC(Java 应用)​

  • 现象:GC 线程(如 Gang worker#0)占用高 CPU。

  • 验证

    # 查看 GC 统计
    jstat -gcutil <PID> 1000 10
    
  • 解决

    • 临时增大堆内存:-Xmx4g -Xms4g
    • 优化代码减少对象创建。

3. 锁竞争或死锁

  • 现象:线程状态为 BLOCKED 或 WAITING

  • 验证:通过 jstack 检查锁持有情况。

  • 解决

    • 优化锁粒度(如用读写锁替代独占锁)。
    • 重启服务临时恢复。

4. 外部攻击或异常流量

  • 现象:大量网络连接(如 ESTABLISHED 状态)。

  • 验证

    # 查看 TCP 连接数
    netstat -nat | awk '{print $6}' | sort | uniq -c
    # 或检查访问日志
    tail -f /var/log/nginx/access.log
    
  • 解决

    • 防火墙限流:iptables 或云平台安全组。
    • 使用 CDN 或 WAF 过滤恶意请求。

三、系统级排查工具

1. 系统负载监控

# 查看过去1/5/15分钟平均负载(应小于CPU核心数)
uptime
# 统计 CPU 上下文切换和中断
vmstat 1 5

2. 性能分析(Perf)​

# 安装 perf
apt-get install linux-tools-common
# 采样 CPU 热点函数(采样10秒)
perf record -F 99 -a -g -- sleep 10
perf report

3. 火焰图生成

# 下载 FlameGraph 工具
git clone https://github.com/brendangregg/FlameGraph.git
# 生成火焰图(需 perf 数据)
perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > flame.svg

四、临时缓解措施

  1. 限流降级:关闭非核心功能,减少 CPU 消耗。

  2. 重启服务:强制释放资源(可能丢失会话数据)。

  3. 调整优先级:降低问题进程的 CPU 优先级。

    renice -n 19 -p <PID>  # 优先级调整为最低(19)
    

五、预防与优化

  1. 监控告警:配置 Prometheus + Grafana 监控 CPU 和线程状态。
  2. 压测优化:定期进行压力测试,识别性能瓶颈。
  3. 代码审查:避免无限循环、未优化的正则表达式等。
  4. 资源隔离:使用容器(Docker)或 cgroups 限制进程资源。

案例:Java 应用正则表达式导致 CPU 100%

  • 现象:某线程持续运行 java.util.regex.Pattern
  • 排查jstack 发现线程在执行 Matcher.find()
  • 根因:低效的正则表达式(如贪婪匹配)。
  • 解决:优化正则表达式,或改用字符串解析。

通过以上步骤,可快速定位并解决 CPU 飙升问题。建议结合监控系统提前预防,并保留排查记录供后续分析。