ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux性能调优实战:从CPU负载到磁盘IO的排查与优化

Linux性能调优实战:从CPU负载到磁盘IO的排查与优化 简介围绕 Linux 性能调优整理的文档资料主要面向需要优化 Red Hat Enterprise Linux AS 与 SUSE LINUX Enterprise Server 运行效率的系统管理员和运维工程师。内容按关闭 daemons、关闭 GUI、改变内核参数、处理器子系统调优、内存子系统调优、文件系统调优、网络子系统调优等模块展开每部分均结合具体命令说明操作方法。例如用 service 或 init.d 停用后台服务用 chkconfig 关闭自启动用 runlevel 与 init 切换运行级别修改 /etc/sysctl.conf 或 /proc/sys/vm 下的参数调整内存与网络行为用 taskset 设置 CPU 亲和性用 nice、renice 管理进程优先级调整文件系统挂载选项和磁盘 I/O 调度器。资源为单份 docx 文档压缩包约 373KB方便在办公软件中阅读、检索和打印目前已有 238 人学习下载。文档同时提醒关闭 xfs daemon 可能影响 X 启动强调调整参数后应做基准测试避免过度优化能为排查性能瓶颈提供较为完整的参考路径。1. Linux性能调优从哪里下手先分清瓶颈再动手我处理过不少服务器卡顿的工单典型画面是业务方说接口超时我上去 top 一看CPU 利用率只有 12%load average 却已经飙到 18进程列表里挤着一串 D 状态。很多人遇到这种情况第一反应是加 CPU但 Linux 性能调优的核心从来不是把单个参数调到极限而是先用指标把瓶颈定位到 CPU、内存、磁盘、网络这四个维度之一再针对性地动手。下面按四条最常见的调优路径展开从 linux 常用命令怎么读到参数怎么改、改完怎么验证最后把我踩过的几个坑一并列出来。适合运维、后端开发以及做嵌入式 linux 系统的人照着排查。2. CPU与进程调度调优从top看负载到taskset绑核2.1 先读懂CPU指标load average、us/sy/wa/idtop 第一行的 load average 三个数字分别代表 1、5、15 分钟的平均负载。很多人把它当成 CPU 利用率其实它统计的是 R 状态正在运行和 D 状态不可中断睡眠通常是等待 IO进程数的总和。反过来CPU 利用率低不代表系统不忙负载高而 CPU 空闲时优先怀疑 D 状态进程在排队等磁盘或网络。top 进入后按数字 1 键能看到每个逻辑核独立的 us用户态、sy内核态、waIO 等待、id空闲四列。我一般按下面三条来判断wa 高先查磁盘 IO不是 CPU 问题sy 高重点看系统调用、锁竞争、中断处理别急着加核us 逼近 100%才算真正的算力瓶颈这时候才轮到 CPU 调优。配合 vmstat 看运行队列更直观。r 列是正在运行和等待 CPU 的进程数b 列是阻塞在 IO 上的进程数。r 长期大于逻辑核数说明 CPU 排队b 长期非零说明 IO 有问题。连续观察三次再下结论单次 top 快照经常被瞬时尖刺干扰。# 2秒刷新一次进入后按1展开每个逻辑核 top -d 2 # 每秒采样一次共5次重点看 r、b、us、sy、wa 五列 vmstat 1 5top 的 -d 2 表示刷新间隔为 2 秒连续观察比单次快照更能看出趋势vmstat 1 5 是每 1 秒采样一次、共输出 5 组数据。r 列的数值直接对应等待调度的任务数如果 r 长期是核数的好几倍说明用户态进程已经抢不到 CPU 时间片。如果所有系统指标正常但业务仍然卡顿再用 perf stat 或 strace 看应用内热点那已经属于应用层调优的范畴。什么时候才值得做 CPU 调优我的判断标准是us 稳定在 85% 以上、r 队列长期超过核数的 4 倍同时 vmstat 的 cs上下文切换列每秒几万次以上。这种组合说明进程在频繁切换中空转优先级和绑核才有明显收益。否则就算把 nice 调到底瓶颈还在别的维度属于白费劲。2.2 用nice/renice调整优先级命令行与systemd配置定位到 CPU 瓶颈后第一个能做的调优是调整进程优先级。运行队列里所有进程按优先级排队nice 值范围是 -20 到 19数值越小优先级越高普通用户只能调大降级调小需要 root。业务上最常见的用法是把备份、日志压缩、数据迁移这类慢就慢点的任务降优先级把数据库和网关进程的优先级适当提高这在实际的 mysql 性能调优场景里很常见。# 启动备份脚本并降低优先级 nice -n 10 ./backup.sh # 调整已经在跑的进程-5 表示提高优先级必须 root 执行 renice -n -5 -p $(pidof mysqld)nice -n 10 表示把进程的 CPU 调度优先级降到 10适合后台批量任务renice 则作用于运行中的进程$(pidof mysqld) 动态取进程号避免手动查 PID。注意一点不要为了更快把所有核心进程都调成负 nice优先级过高会导致系统响应异常极端情况下连 ssh 都连不上属于典型的翻车姿势。如果进程由 systemd 托管直接在单元文件里加调度参数更稳妥。在 [Service] 段下写 Nice10、CPUSchedulingPolicyrr再执行 systemctl daemon-reload 并重启服务效果和命令行一致而且重启后不会丢。云主机上还要注意 cgroup 的 cpu.weight 会在更高层级限流外层限制没放开时内核 nice 调整的效果会被削掉一截。调整完怎么确认生效用 ps 带格式参数看命令是 ps -o pid,pri,ni,comm -p 进程号ni 列变成目标值就说明生效。这里有个前提如果进程本身卡在 IO 等待上调高优先级不会让磁盘变快perf 记录里会看到处理器大部分时间在等待事件这种场景改 nice 没有任何意义。2.3 绑核与隔离taskset与isolcpus优先级只能解决竞争解决不了多个高负载进程互相抢占同一个核的问题。绑核是把进程固定到指定 CPU 上减少上下文切换和缓存抖动。对数据库实例、转发网关这类延迟敏感的服务我一般会单独留两个核给它。嵌入式 linux 设备上核数少绑核通常比调 nice 更直接。# 把 nginx 的 master 进程绑到 2、3 号核 taskset -c 2,3 nginx # 查某个进程当前绑在哪些核上 taskset -cp $(pidof nginx) # 内核启动参数做核隔离改 /etc/default/grub 中的 GRUB_CMDLINE_LINUX # 追加 isolcpus4,5 后执行 grub2-mkconfig -o /boot/grub2/grub.cfg 并重启taskset -c 2,3 是绑核命令表示进程只允许在 2 号和 3 号核上运行isolcpus4,5 是内核启动参数把 4、5 号核从普通调度中隔离出来普通用户态进程默认不会跑上去配合 taskset 手动放进去的服务使用。需要注意隔离的核要留够别把系统全隔离了另外在云主机上宿主机看不到真实拓扑isolcpus 可能没效果物理机或嵌入式场景更实用。注意isolcpus 隔离的核仍然会处理内核中断需要配合 irqbalance 或手动把中断亲和性写到其他核才能真正做到专用核。绑核效果怎么验证用 perf stat -e context-switches,cpu-migrations sleep 10 观察 cpu-migrations 计数如果接近 0说明进程已经不再在核之间迁移。这里的逻辑是进程不迁移意味着缓存更热、上下文切换更少但代价是单核负载集中所以要给绑定的核留足余量。3. 内存与Swap调优free命令背后的几个关键参数3.1 先看懂free输出buffer/cache不等于占用内存调优的第一步是确认内存到底够不够。free -m 的输出里used 列看着很高大部分其实是 page cache文件缓存。Linux 会把空闲内存尽量拿去做缓存业务需要时再回收所以判断依据不是 used 而是 available 列它才是还能分给新进程的真实内存。# 以MB为单位查看内存 free -m # 更精确地看内核 commit 了多少内存 grep -i commit /proc/meminfofree -m 里的 available 来自内核估算比直接算 usedfree 可靠得多。当 available 持续低于总内存的 10%说明内存确实吃紧。CommitLimit 和 Committed_AS 两行表示内核承诺给进程的内存上限和当前已承诺量配合超卖场景判断是否会发生 OOM 很有用。另外观察 page cache 的回收速度也有参考价值如果 available 下降很快但 cache 一直在开大说明有人在大量读文件磁盘 IO 可能才是第一瓶颈。3.2 swappiness怎么调换页倾向不是越大越好swap 是内存不足时的兜底但换页本身损耗很大。vm.swappiness 取值范围 0 到 100默认 60数值越大越倾向于把不常用的内存页换到 swap越小越倾向于回收 page cache。对交互式应用或数据库我一般降到 10 左右如果机器磁盘是机械盘宁可让 OOM 去杀进程也不要让整机陷入换页泥潭这是血泪经验。# 临时调整重启失效 sysctl -w vm.swappiness10 # 永久生效写入 /etc/sysctl.d/99-perf.conf # vm.swappiness10 sysctl --systemsysctl -w 是临时写运行时参数适合先验证效果sysctl --system 会按 /etc/sysctl.d/ 下所有 conf 文件依次加载比直接改 /etc/sysctl.conf 更好维护。这里的关键是理解 swappiness 不是内存用了多少才换页的阈值而是内核回收内存时对换页的倾向权重。调完以后用 swapon --show 看 swap 使用率如果 swap 长时间不增长说明这个值对你的负载是合适的。3.3 overcommit 三档含义与OOM防护vm.overcommit_memory 控制内核允许超量分配内存的程度。0 是启发式大多数情况够用但碰到申请一大块内存再逐步使用的程序会误判1 是允许任意 overcommit适合内存池类应用但系统很容易在真正需要内存时找不回来2 是禁止超过 CommitLimit 的分配最保守配合 overcommit_ratio 能防止单个大内存进程把系统拖死。# 使用保守模式承诺比例设为物理内存的80% sysctl -w vm.overcommit_memory2 sysctl -w vm.overcommit_ratio80overcommit_ratio 只有在模式 2 下生效表示允许承诺的内存是物理内存加 swap 的多少倍填 80 就是 80%。数据库服务我倾向模式 2因为它能把失控进程挡在 CommitLimit 之外宁可让它分配失败也不要整机死锁。模式 1 适合明确知道自己内存池大小、且能容忍小概率 OOM 的中间件。一旦发生 OOM第一时间看 /var/log/messages 或 journalctl -k里面会记录内核选了哪个进程、当时的内存水位这是判断参数是否过严的最快路径。3.4 参数持久化别让重启丢掉所有改动整套内存参数改完最怕重启后全部失效。规范化做法是在 /etc/sysctl.d/ 下建独立文件每个参数一行注释谁改的、为什么改都写清楚。系统启动时 systemd-sysctl 服务会自动加载这个目录不需要手工执行。# 新建文件写入并验证 cat /etc/sysctl.d/99-perf.conf EOF # 降低换页倾向减少磁盘抖动 vm.swappiness10 # 保守overcommit保护数据库进程 vm.overcommit_memory2 vm.overcommit_ratio80 EOF sysctl --system sysctl vm.swappinesscat 加 EOF 直接生成配置文件避免 vim 误操作sysctl --system 重新加载全部文件最后一条 sysctl vm.swappiness 单独确认当前生效值。注意同一个参数出现在多个文件时文件名排序靠后的会覆盖靠前的所以 99- 这个前缀是我个人习惯保证覆盖系统默认配置。还有一类特殊参数是只读的写入会报 kernel parameter 错误这种参数只能通过 grub 命令行传别在 sysctl.d 里浪费时间。4. 磁盘IO与网络栈调优iostat、调度器与网卡队列4.1 iostat指标解读await和util的组合判断磁盘饱和的特征不是 CPU 变高而是 wa 升高、进程进入 D 状态。iostat -x 能给出每个磁盘的详细指标最常用的判断组合是 util 和 await。util 接近 100% 说明磁盘几乎一直在忙但这不能直接等于性能差还要看 await 是否超过磁盘能承受的延迟水平。# 每2秒采样连续5次显示扩展统计 iostat -x 2 5-r 和 -w 可以拆开看读写分离但日常我只看几个字段util 是设备忙闲占比await 是 IO 请求从进队到完成的总等待时间r_await/w_await 是读写各自的平均等待。如果 await 高而 util 低大概率是 IO 请求本身排队严重或者磁盘降速了util 高且 await 接近物理极限才是真的需要换盘或做读写分离。机械盘的合理随机 IO 延迟在 10ms 上下SSD 在 1ms 以内超过这个量级先怀疑调度和队列深度再怀疑硬件。4.2 磁盘调度器机械盘用mq-deadlineNVMe用noneLinux 内核用调度器决定 IO 请求的排队顺序。CFQ 在旧内核里是默认值新内核改成多队列模式后常见选项是 mq-deadline 和 none。机械盘多并发场景用 mq-deadline 能尽量合并相邻请求SSD 和 NVMe 因为寻道时间接近 0直接选 none 减少一层排队开销。# 查看当前调度器 cat /sys/block/sda/queue/scheduler # 临时切换 echo mq-deadline /sys/block/sda/queue/scheduler # 永久生效在 /etc/udev/rules.d/ 下按磁盘类型设置scheduler 文件里方括号标着当前使用的调度器echo 写入即可临时切换。永久生效常见做法是写 udev 规则按盘符或型号匹配后设置也可以在 grub 内核参数里加 elevatormq-deadline 统一指定。要注意的是云主机的虚拟磁盘有些只支持 none写入别的会直接报错改之前先 cat 看清楚支持哪些。提示调度器改动后立即生效但重启会还原线上环境务必写成 udev 规则或 grub 参数不要每次开机手动 echo。4.3 网络栈调优ss看队列网卡队列与TCP缓冲网络调优的第一步还是先看指标。ss -lnt 输出的 Send-Q 和 Recv-Q 能反映 socket 队列堆积情况。Recv-Q 长期不为 0 说明应用来不及读数据Send-Q 长期不为 0 说明对端处理慢或网络拥塞。这两个队列溢出时抓包是看不到明显丢包的因为它们还没走到协议栈的丢包逻辑。# 查看监听端口和队列 ss -lnt # 查看网卡支持的中断队列数 ethtool -l eth0网卡多队列是老生常谈的调优点。ethtool -l 看 Combined 值如果网卡支持 8 条队列而系统只用 1 条可以把 Combined 调高配合 RPS/RSS 把中断分散到多个核多核机器上能明显改善单核 softirq 打满的问题。RPS 的手动配置也很简单把 rps_cpus 写成目标核的 CPU 位图即可比如 4 核机器想用后 3 个核就写 0xe。# 积压队列相关参数常规修改项 sysctl -w net.core.somaxconn1024 sysctl -w net.ipv4.tcp_max_syn_backlog2048somaxconn 是 listen 队列上限tcp_max_syn_backlog 是半连接队列上限。这两个参数只在应用 backlog 配得足够大时才生效如果 nginx 的 backlog512内核 somaxconn 调到 65535 也没意义。网络调优的原则是参数配合应用一起看孤立的 sysctl 只会制造假优化。遇到 TCP 重传先确认丢包发生在哪个方向调大缓冲前先排除对端处理能力和链路问题。4.4 文件系统挂载参数noatime与日志模式文件系统层面的调优容易被忽略但收益很直接。mount 默认记录每次文件访问时间atime高频读场景下这个写操作会放大 IO 次数。noatime 挂载参数可以去掉这个行为。数据库数据盘我会顺手把日志模式调整一下ext4 的 dataordered 比 datawriteback 更谨慎但后者写入时延更低适合能接受异常断电丢最近数据的场景。# 查看当前挂载参数 mount | grep /data # 临时重挂载不卸载磁盘 mount -o remount,noatime /dataremount 不需要卸载就能改挂载参数生产环境也能执行。注意noatime 只影响读操作的时间戳更新对写密集型应用没有优化作用如果应用依赖 atime 做失效判断比如某些邮件系统开了 noatime 反而会引出新问题这类功能取舍必须确认应用行为后再做。5. Linux性能调优避坑改错参数比不改更糟5.1 swappiness设成100Swap抖动反而拖慢数据库现象业务反馈接口延迟飙升free 输出显示 swap 使用率在 5% 和 30% 之间反复跳动CPU softirq 增高磁盘 IO 里能看到大量换页写。原因把 vm.swappiness 设置成了 100内核回收内存时极度偏好换页大量冷热不分的内存页被反复写入磁盘机械盘和普通 SSD 根本扛不住换页流量。解决改回 10 左右等 swap 使用率回落后再观察。如果内存真的不够正确做法是加内存或限制缓存而不是靠调 swappiness 硬撑。这个参数的调优收益有上限对数据库这类重负载进程换页带来的抖动远大于回收 page cache 的收益。5.2 overcommit_memory1 后 MySQL 分配内存失败现象设置 vm.overcommit_memory1 后MySQL 实例反复报内存分配失败日志里出现 Out of memory 且进程被 OOM Killer 选中。原因模式 1 允许内核无限超量承诺应用申请大块内存时总能成功但真正访问内存页时物理内存不够内核只能请 OOM Killer 找进程下手。MySQL 这类内存大户申请了不用用了才触发缺页最容易被选中。解决改用模式 2 并设置合理的 overcommit_ratio让内核在承诺阶段就拦住超量请求。我的经验是数据库机器 overcommit_ratio 设在 80 起步再按实际占用逐步微调同时用 systemd 的 MemoryMax 从 cgroup 层面再兜一层。5.3 机械盘换 none 调度器延迟不降反升现象按 SSD 调优教程给老机械盘执行 echo none /sys/block/sda/queue/scheduler结果随机读写延迟从 20ms 涨到 60msIO 吞吐反而下滑。原因机械盘寻道是物理瓶颈none 调度器不做请求合并和排序随机 IO 全部直接打给磁盘磁头来回跑延迟自然变差。mq-deadline 和 bfq 存在的意义就是给机械盘做电梯算法。解决换回 mq-deadline。教训是调度器选型先看介质机械盘选 deadlineSSD 选 none别拿一套配置套所有机器。5.4 sysctl 改了当时生效重启全部还原现象做完内存调优后 sysctl -w 验证一切正常过几天重启后 free 输出又回到原来的行为。原因sysctl -w 修改的是运行时内核参数不会写入配置文件。没有在 /etc/sysctl.d/ 下建立持久化文件重启后自然恢复默认。解决写完临时值验证没问题后立刻同步写入 /etc/sysctl.d/99-perf.conf再用 sysctl --system 重新加载。我的习惯是每改完一个参数马上加一行注释写入文件避免今天临时试一下变成重启后踩坑。5.5 一次改十个参数出了问题不知道回滚谁现象同时调整了 swappiness、overcommit、TCP 缓冲区、IO 调度器线上出现性能回退排查时每个参数看起来都是可疑的。原因多个参数之间存在耦合比如调大 TCP 缓冲区会占用更多内存进而触发更激进的内存回收单参数验证时看不到这个连锁反应。解决每次只改一个参数记录 baseline 指标验证有效再继续下一个。需要回退时优先回退最近一次改动而不是把所有配置推倒重来。6. 调优效果的闭环验证sysbench、fio 与 perf 怎么配合调优做完不验证等于白做。我习惯在执行任何改动前先记一组 baseline改动后复测同一组命令用数字对比代替感觉快了。以一次 MySQL 主机优化为例我按下面的顺序把四个维度各测一遍结果汇总成表指标调优前调优后变化平均负载 load18.23.5-57%磁盘 awaitms3621-42%swap 使用率85%12%-73%接口 P99 延迟ms920410-55%CPU 和内存用 sysbenchsysbench cpu run 测整数性能sysbench memory run 测内存带宽跑完看 events per second 和吞吐量。磁盘用 fio 更贴近真实负载下面这组命令用 libaio 引擎直写绕过 page cache测得的是纯粹的磁盘性能。# 调优前先跑一次记录数值 fio --nametest --rwrandread --bs4k --size1G \ --ioenginelibaio --direct1 --iodepth32 \ --numjobs4 --runtime30 --group_reporting # 调优后再跑一次对比 IOPS 和 lat avgusec--direct1 绕过 page cache确保测的是磁盘而非文件缓存--runtime30 控制测试时长避免把磁盘写满。对比时重点看 read IOPS 和平均延迟两个数值变化幅度超过 10% 才值得关注小幅度波动多半是噪声。网络验证用 iperf3 打满带宽测吞吐记录重传率。最后再用 perf top 看一眼热点确认调优没有引入新的异常系统调用。说句实话性能调优里最容易翻车的不是参数难记而是贪心。我自己的习惯是一次只动一个参数改完立刻记录结果确认有效再碰下一个这个习惯帮我少踩了很多坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表