如何排查CPU占用过高

0 前言

参考这篇文章

在程序运行过程中,CPU 占用率过高是一个不容忽视的问题,它就像程序性能的 “绊脚石”,可能引发程序响应迟缓、系统卡顿甚至崩溃等严重后果。比如,在一个高并发的在线交易系统里,若 CPU 占用率持续居高不下,用户进行交易操作时,页面加载时间会大幅延长,甚至出现交易失败的情况,极大地影响用户体验与业务开展。

1 不同场景

当系统出现 “CPU 占用高” 的问题时,本质是 CPU 的 “时间分配” 出现了异常 —— 某类任务(用户态程序、内核操作、I/O 等待、中断处理等)占用了过多的 CPU 时间,导致其他任务响应变慢。结合前面提到的 CPU 使用率分类,我们可以针对性地分析原因、排查问题并优化。

1.1 用户态 CPU 使用率(user)过高:应用程序自身 “太忙”

核心原因

用户态 CPU 高,说明应用程序在用户态执行的代码(如业务逻辑、计算、函数调用等)占用了大量 CPU 时间。常见场景:

  1. 计算密集型任务:如大数据处理、加密解密、复杂数学运算(如 AI 模型推理)等,代码中存在大量循环或高复杂度逻辑。
  2. 低效代码:如频繁创建销毁对象(导致 GC 频繁)、无意义的空循环、重复计算等。
  3. 并发失控:多线程 / 进程过度竞争 CPU,导致大量时间浪费在 “抢 CPU” 而非实际工作(如线程池过大)。

排查工具

  1. top/htop:查看进程的%CPU,定位到占用高的具体进程(如 Java 进程、C++ 程序)。
  2. pidstat -u 1:更精确地观察单个进程的用户态 CPU 占比(%usr)。
  3. perf(Linux 性能分析工具):通过perf record -g -p <进程ID>记录进程的函数调用栈,生成报告后查看 “热点函数”(耗时最多的函数),定位具体代码段。
  4. jstack/gdb:对 Java 程序用 jstack 查看线程栈,对 C++ 程序用 gdb 查看调用栈,分析线程是否在做 “无效工作”(如死循环、锁竞争)。

优化思路

  1. 优化代码逻辑:简化计算步骤(如用查表替代实时计算)、减少重复操作(如缓存中间结果)。
  2. 控制并发数:根据 CPU 核心数调整线程池大小(如线程数≈CPU 核心数,避免过度竞争)。
  3. 异步化处理:将非关键路径的任务(如日志打印、统计上报)异步执行,避免阻塞主线程。

1.2 内核态 CPU 使用率(system)过高:内核 “太忙”

核心原因

内核态 CPU 高,说明应用程序频繁触发内核操作(如系统调用),或内核自身任务(如进程调度、内存管理)过重。常见场景:

  1. 频繁系统调用:应用程序频繁执行需要切换到内核态的操作,如频繁读写小文件(read/write)、频繁创建销毁进程 / 线程(fork/clone)、频繁网络收发(send/recv)等。
  2. 内核模块异常:如驱动程序 bug(如无限循环)、内核参数配置不合理(如进程调度策略不当)。
  3. 锁竞争:多进程 / 线程竞争内核资源(如全局锁、文件锁),导致内核频繁进行 “锁争夺” 的调度。

排查工具

  1. top:观察%system占比,确认内核态是否过高。
  2. strace -p <进程 ID>:跟踪进程的系统调用,查看是否有频繁重复的调用(如每秒几千次open/close)。
  3. vmstat:查看sys列(每秒系统调用次数),若数值过高(如超过 10 万),说明系统调用频繁。
  4. dmesg:查看内核日志,排查是否有驱动错误(如BUG、Oops)。

优化思路

  1. 减少系统调用次数:例如,将多次小文件读写合并为一次大文件读写,用缓冲 IO(如fread/fwrite)替代直接系统调用(read/write)。
  2. 优化内核配置:如调整进程调度策略(如对实时性要求高的程序用SCHED_FIFO)、关闭不必要的内核模块。
  3. 避免内核锁竞争:如减少多进程对同一文件的并发写(改用单进程写 + 多进程读)。

1.3 I/O 等待(iowait)过高:CPU“等 I/O” 的时间太长

核心原因
iowait 高不代表 CPU “忙”,而是 CPU“闲得没事干,在等 I/O 操作完成”。本质是I/O 设备(磁盘、网络、外设)速度跟不上 CPU 的需求。常见场景:

  1. 磁盘 I/O 瓶颈:机械硬盘(HDD)读写慢,若程序频繁读写大文件或随机读写(如数据库频繁刷盘),会导致 CPU 等待磁盘响应。
  2. 网络 I/O 瓶颈:网络带宽不足(如服务器被大量请求打满)、远程服务响应慢(如调用外部 API 超时),导致 CPU 等待网络数据。
  3. I/O 请求无序:如频繁随机读写小文件(机械盘随机读写性能差),或 I/O 调度算法不合理(如默认的cfq对数据库场景不友好)。

排查工具

  1. iostat -x 1:查看磁盘 I/O 状态,%util(磁盘利用率)接近 100% 说明磁盘忙;await(平均 I/O 等待时间)过高(如超过 50ms)说明磁盘响应慢。
  2. iftop:查看网络流量,若带宽接近上限(如 1G 网卡跑满 1Gbps),说明网络瓶颈。
  3. pidstat -d 1:查看进程的 I/O 情况(如kB_read/s、kB_wrtn),定位到频繁读写的进程。

优化思路

  1. 升级 I/O 设备:用 SSD 替代机械盘(随机读写性能提升 10 倍以上),或用 NVMe SSD 进一步提升磁盘速度。
  2. 优化 I/O 模式:
  3. 批量读写:将多次小 I/O 合并为一次大 I/O(如数据库开启write buffer,积累到一定量再刷盘);
  4. 顺序读写替代随机读写:如日志文件按顺序追加,避免随机修改。
  5. 增加缓存:用内存缓存(如 Redis)减少磁盘 / 网络 I/O(如缓存热点数据,避免重复查询数据库)。

1.4 软硬中断 CPU 使用率过高:“突发事件” 太多,CPU 被频繁打断

中断是 CPU 处理 “突发事件” 的机制(硬件触发为硬中断,软件触发为软中断)。中断过高说明系统在处理大量 “突发事件”,导致正常任务被频繁打断。

核心原因

  1. 硬中断高:硬件设备频繁触发中断,如磁盘控制器(频繁读写导致中断)、网络适配器(大量数据包涌入)、定时器(高频时钟中断)。
  2. 软中断高:软件层面的异步事件过多,如网络协议栈处理大量数据包(如 TCP/UDP 报文)、内核定时器到期(如进程调度、监控指标采集)。

排查工具

  1. vmstat:in列表示每秒硬中断次数(正常系统通常几百到几千,异常时可达数万);cs(上下文切换)过高(如超过 10 万 / 秒)可能与中断相关。
  2. cat /proc/interrupts:查看各中断源的次数(如网络适配器eth0的中断次数是否激增)。
  3. iftop/tcpdump:若软中断高,优先检查网络流量(如是否遭遇 DDOS 攻击,导致大量无用数据包)。

优化思路

  1. 网络中断优化:
  • 开启网卡 “中断合并”(如ethtool -C eth0 rx-usecs 100),减少小包导致的频繁中断;
  • 用多队列网卡(如eth0-0、eth0-1),将中断分散到多个 CPU 核心,避免单核心被打满。
  • 磁盘中断优化:调整磁盘调度算法(如deadline算法减少随机 I/O 的中断次数)。
  1. 减少无效中断:过滤恶意网络流量(如防火墙拦截 DDOS),减少不必要的定时器(如降低非关键监控的频率)。

2 总结:CPU 高占用的排查流程

  1. 先用top观察 CPU 使用率的分布(user/system/iowait/hi/si),确定问题类型;定位进程
  2. 针对具体类型,用专项工具定位细节(如perf查用户态函数,strace查系统调用,iostat查 I/O);
  3. 结合业务逻辑优化(如减少计算、合并 I/O、控制中断)。

本质上,CPU 高占用是 “任务需求” 超过 “CPU 处理能力” 的表现,要么降低需求(优化任务),要么提升能力(扩容 CPU / 优化硬件)。

posted @ 2025-08-12 10:59  wenli7363  阅读(345)  评论(0)    收藏  举报