服务器CPU占用率高,核心原因集中在流量突增、慢SQL与程序死循环、资源争抢以及硬件故障这几类,其中应用层问题占绝大多数。
流量突增与并发压力:最直接但最容易被误判的原因
服务器CPU高,第一个要排查的就是流量,很多人一看到CPU飙到90%以上,第一反应是“被攻击了”,但实际业务场景里,促销活动、热点事件、爬虫抓取都可能带来数倍于平时的请求量,这不是故障,而是业务增长的表现。
如何区分正常流量和异常流量
正常流量通常有规律,比如白天高、凌晨低,周末比工作日高,异常流量则表现为瞬时暴涨、来源分散、请求路径单一。
- 查看Nginx或负载均衡的访问日志,统计每秒请求数QPS
- 用
netstat -an | grep :80 | wc -l查看当前连接数 - 对比前一天同一时段的CPU曲线,如果形态相似只是数值更高,大概率是正常流量
如果确认是正常流量,解决方案是扩容或限流,云服务器可以临时升级配置,或者开启CDN分担静态资源压力,如果是爬虫,用WAF拦截UA特征,或者在Nginx层配置IP限速。
并发连接数过高导致CPU耗尽
即使QPS不高,如果每个请求的响应时间很长,并发连接数也会堆积,比如一个请求需要3秒才能返回,每个连接占用一个PHP-FPM进程,那么100个并发就能吃掉全部CPU资源。
这里有个容易被忽略的点:Keep-Alive超时时间设置过长,默认75秒,如果客户端复用连接不活跃,服务器也要维持这个连接,大量空闲连接会占用进程和内存,间接推高CPU。
慢SQL与数据库查询:CPU高的头号内鬼
行业共识认为,数据库慢查询是服务器CPU居高不下的最常见原因,尤其是MySQL,一条没走索引的全表扫描,能把单核CPU跑满几十秒。
定位慢SQL的实操步骤
- 开启慢查询日志:在my.cnf中设置
slow_query_log=ON
和
long_query_time=2 - 使用
mysqldumpslow -s at /var/log/mysql/slow.log按平均执行时间排序 - 对排在最前的SQL执行
EXPLAIN,重点看type列和rows列
type列如果是ALL(全表扫描)或index(全索引扫描),说明索引失效,rows列数值越大,扫描行数越多,CPU消耗越高。
常见慢SQL模式
- SELECT 查大表,传输大量无用字段
- 在WHERE条件中对索引列使用函数,比如
WHERE DATE(create_time)='2026-01-01',会导致索引失效 - JOIN关联表过多,且关联字段没有索引
- 分页深度过大,比如
LIMIT 100000, 20,需要扫描前10万行再丢弃
优化思路也很直接:给WHERE和JOIN字段加索引,避免使用函数包裹索引列,用覆盖索引替代回表查询,对于分页,可以记录上一页的最大ID,用WHERE id > ? LIMIT 20代替深分页。
程序代码问题:死循环、内存泄漏与GC频繁
这部分最考验运维和开发的经验,代码层面的问题,往往隐藏得很深,不会像慢SQL那样有明确的日志。
死循环和空转逻辑
最典型的是while循环里没有退出条件,或者条件永远不会满足,比如有一个定时任务,每5秒执行一次,但任务内部有个bug导致重复处理相同的数据,CPU会以肉眼可见的速度飙升。
排查方法:
- 使用
top查看CPU占用最高的进程PID - 执行
top -Hp PID查看这个进程下的线程ID - 将线程ID转为十六进制,用
jstack(Java)或gdb(C/C++)抓取线程栈
如果发现同一代码位置的线程大量堆积,基本就能锁定死循环,Python环境则用py-spy dump --pid PID直接输出调用栈。
垃圾回收导致的CPU飙升
Java和Go这类带GC的语言,内存分配过快会导致频繁触发垃圾回收,GC本身需要CPU,尤其是Full GC阶段,会STW(停止工作线程),表现就是CPU占用高且应用响应变慢。

判断方法:在Java应用中,用jstat -gcutil PID 1000观察FGC(Full GC次数)和FGCT(Full GC耗时),如果FGC在1秒内增长超过一次,基本可以确定是GC压力过大。
根本原因是内存里生成了大量短生命周期对象,比如在for循环里拼接字符串用String +=而不是StringBuilder,或者反复读取大文件不释放流,优化代码后,GC频率会明显下降,同时可以调整堆内存参数,比如设置-Xmx为物理内存的50%-70%,避免内存过小导致频繁Full GC。
硬件与虚拟化瓶颈:当物理资源本身成为短板
排除应用问题后,还要看底层硬件的表现。磁盘I/O等待(iowait)过高会连累CPU,因为CPU在等待磁盘数据时不能做其他事情,整体吞吐量下降,看似CPU忙,实际大部分时间在空转。
磁盘I/O和内存Swap的影响
- 内存不足触发Swap,交换分区读写速度远低于内存,会大量占用CPU的wait状态
- 磁盘损坏导致的频繁重试,会让iowait持续走高
- 云服务器的宿主机超卖严重,导致CPU steal(被虚拟机管理器偷走的时间片)超过10%
排查命令:vmstat 1观察wa列和si/so列,如果wa长期大于20%,考虑升级SSD或增加内存,如果st列大于10%,说明云服务商超卖,需要换性能更强的实例类型。
单线程性能受限
老一代CPU主频低,单核性能弱,有些应用是单线程架构,比如Redis,即使8核服务器,也只能用1个核,这时候CPU总利用率看起来不高(比如12.5%),但实际那个核已经满载,导致Redis延迟变大。
解决方案是使用Redis Cluster开启多实例,或者把绑定CPU的核心设置到高性能核心上,物理服务器可以在BIOS中关闭节能模式,云服务器则选择新代次CPU的实例规格。
操作系统与中间件配置陷阱:常见但容易被忽略

有时候不是应用有问题,而是系统层面的默认配置不适合当前场景。
上下文切换过频繁
一个进程有大量线程,但CPU核数有限,线程之间频繁切换会消耗CPU,这种现象在线程池设置过大时非常常见,比如Tomcat的maxThreads默认200,如果并发只有50,依然会创建200个线程待命,每个线程都要参与调度。
查看上下文切换:vmstat 1观察cs列,如果持续在几十万以上,说明线程数过多,建议根据实际QPS调整线程池,比如Tomcat设置为maxThreads="150",更合理的是使用缓冲队列限制并发。
日志写入量过大
代码里打了大量debug日志,或者日志级别设置不合理,每次请求输出几十行日志。磁盘写日志本身就是I/O操作,还要同步到日志系统,这在低配服务器上会消耗可观的CPU,生产环境应该开启WARN级别,同时用异步日志框架,比如Log4j2的AsyncAppender。
Q&A:关键词“服务器cpu高主要是什么导致的”延伸解答
问:服务器CPU高到多少算异常?是超过70%就需要处理吗?
不能用固定数值定义,先看基线,如果平时只有10%,突然到50%就可能有问题;如果一直稳定在70%,只要响应时间正常,就不用紧张。重点是观察变化趋势和响应时间,而不是绝对值。
问:排查服务器CPU高应该先看哪里?
先用uptime看负载平均值,再用top定位进程,然后用pidstat或perf分析进程内部,整个过程按“流量→数据库→应用代码→硬件”的顺序排查,最快能定位到问题。
问:服务器CPU高会导致网站打不开吗?
会,CPU接近100%时,进程无法及时处理请求,连接超时,服务器为了自我保护会拒绝新连接,数据库服务器CPU高时,前端应用等待数据库响应,同样表现出页面卡顿或502错误,CPU高本身不是宕机原因,但引发的连锁反应会让服务不可用。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/806745.html

