
简介这份文档面向企业级 Linux 运维工程师与系统管理员聚焦 Red Hat Enterprise Linux AS 与 SUSE LINUX Enterprise Server 两大发行版下的性能调优实践帮助读者在服务器场景中定位并突破性能瓶颈。内容围绕关闭非必要 daemons、停用 GUI 图形界面、修改内核参数三条主线展开并延伸至处理器、内存、文件系统与网络子系统的调优思路涵盖 runlevel 切换、sysctl 参数调整、CPU 亲和性与进程优先级控制、脏页写回策略、TCP/IP 栈参数等具体知识点同时提醒过度优化可能带来的反效果。资源包内含 1 个 docx 文档约 373KB结构紧凑、便于随查随用。目前已有 239 人学习适合需要系统梳理调优方法、对照命令与参数说明查漏补缺的中高级运维人员参考。1. Linux 性能调优的几种方法从 load 高到 RT 抖动的排查顺序线上告警一响top里 load average 冲到 40CPU 使用率却只有 15%这种“玄学”场景几乎每个运维都遇到过。Linux 性能调优的几种方法核心不是背命令而是建立一套从全局到局部、从现象到根因的排查顺序。这套方法解决的是系统变慢时先看什么、再看什么、什么时候该怀疑内存、什么时候该盯调度延迟。适合已经能跑top、free、iostat但面对真实故障仍靠猜的工程师。下面按 CPU、内存、IO、网络、调度五个维度拆开每个维度给出可复现的命令和参数判读标准。2. CPU 与调度从 load 到 runqueue 延迟的定位路径2.1 先分清 load 高是 CPU 排队还是 IO 等待load average统计的是运行队列长度加不可中断睡眠任务数。如果 load 高但%idle也高大概率是 IO 等待把任务压进了 D 状态。用vmstat 1看r列和b列r大于 CPU 核数说明 CPU 排队b持续大于 0 说明有阻塞任务。# 每秒采样观察 r运行队列、b阻塞、si/soswap、waIO等待 vmstat 1 10 # 输出示例 # procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- # r b swpd free buff cache si so bi bo in cs us sy id wa st # 8 2 0 102400 20480 512000 0 0 120 340 1200 2400 35 5 55 5 0r8且id55说明 8 个任务在等 CPU但 CPU 还有 55% 空闲矛盾点在于wa5和b2——有任务卡在 IO。此时继续用pidstat -d 1找具体进程。2.2 用 pidstat 和 perf 把热点锁到函数级pidstat -u 1按进程看 CPUpidstat -w 1看上下文切换。如果cswch/s异常高说明锁竞争或频繁阻塞唤醒。进一步用perf top -p pid看用户态热点函数。# 按进程统计 CPU-u 用户态-w 上下文切换 pidstat -u -w -p ALL 1 5 # 对目标进程采样 30 秒生成火焰图数据 perf record -F 99 -p 12345 -g -- sleep 30 perf report --stdio | head -50perf record的-F 99表示每秒采样 99 次-g记录调用栈。采样频率不要超过 200否则自身开销会干扰结果。perf report里如果__schedule或futex_wait占比高问题在调度或锁不在计算。2.3 调度延迟用 tracepoint 看 runqueue latencyCFS 调度器下任务从唤醒到上 CPU 的延迟叫 runqueue latency。用perf sched或bpftrace抓。# 统计每个任务的调度延迟分布 perf sched latency --sort max # bpftrace 一行抓 runqueue 延迟超过 1ms 的事件 bpftrace -e tracepoint:sched:sched_wakeup { start[args-pid] nsecs; } tracepoint:sched:sched_switch /start[args-prev_pid]/ { $d nsecs - start[args-prev_pid]; if ($d 1000000) { printf(pid %d latency %d us\n, args-prev_pid, $d/1000); } delete(start[args-prev_pid]); }perf sched latency输出里Maximum列超过 10ms 就值得关注。bpftrace脚本里1000000是 1ms 阈值按业务敏感度调整。实时任务抖动大时检查是否被RT任务抢占或cgroupCPU 配额限制。3. 内存与 swapfree 数字背后的回收压力3.1 available 才是可用内存buff/cache 不是缓存free -h里available列才是内核估算的可用内存。buff/cache大部分可回收但如果available低于总内存 10%分配就会触发直接回收表现为卡顿。free -h # 输出示例 # total used free shared buff/cache available # Mem: 15Gi 12Gi 512Mi 1.2Gi 2.5Gi 1.8Gi # Swap: 4.0Gi 3.8Gi 200Miavailable1.8Gi且Swap used3.8Gi说明内存压力已经很大swap 换入换出会拖慢所有 IO。用vmstat 1看si/so持续非零就是 swap 颠簸。3.2 用 smem 和 /proc/meminfo 定位真实占用ps aux的 RSS 会重复计算共享库。smem -t -k按 PSS 统计更准。/proc/meminfo里Slab、SReclaimable、SUnreclaim能看出内核对象占用。# 按 PSS 排序前 10 进程 smem -t -k -s pss | head -12 # 看内核 slab 占用 grep -E Slab|SReclaimable|SUnreclaim|KernelStack|PageTables /proc/meminfoSUnreclaim持续增长通常是内核内存泄漏比如驱动或dentry缓存异常。PageTables过大说明有进程映射了海量内存页常见于 JVM 或数据库。3.3 调整 vm.swappiness 和 overcommit 的边界vm.swappiness60是默认值数据库服务器建议降到 1 到 10减少匿名页换出。vm.overcommit_memory0启发式1总是允许2严格限制。Redis 这类 fork 场景需要1。# 临时生效 sysctl -w vm.swappiness10 sysctl -w vm.overcommit_memory1 # 永久写入 echo vm.swappiness10 /etc/sysctl.d/99-tuning.conf echo vm.overcommit_memory1 /etc/sysctl.d/99-tuning.conf sysctl -p /etc/sysctl.d/99-tuning.confswappiness0不代表禁用 swap只是尽量不换出匿名页。overcommit_memory2配合overcommit_ratio要算好否则大页分配直接失败。4. 磁盘 IOiostat 利用率与 await 的判读4.1 %util 高不等于磁盘瓶颈iostat -x 1里%util是设备有 IO 请求的时间占比对 NVMe 多队列设备参考价值有限。真正要看await平均等待和aqu-sz队列深度。iostat -x 1 5 # 关注列r/s w/s rkB/s wkB/s await r_await w_await aqu-sz %util # Device r/s w/s rkB/s wkB/s await r_await w_await aqu-sz %util # nvme0n1 1200 3400 48000 136000 0.8 0.5 0.9 12.5 85.0await0.8ms对 NVMe 正常aqu-sz12.5说明队列有积压但延迟低。如果await超过 10ms 且aqu-sz高才是真瓶颈。机械盘await20ms 以内可接受。4.2 用 iotop 和 blktrace 追到具体文件iotop -oPa按进程看实际 IO。blktrace能追到块设备层的每个请求。# 按累计 IO 排序只显示有 IO 的进程 iotop -oPa -d 2 # 抓 10 秒块设备事件生成分析文件 blktrace -d /dev/nvme0n1 -o trace -w 10 blkparse -i trace -d trace.bin btt -i trace.bin -o btt.outbtt输出里Q2C是队列到完成的总延迟D2C是驱动到完成。如果Q2C远大于D2C瓶颈在调度层或队列深度不足。4.3 文件系统与挂载参数noatime 和调度器noatime减少元数据写入nobarrier在带电池缓存的 RAID 上可开。IO 调度器对 NVMe 用none对 SATA SSD 用mq-deadline。# 查看当前调度器 cat /sys/block/nvme0n1/queue/scheduler # 临时改为 none echo none /sys/block/nvme0n1/queue/scheduler # 挂载参数写入 fstab # /dev/nvme0n1p1 /data ext4 defaults,noatime,nodiratime 0 2noatime对读多写少场景收益明显。nodiratime只关目录访问时间。改调度器前确认内核版本支持none多队列。5. 网络与中断从软中断到 RPS 的调优5.1 用 sar 和 ss 看重传与队列sar -n DEV 1看网卡吞吐和丢包ss -s看 socket 统计。netstat -s里retransmitted高说明网络质量差或缓冲区不足。sar -n DEV 1 5 ss -s netstat -s | grep -E retrans|overflow|dropss -s输出TCP: 1200 (estab 800, closed 300, orphaned 10, timewait 50)orphaned高说明应用没及时 accept。netstat -s里listen queue overflow要调somaxconn。5.2 软中断不均RPS 和 RFS 配置多队列网卡默认按流哈希到不同 CPU但单流可能压在一个核。RPS把软中断分散到多核。# 查看网卡队列数 ls /sys/class/net/eth0/queues/ # 开启 RPS每个队列的 rps_cpus 用十六进制掩码 echo f /sys/class/net/eth0/queues/rx-0/rps_cpus # 开启 RFS设置流表大小 echo 32768 /proc/sys/net/core/rps_sock_flow_entries echo 2048 /sys/class/net/eth0/queues/rx-0/rps_flow_cntrps_cpusf表示 4 个 CPU 参与软中断。rps_sock_flow_entries建议设为rps_flow_cnt乘以队列数。RFS 需要应用配合SO_INCOMING_CPU才最有效。5.3 中断亲和性与 IRQ balance 的取舍irqbalance自动分发中断但数据库这类延迟敏感场景建议手动绑核。# 查看中断号与 CPU 绑定 cat /proc/interrupts | grep eth0 # 把 99 号中断绑到 CPU 2 和 3 echo 0c /proc/irq/99/smp_affinity # 关闭 irqbalance systemctl stop irqbalance systemctl disable irqbalancesmp_affinity是十六进制掩码0c表示 CPU 2 和 3。绑核后确认/proc/interrupts里对应 CPU 计数增长。网卡多队列时每个队列单独绑。6. 避坑与排查五个真实翻车记录6.1 调大 somaxconn 后连接仍超时现象netstat -s里listen queue overflow归零但客户端仍偶发超时。原因应用层backlog参数没改listen(fd, 128)里 128 是上限内核somaxconn只是允许的最大值。解决改应用代码或配置里的 backlogNginx 是listen 80 backlog4096Redis 是tcp-backlog 511。6.2 swappiness 设 0 后 OOM 反而更频繁现象vm.swappiness0后内存快满时直接触发 OOM killer而不是换出。原因swappiness0只是尽量不换出匿名页但文件页回收后仍不够内核直接 OOM。解决设1到10之间保留少量换出能力同时用cgroup memory.limit_in_bytes限制单服务。6.3 perf record 频率过高导致业务抖动现象perf record -F 999采样时业务 RT 从 1ms 涨到 20ms。原因采样频率过高每次采样都触发中断和栈回溯开销叠加。解决降到-F 99或-F 49采样时间控制在 30 秒内生产环境优先用perf top只读模式。6.4 RPS 开启后单流性能下降现象开启 RPS 后单 TCP 流吞吐从 9Gbps 降到 6Gbps。原因单流被哈希到一个 CPURPS 把软中断分散后缓存局部性变差跨核同步开销增加。解决单流场景关 RPS用网卡多队列加SO_INCOMING_CPU绑核多流场景再开 RPS。6.5 改 IO 调度器后 NVMe 延迟反升现象把 NVMe 调度器从none改成mq-deadline后await从 0.8ms 涨到 2.5ms。原因mq-deadline对 NVMe 多队列设备增加了排序开销而 NVMe 本身延迟极低不需要调度器合并。解决NVMe 保持noneSATA SSD 用mq-deadline机械盘用bfq。7. 用 bpftrace 做持续性能观测的进阶技巧调优不是一次性动作而是持续观测。bpftrace能在生产环境低开销抓取内核事件比perf更灵活。下面给一个综合脚本同时统计 runqueue 延迟、块 IO 延迟和 TCP 重传。#!/usr/bin/env bpftrace # 统计 runqueue 延迟超过 1ms 的次数 tracepoint:sched:sched_wakeup { qstart[args-pid] nsecs; } tracepoint:sched:sched_switch /qstart[args-prev_pid]/ { $d nsecs - qstart[args-prev_pid]; if ($d 1000000) { rq_lat hist($d / 1000); } delete(qstart[args-prev_pid]); } # 统计块 IO 完成延迟 tracepoint:block:block_rq_complete { io_lat hist(args-nr_sector ? (nsecs - io_start[args-dev]) / 1000 : 0); } tracepoint:block:block_rq_issue { io_start[args-dev] nsecs; } # 统计 TCP 重传 kprobe:tcp_retransmit_skb { retrans count(); } interval:s:10 { print(rq_lat); print(io_lat); print(retrans); clear(rq_lat); clear(io_lat); clear(retrans); }脚本里hist()输出微秒级直方图interval:s:10每 10 秒打印并清空。io_start用args-dev做 key避免多设备混淆。生产环境跑之前先用bpftrace -l tracepoint:block:*确认内核支持。如果block_rq_complete拿不到args-dev改用args-q或args-rq做 key。我自己的习惯是任何调优动作前先跑 5 分钟基线改一个参数后至少观察 30 分钟对比hist的 P99 变化。曾经因为一次改swappiness没留基线回滚时找不到原始值折腾到凌晨。现在所有sysctl改动都写进配置管理改前sysctl -a baseline.txt。希望帮到你。本文还有配套的精品资源点击获取