最近在准备 RHCA II 的最后一门 EX442(性能调优与容量规划),相关笔记已经写到第 13 篇。说句实话,刚看这个标题时我也觉得“调优”离我很远,但真正动手做下来,发现它比想象中落地得多——不是在系统里随便改几个数字,而是有一套完整的观察、分析、验证流程。这篇笔记主要把从监控工具到内核参数、从瓶颈定位到容量规划的关键点串起来,希望能给同样备考 EX442 或者准备排查生产环境性能问题的同学一些参考。
1. 为什么 RHCA II 要考 EX442:性能调优不是玄学
1.1 EX442 在 RHCA 体系中的定位
RHCA 整个路径分好几门,EX442 是偏“系统性能”的一门。很多同学以为这台考试是“背几个 sysctl 参数”,但实际考试导向是“你能不能在一个看起来没毛病的 Linux 系统里快速找到瓶颈”。我在备考时翻了大纲,大概分几块:系统监控、性能基准、内核参数调整、tuned 动态调优、容量规划。难点不是参数多,而是你怎么判断该调哪个、调完之后怎么确认有效。考试机是模拟好的典型故障,你需要在真实环境里用工具观察、定位、修改并验证。这也是 RHCA 系列和 RHCE 一个比较大的区别:RHCE 考“能不能配出来”,EX442 更考“能不能判断为什么”。
1.2 性能调优的真实场景:从“系统变慢”到“容量瓶颈”
生产环境里最常见的场景是:电商促销前,应用团队反馈接口延迟从 20ms 涨到 200ms,运维第一反应是不是加机器?如果只是容量不够,加机器确实治标;但如果是某个内核参数、文件系统挂载参数或 CPU 亲和性设置不合理,加机器只会让问题更隐蔽。EX442 要求你具备这种“系统体检”能力:开机看一下 load average、top、vmstat、iostat,先判断是 CPU、内存、IO 还是网络;再用 sar 对比历史;接着用 pidstat/strace/perf 定位具体进程和调用栈;最后做个小实验验证。这样一套下来,调优就不是玄学。
1.3 我的备考路线:如何把“调优”变成可复现的方法
我的备考方式比较“笨”:先把官方教材的章节过一遍,然后在一台空闲的虚拟机上模拟各种负载,用工具反复看指标。每看一个性能问题,就写下当时的基线和调优后的数值,形成自己的速查表。EX442 考试有一个很实用的点:它不要求你记住全部参数,但你必须知道每个典型场景在哪儿看文档、用什么命令验证。所以我今天这篇第 13 篇笔记,也算是一次“总复习”:把零散的知识按排查流程重新整理。
2. 核心知识拆解:监控、基准和瓶颈
2.1 性能分析的标准流程:“观察-分析-调优-验证”
很多入门教程会直接列参数,但 EX442 更强调流程。我的理解是四个字:先测量,后修改。 第一步观察:通过 uptime、top、vmstat 等确认系统当前状态,是 CPU 高还是 IO 忙?然后再分析:用 mpstat 看每个核的情况,用 pidstat 看是哪个进程在消耗资源,必要时用 perf top 看内核/用户态热点。调优的时候一次只改一个变量,比如先把 vm.swappiness 从 60 改到 10,跑一段脚本,观察 swap 是否减少,而不是同时动五六个参数。最后验证:用同样的命令和同样的负载重新测量,比较前后差异,如果效果不明显就先回滚,再试下一个。这条流程我在模拟环境里跑了不下二十遍,考试时也一样,先冷静定位,再动手。
2.2 必须掌握的监控工具清单
我整理了一张自己复习用的工具表,按“看全局、看细节、看历史”分类:
| 目的 | 命令 | 关注点 |
|---|---|---|
| 全局负载 | uptime | load average 与 CPU 数对比 |
| CPU/内存/进程 | top / htop | %us、%sy、%wa、zombie、VIRT/RES |
| CPU各核 | mpstat -P ALL 1 | 是否单核打满 |
| 进程CPU | pidstat -u 1 | 哪个PID在烧CPU |
| 内存 | free -h | available、buff/cache、swap |
| 虚拟内存/IO | vmstat 1 | r、b、si、so、wa、us、sy |
| 块设备IO | iostat -x 1 | %util、await、读写速率 |
| 历史性能 | sar | sar -u -r -b -q 查看历史 |
| 网络连接 | ss -s | 会话数、TCP 状态 |
| 热点分析 | perf top / record | 内核态与用户态函数 |
这个清单是考试的核心,也是在生产环境定位问题的起点。要注意 top 显示的 %wa 在很多新内核里是“IO 等待”占比,但并不能直接代表“死等”磁盘,有时候服务器有空闲 CPU 却在等锁,也会表现成 %wa,最好结合 iostat 的 %util 一起看。
2.3 性能基准测试怎么做
调优前后必须跑同样的基准,不然没法说明有效果。我常用的工具是 sysbench,它不在官方考试要求里,但用来模拟负载很顺手。比如要制造 CPU 压力:
sysbench cpu --threads=4 --time=60 run要制造 IO 压力:
sysbench fileio --file-total-size=4G --file-test-mode=rndrw prepare sysbench fileio --file-total-size=4G --file-test-mode=rndrw run跑基准之前要用sync; echo 3 > /proc/sys/vm/drop_caches清缓存,保证每次起点接近。还要固定 CPU 频率,否则处理器睿频会让结果漂移。考试中虽然不会让你跑 sysbench,但制造压力、验证调优结果是必备思路。
2.4 容量规划的基本思路
容量规划不是“拍脑袋”,而要根据趋势数据推测未来。最简单的做法:保留 sar 历史数据,定期收集 CPU、内存、磁盘、网络的峰值和均值,算出同一业务周期(比如促销日)的环比增长率,再乘以安全系数 1.5 到 2。例如某台应用服务器在工作日 10 点的 CPU 峰值是 60%,如果每月增长 10%,三个月后就会到 80% 以上,这时候就该规划扩容或优化。EX442 对容量规划的考察不一定很深,但会给你一堆历史数据,让你判断哪些资源接近瓶颈,并给出合理建议。
3. 关键调优参数与实操笔记
3.1 sysctl 常用参数速查
这一节是“背参数”的核心区,但不要死记。我把自己在实际环境验证过的参数分成了四类:内存、CPU、IO、网络。先给一张表:
| 参数 | 默认值(RHEL9) | 作用 | 我的建议 |
|---|---|---|---|
| vm.swappiness | 60 | 控制 swap 倾向 | 内存充足时设 10 左右 |
| vm.dirty_ratio | 20 | 脏页占内存百分比上限,触发写盘 | I/O 密集且内存大时可适当调大 |
| vm.dirty_background_ratio | 10 | 后台写脏页阈值 | 配合 dirty_ratio 调整 |
| kernel.sched_min_granularity_ns | 2250000 | 进程最少运行时间 | 大量短任务可调小,减少等待 |
| kernel.sched_wakeup_granularity_ns | 1250000 | 唤醒抢占粒度 | 调大可减少频繁抢占 |
| net.core.rmem_max | 212992 | socket 接收缓冲最大值 | 大流量接收可调大 |
| net.ipv4.tcp_rmem | 4096 87380 6291456 | TCP 读缓冲 | 延迟敏感可调小,吞吐优先可调大 |
| net.ipv4.tcp_tw_reuse | 0 | TIME_WAIT 复用 | 高并发短连接可开 1(注意 NAT 场景) |
调参前必须备份当前值:
sysctl -a > /root/sysctl_before.txt修改可以用sysctl -w key=value临时生效,测试稳定后在/etc/sysctl.d/下写个 conf 文件永久保存,例如/etc/sysctl.d/99-tuning.conf。不要直接把值写进/proc,因为重启就没。
3.2 tuned 动态配置
tuned 是系统自带的性能调整守护进程,它按不同 profile 自动配置一堆参数,比手动改 sysctl 更体系化。查看当前 profile:
tuned-adm active可用 profile:
tuned-adm list切换:
tuned-adm profile throughput-performance对于大多数通用服务器,throughput-performance是比较稳的选择,它会把 swappiness 调低、把 CPU governor 设为 performance。如果是数据库,可以试试virtual-host或自己写 custom profile。自定义 profile 的做法是:
cp -r /usr/lib/tuned/throughput-performance /etc/tuned/myweb然后修改/etc/tuned/myweb/tuned.conf,把需要的 sysctl 写进[sysctl]段,最后执行tuned-adm profile myweb启用。注意:启用 tuned 后,手动 sysctl 修改可能被覆盖,所以要在 profile 里改,或者先确认 tuned 没有管理该参数。
3.3 CPU 调优
CPU 调优的关键词是“减少竞争”:如果应用是多实例部署,尽量把 CPU 密集的进程绑到固定的核上,避免它到处迁移导致缓存失效。使用:
taskset -c 0,1,3 java -jar myapp.jar也可以用 cgroups 限制配额,RHEL9 上更推荐 systemd 的CPUQuota:在 service 文件里设置CPUQuota=200%,意思是这个服务最多用两个完整核心。实践中我还遇到过一个问题:系统整体空闲,但某个 CPU 密集线程把单核打满,导致其他线程排队。这时候先用mpstat -P ALL确认是不是单核问题,再考虑绑核或调整调度器,不要一开始就想着加机器。
3.4 内存调优
内存层面最容易踩坑的是 swappiness。很多文章说“设成 0 禁用 swap”,但在 RHEL9 里设成 0 并不等于禁用 swap,只是系统尽可能不回收匿名页,反而可能让内存不足时触发 OOM。我一般建议设 10 左右,混合负载下既能保留一些 swap 兜底,又不至于频繁换页。另外一个参数是 vm.dirty_ratio 和 vm.dirty_background_ratio:如果写盘是瓶颈,调大 threshold 可以让进程等待时间变短,但会增大掉电丢失数据的风险,所以要权衡。我自己的经验:数据库服务器不要盲目调大 dirty_ratio,除非你有电池备份的存储;应用服务器如果内存充足,可以适当调大。
3.5 存储与网络 I/O 调优
存储调优的入门是确认磁盘调度器。NVMe 上通常用 none,SATA/SAS 可以用 mq-deadline。查看当前调度器:
cat /sys/block/sda/queue/scheduler临时修改:
echo mq-deadline > /sys/block/sda/queue/scheduler永久写 udev 规则或内核参数。如果是虚拟机,磁盘后端通常是虚拟化存储,调度器用 none 反而更少层。网络 I/O 调优要少而精:提高net.core.rmem_max和 tcp 缓冲区能提升大流量吞吐,但会增大延迟和内存占用。高并发短连接场景tcp_tw_reuse有一定帮助,但要注意如果你的服务位于 NAT 网关后,复用 TIME_WAIT 的 socket 可能把延迟“借”给其他连接,导致 NAT 层混乱。总之,网络调参务必压测后再上线。
4. 实操演示:一次 CPU 使用率飙升的完整排查
4.1 症状描述与初步定位
我准备的模拟场景:某 JVM 应用节点在白天高峰期 CPU 使用率飙到 95%,但应用吞吐量没有明显提升。我先执行uptime,看到 load average 已经到 12,而虚拟机只有 8 个 CPU,说明负载确实过高。接着top,发现一个 java 进程占用 850% CPU,基本快打满 8 核。这时候不要急着 kill 或重启,先确认它是不是正常业务线程在忙。用mpstat -P ALL 1看每核利用率,发现 8 个核大部分都在 90% 以上,属于整体 CPU 瓶颈,不是单核问题。vmstat 1看到 r 列(运行队列)经常超过 CPU 数量,说明内核确实有大量可运行任务在排队,而不是在等待 IO,因为 b 列(阻塞进程)几乎为 0,wa 也很低。所以初步结论是 CPU 计算密集导致资源不足。
4.2 使用 pidstat 和 perf 找到热点
定位到进程还不够,EX442 考试里经常要求你进一步说出“是什么操作消耗了 CPU”。这一步可以用:
pidstat -u -p <PID> 1查看该进程下线程的 CPU 占用,会发现多个线程各自占用 100%+。再用:
perf top -p <PID>查看采样热点函数,结果里出现java的 JIT 编译相关符号和高频字符串处理函数,基本可以推断是业务代码里有循环或 GC 频繁。想更精确就打出一个线程的栈:
perf record -p <PID> -g -- sleep 10 perf report我在模拟环境里还遇到过perf报Operation not permitted,原因是kernel.perf_event_paranoid大于 1,临时调成:
sysctl -w kernel.perf_event_paranoid=1就能测了。
4.3 结合 sar 判断是持续峰值还是瞬时抖动
单看一个时间点的 top 容易误判。我会用:
sar -u -q -f /var/log/sa/sa<日期>查看当天历史:如果 CPU 从上午 10 点开始持续走高,和业务高峰吻合,说明是容量问题;如果只是每隔几分钟出现一个尖峰,可能是有定时任务或 GC 线程。这次模拟里我看到 CPU 从 10:00 起逐步上升,到 10:30 接近 90%,基本是持续型。用sar -r看内存和 swap 也发现 swap 一直在增长,说明物理内存不足,JVM 在频繁发生内存换页,进一步加重 CPU 负担。所以真正的问题可能是:内存不够导致 swap,进而引发 CPU 飙高,而不是纯 CPU 不够。
4.4 调优动作与验证
确认根因后,我做了三件事:第一,把 JVM 堆内存参数调大并限制线程栈,减少 GC 和换页;第二,在 sysctl 里把vm.swappiness从 60 降到 15,并用:
sysctl -w vm.swappiness=15临时生效;第三,在不影响业务的情况下把 Java 进程绑到固定 CPU 组:
taskset -c 2-5 -p <PID>执行完后,等 5 分钟再观察:vmstat 1的 si/so 明显下降(swap 换入换出基本为 0),sar -u显示 CPU 降到 60% 左右。再用同样的请求测试接口,延迟从 180ms 降到 90ms。整个过程我没有重启服务,也没有加大服务器规格,这说明调优确实有效。考试时也是一样的思路:先在测试环境里改一个参数、测量、回滚。
5. 常见问题与排查技巧实录
5.1 为什么 free 显示的 available 不等于 free + buff/cache
这是很多同学看free -h会蒙的点。available 是“在不触发 swap 的情况下可分配给新进程的内存估算”,它比 free + buff/cache 更准确,因为 buff/cache 里有些页是可以被回收的,有些是共享内存段、内核占用,不能回收。实际排障时以 available 为主,不要一看到 free 很小就喊内存不足。如果 SWAP 用了很多,而 available 也低,才说明压力大。
5.2 swap 过高怎么办
先不要无脑设 swappiness=0。我见过强行设 0 后数据库直接 OOM 的情况。正确做法是先看vmstat 1的 si/so,如果一直有换页动作,再判断是内存不足还是缓冲区设置不合理。临时缓解可以sysctl -w vm.swappiness=10,但根本办法还是看应用内存模型,比如 JVM 堆、数据库 buffer pool 是否过大,必要时加内存或调整 cgroup 限制。如果 swap 已经很高,想释放一部分,可以swapoff -a && swapon -a,但生产环境执行要谨慎,最好选在业务低峰期,并且先确认内存有足够余量,否则会瞬间 OOM。
5.3 sar 没有历史数据
sar 是 EX442 的重要工具,但很多服务器默认没装 sysstat,或者没开启采集。安装 sysstat 后,需要确认/etc/cron.d/sysstat每分钟跑一次采集脚本,否则/var/log/sa下什么都没有。你可以先手动执行:
sar -u 1 5验证当前能输出,再用:
sar -u -f /var/log/sa/sa$(date +%d)查看当天历史。如果报“请求的文件不存在”,多半是 cron 或 systemd timer 没启动:systemctl start sysstat。
5.4 使用 tuned 后性能反而回退
我先说一个我自己踩过的坑:为了省内存,我把 profile 切到powersave,结果数据库延时翻倍。原因是 powersave 会把 CPU governor 调成节能模式,频率响应变慢。考试或生产环境,不建议用 powersave 调“性能”问题。切换 profile 后如果性能回退,先tuned-adm active确认是否生效,然后用tuned-adm off对比一下,或者干脆自定义 profile,把 governor 设成 performance,再逐个启用其他优化项。
5.5 perf 权限不足
perf top报Operation not permitted,几乎都是因为/proc/sys/kernel/perf_event_paranoid被设成 2 或更大。临时调低:
sysctl -w kernel.perf_event_paranoid=1或者用 sudo 执行也可以,但有些环境会提示kernel.kptr_restrict,把kernel.kptr_restrict=0打开才能看到内核符号。注意这些是安全优化参数,生产环境调整前要和相应负责团队确认,考试机可以放心改。
5.6 考试中的常见坑
最后说一下 EX442 考试机的坑:一是考前会有一个基线,你在答每道题时尽量只改该题涉及的配置,不要全局刷参数,避免影响后面的题目;二是改完之后一定要验证,比如题目要求“将某服务 CPU 使用率降低 20%”,你要用同样的命令对比前后输出,很多同学改完参数不验证就跳到下一题,这是最大失分点;三是记牢备份文件,用cp或配置管理工具做配置备份,万一调错了还能回滚。这些都是纯经验,官方文档不会给你写。