首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Linux 系统性能调优:CPU、内存、IO 瓶颈分析方法(草履虫版)

Linux 系统性能调优:CPU、内存、IO 瓶颈分析方法(草履虫版)

作者头像
IT运维技术圈
发布2025-08-11 10:42:08
发布2025-08-11 10:42:08
71800
代码可运行
举报
文章被收录于专栏:IT运维技术圈IT运维技术圈
运行总次数:0
代码可运行

0. 写在前面:为什么你需要“神器”而非“常用命令

把系统从「慢」变成「稳」有时候不需要大折腾,而是把最显著的瓶颈找出来。下面是一套我常用的方法.


先说一句话的心法:先把用户感受恢复,再去追根溯源。很多时候临时的减害手段(降级、限流、回滚、切流)比立刻找根因更重要。下面分三类瓶颈:CPU、内存、IO(含磁盘与网络),每类给出诊断命令、常见判别依据、应急缓解和长期修复建议。


常用工具速览(先熟悉这些工具)

这些命令几乎是现场救火的工具箱,建议熟练掌握:

代码语言:javascript
代码运行次数:0
运行
复制
top, htop, vmstat, mpstat, pidstat, ps, perf, strace, pstack
free, slabtop, smem
iostat, iotop, blktrace, lsblk, df, du, smartctl
ss, netstat, iftop, iperf3, tc
sar (sysstat), dstat, atop
tcpdump (小心会产生日志)

我常把一台机器的检查脚本写成几行命令串,先快速跑一遍,得出第一轮结论,再深入。


一:CPU 瓶颈 — 如何判断与处理

诊断思路

看整体负载(load)只是起点,关键是区分:是用户态占满、内核态占满、还是等待 I/O(iowait)、或是被虚拟化的 steal(被抢占),再决定对症下药。

现场诊断命令(顺序执行,快速采样)

代码语言:javascript
代码运行次数:0
运行
复制
# 1) 快速看系统负载与总体 CPU 使用
$ top -b -n1 | head -n5
top - 11:30:00 up 12 days,  2:01,  1 user,  load average: 12.34, 11.98, 10.12
%Cpu(s): 92.0 us,  3.0 sy,  0.0 ni,  2.0 id,  3.0 wa

# 2) 更细:每个 CPU 的使用(查看是否存在核不均衡)
$ mpstat -P ALL 1 1
Linux 5.4.0 (host)  08/10/2025  _x86_64_  (8 CPU)
08:30:01 AM  CPU  %usr  %nice  %sys  %iowait  %irq  %soft  %steal  %guest  %idle
08:30:01 AM  all   92.0   0.00   3.0    3.0      0.0   0.0     0.0      0.0    2.0
08:30:01 AM    0   99.0    0.0   0.0    0.0      0.0   0.0     0.0      0.0    1.0
08:30:01 AM    1   85.0    0.0   6.0    0.0      0.0   0.0     0.0      0.0    9.0
...

# 3) 找出占用最严重的进程
$ ps aux --sort=-%cpu | head -n 8
root  23456  95.0  1.2 123456 78900 ?  R  11:29   120:00 /usr/bin/myapp --worker

判别

  • %usr 高,且某个进程占比高 → 进程计算密集(业务逻辑/算法);
  • %sys 高 → 内核开销高(例如频繁上下文切换、网络/磁盘中断);
  • %iowait 高 → 可能是 IO 瓶颈(继续看 IO 部分);
  • %steal 高 → 虚拟化宿主被抢占(云主机需联系云厂商或扩容)。

应急缓解(先恢复服务可用性)

  1. 1. 临时降级或限流:在流量入口(Nginx、LB)做限流或返回降级页面,果断减少负载。
  2. 2. 迁移/扩容:把部分实例从流量池摘除、扩容实例数或增加容器副本(Kubernetes):
代码语言:javascript
代码运行次数:0
运行
复制
# k8s 临时扩副本
$ kubectl scale deployment myapp --replicas=10 -n prod
deployment.apps/myapp scaled
  1. 3. 进程优先级调整/隔离:对非关键进程 renice 或把关键进程绑定到空闲核 taskset
代码语言:javascript
代码运行次数:0
运行
复制
# 优先级调低(nice 值增大)
$ sudo renice +10 -p 23456
# 把进程绑定到 CPU 2 和 3
$ sudo taskset -cp 2,3 23456

示例输出(模拟):

代码语言:javascript
代码运行次数:0
运行
复制
$ sudo renice +10 -p 23456
23456 (process id) old priority 0, new priority 10

深入修复(事后优化)

  • • 对热点函数进行剖面分析(perf record / perf report / FlameGraph),找到热点后优化算法或改为异步处理;
  • • 如果是大量系统调用/上下文切换,检查线程模型、减少锁争用或使用更合适的数据结构;
  • • 用 CPU 亲和性(cpuset)把关键服务放到独立核,避免干扰;
  • • 对延迟敏感服务,使用实时调度(谨慎)或内核参数微调。

perf 快速示例(采样 10s)

代码语言:javascript
代码运行次数:0
运行
复制
# 需要 root,示例模拟命令
$ sudo perf record -F 99 -p 23456 -g -- sleep 10
$ sudo perf report --stdio | head -n 20
# 输出会显示最耗时的函数栈,便于定位

二:内存瓶颈 — 如何判断与处理

诊断思路

内存问题分两类:一是内存不足导致频繁 swap(影响响应),二是内存泄露使某服务占用持续增长。判断依据:freevmstatslabtopps

现场诊断命令

代码语言:javascript
代码运行次数:0
运行
复制
# 1) 总览内存状态
$ free -m
              total        used        free      shared  buff/cache   available
Mem:          32768       25000        1024         123        5744        7000
Swap:         8192         512        7680

# 2) 观察短期页活动
$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 4  0  524288  102400  52480  300000  10   0  1024   128 3000  1000 60 30  5  5 0
...

# 3) 哪个进程占内存
$ ps aux --sort=-rss | head -n 10
appuser  34567  0.1 45.0  1234567 1500000 ? Sl  11:00  300:12 /usr/bin/myapp

# 4) slab 缓存检查(内核对象)
$ sudo slabtop -o
 Active / Total Objects:  123456 / 234567
  OBJS ACTIVE  USE OBJ SIZE  SLABS SIZE  CACHE NAME
  10240   5120   50%     64     80K     8192 kmalloc-64
...

判别

  • available 很低且 swpd 不为 0 → 发生交换(swap);
  • • 单个进程长期增长 → 内存泄露或长时间缓存;
  • • slabtop 显示某一类对象异常多 → 内核层面问题(例如大量 socket、inode 未释放)。

紧急缓解(非破坏性优先)

  1. 1. 短期释放 pagecache(谨慎,仅在确定为缓存占用且内存紧张时):
代码语言:javascript
代码运行次数:0
运行
复制
# 释放 pagecache
$ sudo sync; echo 1 | sudo tee /proc/sys/vm/drop_caches
1

小心:这会清空文件系统缓存,会影响 IO 性能,建议在低峰或先预警。

  1. 2. 调整 swappiness 临时时间窗口降低 swap 倾向:
代码语言:javascript
代码运行次数:0
运行
复制
$ sudo sysctl vm.swappiness=10
vm.swappiness = 10
  1. 3. 重启或重建进程:对泄露严重的服务先重启(注意要有 graceful 下线流程或在负载均衡中下线实例)。
  2. 4. 通过 OOM 策略保护关键进程:调整 oom_score_adj,防止关键进程被 OOM 杀死:
代码语言:javascript
代码运行次数:0
运行
复制
# 给 critical pid 设置 oom_score_adj 为 -1000
$ echo -1000 | sudo tee /proc/34567/oom_score_adj

示例输出(模拟):

代码语言:javascript
代码运行次数:0
运行
复制
$ sudo sysctl vm.swappiness=10
vm.swappiness = 10

深入定位(内存泄露诊断)

  • • 对 C/C++ 服务用 gdb/valgrind/heaptrack 做内存跟踪;
  • • 对 Java 用 jmap / jstack / heap dump 分析;
  • • 对 Go 服务用 pprof(net/http/pprof)做 heap profile。

Go pprof 示例如下(采样与生成报告)

代码语言:javascript
代码运行次数:0
运行
复制
# 在服务机器上采集 30s heap
$ curl http://127.0.0.1:6060/debug/pprof/heap > heap.out
# 使用 go tool pprof 进行分析
$ go tool pprof -svg ./myapp heap.out > heap.svg

三:磁盘 / IO 瓶颈 — 判断与解决

诊断思路

磁盘瓶颈通常表现为高 await、高 %util(iostat),或大量等待导致 CPU 的 iowait 上升。需要区分是单块盘饱和、文件系统元数据锁竞争,还是网络存储(NFS、iSCSI)问题。

常用诊断命令

代码语言:javascript
代码运行次数:0
运行
复制
# 1) 磁盘总体 IO 性能(查看 %util、await)
$ iostat -x 1 3
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm  %util
sda    0.00  0.00   0  100 0      102400  2048      12.34     45.67  0.00   45.67   2.00   95.00
# %util 近 100% 且 await 高 -> 磁盘成为瓶颈

# 2) 实时查看哪个进程在做最多 IO
$ sudo iotop -oPa --iter=3
Total DISK READ :       0.00 B/s | Total DISK WRITE : 512.00 K/s
PID PRIO USER     DISK READ  DISK WRITE  SWAPIN     IO> COMMAND
1234 be/4 appuser   0.00 B/s  512.00 K/s  0.00 %     0.00 % /usr/bin/myapp

# 3) 文件系统使用情况
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   45G  3.0G  94% /

# 4) 块队列长度(avgqu-sz)结合 %util 判断是否饱和
$ cat /sys/block/sda/stat
# 11个字段,通常看 avg queue depth 需用 iostat 更直观

判别

  • %util 高(> 80%)且 avgqu-sz 大 → 磁盘饱和;
  • await 高而 svctm 低 → 可能是队列过长或设备等待服务;
  • • iotop 指向某进程大量写入 → 是应用导致,还是日志/临时文件导致。

应急缓解

  1. 1. 减小写入压力:把日志等级调低、关闭不必要的持久化任务、临时把某些批处理调度到非高峰。
  2. 2. 迁移热点 IO:将热点目录迁移到另一块盘或更快的介质(NVMe、SSD),在文件系统允许下用 rsync 热迁移:
代码语言:javascript
代码运行次数:0
运行
复制
# 假设 /data 是热点目录,要迁移到 /mnt/fastdisk
$ rsync -aHAXv /data/ /mnt/fastdisk/data/
$ mount --bind /mnt/fastdisk/data /data
  1. 3. 调整 IO 调度器(对延迟敏感应用,选择 deadline 或 noop):
代码语言:javascript
代码运行次数:0
运行
复制
# 查看当前调度器
$ cat /sys/block/sda/queue/scheduler
noop [deadline] cfq

# 切换为 deadline
$ echo deadline | sudo tee /sys/block/sda/queue/scheduler
deadline

模拟输出:

代码语言:javascript
代码运行次数:0
运行
复制
$ echo deadline | sudo tee /sys/block/sda/queue/scheduler
deadline
  1. 4. 临时开启更多副本或读写分离:如果是数据库写满盘,优先把写请求限制并把读请求迁移到只读副本。

深入修复(长期)

  • • 升级到更快存储,使用 RAID 0/10 或 NVMe,按成本与可靠性权衡;
  • • 对数据库做分库分表、写入合并或异步化,减少同步写;
  • • 在文件系统层面调优 mount 选项,例如 noatime、合理调整 journaling(ext4 的 commit 值);
  • • 对 SSD 做定期 TRIM:fstrim -v /

四:网络 IO 瓶颈 — 诊断与缓解

网络问题会表现为延迟、丢包或吞吐率受限。检查顺序:链路(链路丢包/延迟)→ 本机网络栈(SOCKET 队列、tc 策略)→ 应用层(连接泄露)。

命令与示例

代码语言:javascript
代码运行次数:0
运行
复制
# 基本连通/延迟
$ ping -c 4 10.0.0.10
PING 10.0.0.10 (10.0.0.10): 56 data bytes
64 bytes from 10.0.0.10: icmp_seq=1 ttl=64 time=1.23 ms
...
# TCP 层面连接问题
$ ss -s
Total: 123 (kernel 456)
TCP:   789 (estab 100, closed 200, orphaned 0, timewait 50)
# 查看端口连接详情
$ ss -tn state established '( dport = :3306 or sport = :3306 )'

缓解

  • • 对客户端连接数量暴增,使用 tc/iptables 做限速或连接数限制;
  • • 检查并增大 socket 缓冲区:sysctl -w net.core.rmem_max=...
  • • 若网络链路受限,联系网络团队或按需做流量剖分、QoS。

五:容器 / 虚拟化层面注意点

容器环境下,很多性能问题来源于资源配额不当或 cgroup 限制:

  • • 检查容器的 CPU/Memory requests & limits(Kubernetes):
代码语言:javascript
代码运行次数:0
运行
复制
$ kubectl describe pod mypod -n prod
  • • 容器被 OOMKilled 要看事件和 kubectl logs --previous
  • • 虚拟化(云)出现 %steal 高,请联系云厂商或考虑换实例规格。

六:快速排查清单(现场小抄)

在现场我常用的一套顺序(在 1–3 分钟内跑完):

代码语言:javascript
代码运行次数:0
运行
复制
# 系统总体
top -b -n1 | head -n20
free -m
vmstat 1 5
iostat -x 1 3
df -h

# 进程级别
ps aux --sort=-%cpu | head
ps aux --sort=-%mem | head

# 网络
ss -s
ss -tn state established

# 容器 / k8s
kubectl get pods -A
kubectl top nodes

把这些输出截图/保存到事件工单中,便于后续复盘与分析。


七:现场快速缓解模板(可复制)

1)对 CPU 峰值,临时扩容(Kubernetes)

代码语言:javascript
代码运行次数:0
运行
复制
kubectl scale deployment myapp --replicas=10 -n prod

2)对内存泄露,优雅下线并重启单实例

代码语言:javascript
代码运行次数:0
运行
复制
kubectl drain node/node-1 --ignore-daemonsets --delete-local-data
systemctl restart myapp.service

3)对磁盘写满,归档并释放日志

代码语言:javascript
代码运行次数:0
运行
复制
sudo mv /var/log/app.log /var/log/app.log.$(date +%F-%H%M)
sudo gzip /var/log/app.log.$(date +%F-%H%M)
sudo systemctl restart rsyslog

这些操作都有风险,执行前请确认变更窗口与回滚路径。


八:长期稳固策略(把临时救火变成可控)

  • 监控与告警:把 CPU/Memory/IO/网络关键指标纳入监控并设置合理阈值;关键阈值触发自动化脚本或工单。
  • 容量规划 & 压测:做持续的负载测试,找到系统的实际瓶颈并预留余量。
  • 服务分层 & 异步化:把耗时或不必要的同步调用改为异步,增加缓冲/队列(Kafka、RabbitMQ)。
  • 资源限制与 QoS:在容器平台上使用 requests/limits,避免小服务对大服务的「内耗」。
  • 定期剖析:把 perf、pprof、heap dumps 写入常规的 SRE 周期任务,发现隐匿问题。
  • 演练:故障演练要常态化,演练会暴露监控盲区与恢复流程的缺陷。

九:常见误区(我见过的“坑”)

  • • 盲目扩容:遇到问题第一反应是加机器,但如果根因是单进程锁或 DB 限制,扩容只是浪费。
  • • 频繁 drop_caches:乱用 drop_caches 会把缓存击穿,短期内看似缓解,长期反而伤性能。
  • • 忽略后端依赖:很多“应用慢”其实是依赖(DB、外部 API)慢,优化前端并不能从根本上解决问题。
  • • 只看 top:top 很直观,但容易误导;结合 iostat、vmstat、mpstat 才能分清 CPU/IO/内存的责任。

十:现场演练后的记录模板(务必填写)

每次事件结束后,请在工单里补全:

  • • 事件时间线:发生 → 发现 → 应急措施 → 恢复;
  • • 快速截图与关键命令输出(保存到工单附件);
  • • 根因分析结论与后续计划(谁、何时、如何修复);
  • • 是否需要变更 CI/CD、监控告警或自动化脚本。

结尾话

性能调优不是一次性的魔法,而是一种持续的工程:不断观察、不断剖析、不断改进。现场救火要快要稳,事后修复要彻底。你会发现,很多问题经过一次完整的定位与修复后,就再也不会重复抓你;这正是把“偶发事故”变成“可控变更”的意义。

老杨时间

这里我先声明一下,日常生活中大家都叫我波哥,跟辈分没关系,主要是岁数大了.就一个代称而已. 我的00后小同事我喊都是带哥的.张哥,李哥的. 但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适. 比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“ 这个氛围配这个称呼在互联网这行来讲就有点对不齐! 每次遇到这个情况我就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.我干了,你们随意!” 所以以后咱们改叫老杨,即市井又低调.还挺亲切,我觉得挺好.

运维X档案系列文章:

从告警到CTO:一个P0故障的11小时生死时速

企业级 Kubernetes 集群安全加固全攻略( 附带一键检查脚本)

老杨的关于AI的号

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT运维技术圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 常用工具速览(先熟悉这些工具)
  • 一:CPU 瓶颈 — 如何判断与处理
    • 诊断思路
    • 现场诊断命令(顺序执行,快速采样)
    • 应急缓解(先恢复服务可用性)
    • 深入修复(事后优化)
  • 二:内存瓶颈 — 如何判断与处理
    • 诊断思路
    • 现场诊断命令
    • 紧急缓解(非破坏性优先)
    • 深入定位(内存泄露诊断)
  • 三:磁盘 / IO 瓶颈 — 判断与解决
    • 诊断思路
    • 常用诊断命令
    • 应急缓解
    • 深入修复(长期)
  • 四:网络 IO 瓶颈 — 诊断与缓解
    • 命令与示例
  • 五:容器 / 虚拟化层面注意点
  • 六:快速排查清单(现场小抄)
  • 七:现场快速缓解模板(可复制)
  • 八:长期稳固策略(把临时救火变成可控)
  • 九:常见误区(我见过的“坑”)
  • 十:现场演练后的记录模板(务必填写)
  • 结尾话
  • 老杨时间
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档