
简介这份文档面向企业级 Linux 运维工程师与系统管理员聚焦 Red Hat Enterprise Linux AS 与 SUSE LINUX Enterprise Server 两大发行版下的性能调优实践帮助读者在有限硬件条件下提升服务器吞吐与稳定性。内容围绕关闭非必要 daemons、停用 GUI 图形界面、修改内核参数三条主线展开并延伸至处理器、内存、文件系统与网络子系统的调优思路涉及 sysctl、runlevel、chkconfig、taskset、nice 等常用手段同时提醒过度优化可能带来的反效果。资源包内含 1 个 docx 文档约 373KB按调优主题分节组织便于按需查阅与对照实践。目前已有 239 人学习适合希望系统梳理 Linux 性能优化路径、积累调优经验的中高级运维人员参考。1. Linux 性能调优的几种方法从一台「没跑满却卡成 PPT」的机器说起一台 8 核 16G 的 Linux 服务器CPU 使用率不到 30%内存还剩一半可业务接口的 P99 从 80ms 涨到了 900ms。登录上去敲topload average 是 12iostat里%util贴着 100%vmstat的wa列高得离谱——问题不在 CPU也不在内存而是磁盘 I/O 把整条链路拖住了。这就是 Linux 性能调优最典型的场景瓶颈往往不在你第一眼看的那个指标上。这篇笔记围绕「Linux 性能调优的几种方法」展开把 CPU、内存、磁盘 I/O、网络四条主线拆开讲清楚每条线用什么工具定位、关键参数怎么读、改哪些内核参数或应用配置能真正见效、改完怎么验证没翻车。适合已经能熟练敲linux 常用命令、但遇到性能问题还靠「重启大法」的运维和后端同学也适合准备linux 面试题时想把「调优」这块从背答案变成真会做的人。下面所有命令都在主流发行版CentOS/RHEL、Ubuntu/Debian、国产 Linux 发行版上验证过参数含义逐条说明不玩玄学。2. 先定位再动手用 USE 方法把四条资源线跑一遍调优最大的坑是「上来就改参数」。sysctl里几百个内核参数不知道瓶颈在哪就乱调轻则无效重则把稳定的服务调崩。我一般先用 USE 方法Utilization 使用率、Saturation 饱和度、Errors 错误把 CPU、内存、磁盘、网络四条线快速扫一遍锁定嫌疑对象再进具体章节。2.1 四条资源线的最小排查命令组合先装好sysstat工具包yum install sysstat或apt install sysstat它提供sar、iostat、pidstat这一套。下面这组命令是我每次上机器必跑的第一轮# 1. 全局概览load、CPU、内存、swap、上下文切换 vmstat 1 5 # 输出关注列 # r 运行队列长度持续 CPU核数 说明 CPU 饱和 # b 阻塞进程数0 通常意味着 I/O 等待 # si/so swap 换入换出非 0 就要警惕内存压力 # wa I/O 等待占 CPU 时间百分比20 基本锁定磁盘 # cs 上下文切换次数突增可能是锁竞争 # 2. 磁盘每个设备的 IOPS、吞吐、队列、利用率 iostat -xz 1 5 # 关注列 # %util 设备繁忙度接近 100% 说明设备饱和 # await 平均 I/O 等待毫秒数机械盘 20ms、SSD 5ms 要查 # aqu-sz 平均队列深度持续 1 说明请求排队 # r/s w/s 读写 IOPS # 3. 进程级谁在吃 CPU、谁在等 I/O pidstat -u -d -r 1 5 # -u CPU -d 磁盘 -r 内存缺页 # 4. 网络连接数、重传、丢包 ss -s netstat -s | grep -iE retrans|drop|overflow逻辑说明vmstat给全局画像iostat确认磁盘是否饱和pidstat把责任落到具体进程ss/netstat看网络层有没有异常。四步下来瓶颈基本能定位到某一条线。参数上vmstat 1 5表示每秒采样一次共 5 次采样间隔别设太大否则瞬时毛刺会被平均掉iostat -x的-x是显示扩展统计不加这个参数看不到%util和await等于白跑。提示load average高不等于 CPU 忙。Linux 的 load 把「运行中」和「不可中断睡眠D 状态多在等 I/O」的进程都算进去所以磁盘卡死时 load 会飙高而 CPU 很闲。看到 load 高先看vmstat的b列和wa列。2.2 把指标对应到「改什么」的决策表定位到瓶颈后下一步是决定动哪里。下面这张表是我自己用的对照表左边是现象右边是优先尝试的方向避免瞎调现象大概率瓶颈优先动作r列持续 核数ussy高CPU 饱和查热点进程/线程看是否可并行或限流sy特别高30%系统调用/上下文切换查cs、中断看是否锁竞争或频繁 syscallsi/so非 0free的 available 低内存不足触发 swap查内存泄漏调vm.swappinesswa高%util接近 100%磁盘 I/O 饱和查慢查询/大文件写考虑 IO 调度器重传率高、ss -s连接堆积网络或连接数瓶颈查somaxconn、tcp_max_syn_backlog这张表的价值在于它把「看指标」和「改配置」连起来了。很多人卡在中间——数据会看但不知道该改哪个参数。有了这张表至少方向不会错。接下来四章分别展开 CPU、内存、磁盘、网络的具体调法。3. CPU 与调度调优从 load 高但 CPU 闲的怪象说起CPU 调优最容易翻车的地方是把「CPU 使用率高」直接等同于「CPU 不够用」。实际上us用户态、sy内核态、waI/O 等待、st被虚拟化偷走四个值指向完全不同的病因。这一章先把 CPU 指标读透再讲调度和绑核这类真正能见效的手段。3.1 读懂 us/sy/wa/st四种「CPU 高」的不同解法top第一行的%Cpu(s)拆开看us高应用在用户态真算得欢。常见于计算密集、死循环、正则回溯。解法是查热点函数perf top或加缓存。sy高内核态时间多通常是系统调用频繁、上下文切换多、锁竞争。vmstat的cs列会同步飙高。解法是减少 syscall批量读写代替逐条、排查锁。wa高CPU 在等磁盘本质是 I/O 问题不是 CPU 问题。别去加 CPU去查磁盘。st高虚拟机被宿主机「偷」了 CPU 时间。这种情况你在 guest 里怎么调都没用得找宿主机或换实例规格。我见过最典型的误判一台机器sy占到 40%运维以为是 CPU 不够要扩容实际是应用每秒发起几十万次小write系统调用。改成批量写之后sy掉到 5%机器根本不用换。所以看到 CPU 高先分清是哪种高。# 找出用户态 CPU 最高的线程并看到它在干什么 top -H -p $(pgrep -f your_app | head -1) # 拿到高 CPU 的线程 TID 后转成 16 进制 printf %x\n TID # 用 perf 或 gdb 看这个线程的调用栈 perf top -p PID # 或者直接采样整个系统 5 秒 perf record -F 99 -a -g -- sleep 5 perf report逻辑说明top -H把进程拆到线程级定位到具体线程perf record -F 99以 99Hz 采样 5 秒-g记录调用栈perf report里能看到热点函数。参数-F 99是采样频率99 是经验值避开 100 的整数倍减少与定时器共振。这一步的目的是把「CPU 高」落到具体代码路径而不是停在进程名。3.2 进程优先级、绑核与调度策略的取舍定位到热点后如果短期内改不了代码可以用调度手段缓解。三个常用动作调整 nice 值renice -n -5 -p PID提高优先级需要 root让关键进程优先拿到 CPU。但注意nice 只在 CPU 争抢时起作用CPU 空闲时调它没意义。CPU 绑核taskset -cp 0-3 PID把进程绑到 0-3 号核。适合对延迟敏感、且希望减少跨核缓存失效的服务。但绑核是双刃剑——绑太死会让该进程在核忙时干等反而增加延迟。我一般只对延迟敏感的中间件如网关绑核且留出至少一个核给系统。调度策略普通进程用 CFS完全公平调度实时进程可用chrt设 SCHED_FIFO/SCHED_RR。实时策略优先级高于所有普通进程设错了会把系统卡死比如一个死循环的实时进程能饿死所有其他进程生产环境慎用。# 查看进程当前调度策略和优先级 chrt -p PID # 把进程设为 SCHED_FIFO优先级 101-99越高越优先 chrt -f -p 10 PID # 绑核到 2、3 号 CPU taskset -cp 2,3 PID参数说明chrt -f是 FIFO 策略-p 10是优先级。FIFO 策略下同优先级进程按到达顺序执行且不会被低优先级抢占。注意实时进程如果陷入死循环会独占 CPU 导致系统无响应务必配合ulimit或 watchdog 使用。绑核的核编号从 0 开始lscpu能看到可用核范围。提示容器环境下Docker/K8staskset和chrt的效果受 cgroup CPU 配额限制。如果容器设了--cpus2你在容器里绑 4 个核也没用实际还是被 cgroup 限流。调优前先确认cat /sys/fs/cgroup/cpu.maxcgroup v2或对应的 cgroup v1 文件。4. 内存与 swap 调优OOM 之前你还有哪些后悔药内存问题的可怕之处在于它平时不声不响一旦触发 OOM Killer进程直接被 kill业务瞬间掉线。这一章讲三件事怎么判断内存是真不够还是被缓存占了、swap 到底该不该关、以及 OOM 发生前能做什么。4.1 分清 available、buff/cache 与真正的内存压力free -h的输出里最容易被误读的是buff/cache。很多人看到free只剩几百 M 就慌了其实buff/cache是可回收的——它被内核用来缓存文件内存紧张时会自动释放。真正该看的是available这一列它估算的是「不触发 swap 的情况下还能给新进程用多少内存」。free -h # 关注 available 列而不是 free 列 # 看内存压力更准的指标/proc/meminfo 里的 MemAvailable grep -E MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree|Dirty /proc/meminfo # 看谁在占内存按 RSS 排序 ps aux --sort-rss | head -10 # 看进程的内存明细常驻、共享、缺页 pidstat -r 1 5逻辑说明MemAvailable是内核给出的「可用内存」估算比MemFree靠谱得多。Dirty是待写回磁盘的脏页如果这个值很大且长时间不降说明写回跟不上可能引发内存回收压力。pidstat -r的minflt/s次缺页和majflt/s主缺页能看出进程是否在频繁触发磁盘换页——majflt高说明进程在等磁盘性能会断崖式下跌。4.2 swappiness、overcommit 与 OOM 的三个关键参数内存相关的内核参数里真正影响生产稳定性的就三个vm.swappiness控制内核把内存页换到 swap 的倾向取值 0-100。默认 60意味着内核比较积极用 swap。对数据库、缓存类服务我一般设成 1 或 10减少不必要的换出但不建议设成 0因为 0 在部分内核版本上会让内核在内存紧张时直接 OOM 而不是先换出反而更危险。vm.overcommit_memory控制内存分配策略。0 是启发式默认1 是永远允许超额分配2 是严格限制。Redis 这类 fork 场景建议设 1避免 fork 时因 overcommit 检查失败。vm.panic_on_oomOOM 时是否 panic。默认 0只 kill 进程生产环境保持 0让系统 kill 掉最占内存的进程而不是整机重启。# 临时生效 sysctl -w vm.swappiness10 sysctl -w vm.overcommit_memory1 # 永久生效写入 /etc/sysctl.d/99-tuning.conf cat /etc/sysctl.d/99-tuning.conf EOF vm.swappiness 10 vm.overcommit_memory 1 vm.dirty_ratio 20 vm.dirty_background_ratio 10 EOF sysctl -p /etc/sysctl.d/99-tuning.conf参数说明vm.dirty_ratio20表示脏页占到内存 20% 时写操作会被阻塞强制回写vm.dirty_background_ratio10表示脏页到 10% 时后台开始回写。这两个值调低能让写回更平滑避免突发大量脏页导致 I/O 抖动但调太低会增加磁盘写次数。我一般把dirty_ratio设在 15-20dirty_background_ratio设在 5-10。注意改swappiness前先确认机器有没有 swap。swapon --show为空说明没启用 swap改这个参数没意义。另外 SSD 上频繁 swap 会加速磨损但现代 SSD 寿命足够不必因噎废食关键还是别让内存真的不够。5. 磁盘 I/O 调优iostat 里 %util 100% 时该动哪里磁盘 I/O 是生产环境最常见的瓶颈也是最容易被误诊的。%util100% 不代表磁盘一定到极限——对多队列的 NVMe%util可能虚高。这一章讲怎么正确判断磁盘饱和、IO 调度器怎么选、以及文件系统和挂载参数能带来什么。5.1 用 await、aqu-sz、IOPS 判断磁盘是否真饱和iostat -xz 1里几个关键列的正确读法r/s、w/s每秒读写次数IOPS。对比磁盘标称 IOPS看是否接近上限。await平均每次 I/O 的等待时间毫秒包含排队时间。这是判断用户体验最直接的指标。aqu-sz平均队列深度。持续大于 1 说明请求在排队。%util设备繁忙百分比。对单队列设备机械盘、SATA SSD这个值有意义对多队列 NVMe即使 %util 100% 也可能还有余量要结合await和 IOPS 一起看。# 看磁盘的实时 IOPS 和延迟 iostat -xz 1 5 # 找出哪个进程在疯狂读写 iotop -oPa # 或不用 iotop 时用 pidstat pidstat -d 1 5 # 看具体是哪个文件被读写需要 root # 先找到进程 PID再看它打开的文件 lsof -p PID | grep -E REG|DIR逻辑说明iotop -oPa的-o只显示有 I/O 的进程-P显示进程而非线程-a显示累计。pidstat -d的kB_rd/s和kB_wr/s是读写吞吐。定位到进程后lsof看它打开了哪些文件能进一步缩小到具体数据文件或日志。5.2 IO 调度器选择与文件系统挂载参数Linux 的 IO 调度器决定请求怎么排队和合并。常见三种调度器适用场景特点none/noopNVMe、高性能 SSD不做排序直接下发依赖设备自身队列mq-deadline通用、数据库保证请求在截止时间内完成防饿死bfq桌面、交互式按进程分配带宽公平性好但开销大查看和切换# 查看当前调度器 cat /sys/block/nvme0n1/queue/scheduler # 输出如 [none] mq-deadline bfq方括号是当前生效的 # 临时切换 echo mq-deadline /sys/block/nvme0n1/queue/scheduler # 永久生效写 udev 规则 cat /etc/udev/rules.d/60-ioscheduler.rules EOF ACTIONadd|change, KERNELnvme[0-9]*, ATTR{queue/scheduler}none ACTIONadd|change, KERNELsd[a-z], ATTR{queue/scheduler}mq-deadline EOF参数说明NVMe 设备用none通常性能最好因为它自身有深度队列内核再排序反而增加开销。SATA SSD 和机械盘用mq-deadline更稳。bfq在服务器上一般不用开销偏大。文件系统挂载参数也能影响 I/O 性能。以 ext4 为例noatime能避免每次读文件都更新访问时间减少写操作datawriteback提升写性能但降低一致性保证数据库场景慎用。# /etc/fstab 里给数据盘加 noatime # /dev/sdb1 /data ext4 defaults,noatime 0 2 mount -o remount,noatime /data提示noatime对大多数服务是安全的但如果你的应用依赖文件访问时间比如某些备份工具判断文件是否被读过就别加。改挂载参数前先确认业务不依赖 atime。6. 网络与内核参数调优高并发下连接被丢在哪一步网络调优的坑在于参数很多但真正影响高并发表现的没几个。这一章聚焦 TCP 连接建立、连接队列、以及文件描述符这几个高并发场景下的关键点。6.1 从 ss 和 netstat 看连接堆积在哪高并发下连接建立失败通常卡在三个地方半连接队列SYN 队列、全连接队列accept 队列、文件描述符耗尽。先用命令确认卡在哪# 看各种状态的连接数 ss -s # 看监听队列的溢出情况 ss -lnt # 输出里 Send-Q 是队列上限Recv-Q 是当前排队数 # 如果 Recv-Q 接近 Send-Q说明 accept 队列快满了 # 看内核层面的队列溢出统计 netstat -s | grep -iE listen|syn|overflow # times the listen queue of a socket overflowed 非 0 说明全连接队列溢出 # SYNs to LISTEN sockets dropped 非 0 说明半连接队列溢出逻辑说明ss -lnt的Recv-Q对 LISTEN 状态的 socket 表示当前已完成三次握手、等待应用 accept 的连接数Send-Q是队列上限。如果Recv-Q持续接近Send-Q说明应用 accept 太慢要么加应用处理能力要么调大队列。netstat -s里的溢出计数是累计值隔一段时间看增量才有意义。6.2 somaxconn、tcp_max_syn_backlog 与文件描述符三个最常调的网络参数net.core.somaxconn全连接队列上限默认 128老内核或 4096。高并发服务建议调到 32768。注意这个值要和应用的listen()backlog 参数配合取两者较小值。net.ipv4.tcp_max_syn_backlog半连接队列上限默认 1024 左右。SYN Flood 或高并发建连时可能不够建议调到 8192 以上。文件描述符ulimit -n默认 1024高并发下远远不够。要同时改系统级和进程级。# 临时调整 sysctl -w net.core.somaxconn32768 sysctl -w net.ipv4.tcp_max_syn_backlog8192 sysctl -w net.ipv4.tcp_syncookies1 # 永久写入配置文件 cat /etc/sysctl.d/99-tuning.conf EOF net.core.somaxconn 32768 net.ipv4.tcp_max_syn_backlog 8192 net.ipv4.tcp_syncookies 1 net.ipv4.tcp_tw_reuse 1 net.ipv4.ip_local_port_range 10240 65000 EOF sysctl -p /etc/sysctl.d/99-tuning.conf # 文件描述符系统级 cat /etc/security/limits.conf EOF * soft nofile 65535 * hard nofile 65535 EOF # 进程级systemd 服务 # 在 service 文件里加 LimitNOFILE65535参数说明tcp_syncookies1在 SYN 队列满时用 cookie 机制响应能缓解 SYN Flood但会牺牲部分 TCP 选项如窗口缩放高并发正常场景下影响不大。tcp_tw_reuse1允许复用 TIME_WAIT 状态的连接缓解端口耗尽但只在客户端主动连接时生效。ip_local_port_range扩大本地端口范围增加可用连接数。注意tcp_tw_reuse和已废弃的tcp_tw_recycle不是一回事。tcp_tw_recycle在 NAT 环境下会导致连接异常已被内核移除别再去开它。改somaxconn后要重启应用才生效因为队列大小在listen()时确定。7. 调优后的验证与回滚怎么确认没把系统调坏调优最怕的是「改完感觉快了但不知道是不是错觉」或者更糟——改完当时没事压测一上来就崩。这一章讲怎么用数据验证调优效果以及怎么给自己留后悔药。7.1 用压测和基线对比验证效果调优前后必须有可对比的数据。我一般用wrk或ab做 HTTP 压测用fio做磁盘压测记录关键指标# HTTP 压测4 线程 100 连接持续 30 秒 wrk -t4 -c100 -d30s --latency http://127.0.0.1:8080/api # 磁盘压测随机读 4K队列深度 32跑 30 秒 fio --namerandread --ioenginelibaio --rwrandread \ --bs4k --numjobs4 --iodepth32 --runtime30 \ --time_based --group_reporting # 压测同时采集系统指标 sar -u -r -d 1 30 /tmp/before_tuning.log逻辑说明wrk的--latency会输出延迟分布P50/P90/P99这是比平均值更有意义的指标。fio的--iodepth32模拟高并发 I/O--numjobs4是并发任务数。压测时用sar同步采集事后对比调优前后的%util、await、CPU 各态占比。关键原则一次只改一个参数改完压测确认有效再改下一个否则出了问题不知道是哪个参数导致的。7.2 参数回滚与变更记录调优参数一定要有回滚方案。我的习惯是所有sysctl改动写进独立的/etc/sysctl.d/99-tuning.conf不直接改/etc/sysctl.conf回滚时删文件即可。改动前记录原值sysctl -a /tmp/sysctl_before.txt回滚时对比。应用层参数如 JVM、连接池改动走配置中心或版本控制别手改线上文件。每次变更记录改了什么、为什么改、预期效果、实际效果、回滚命令。# 记录当前所有内核参数作为基线 sysctl -a /tmp/sysctl_baseline_$(date %F).txt # 回滚删除调优文件并重新加载 rm /etc/sysctl.d/99-tuning.conf sysctl --system # 对比改动前后的差异 diff (sysctl -a) /tmp/sysctl_baseline_2024-01-01.txt参数说明sysctl --system会重新加载所有配置文件包括/etc/sysctl.d/下的。diff能快速看出哪些参数被改过。这套流程看起来繁琐但真出问题时能让你在几分钟内回到已知稳定状态比现场抓瞎强太多。我踩过最深的一个坑有次为了「优化」把vm.dirty_ratio从 20 调到 5压测时写性能确实好了但上线后遇到一次大批量写脏页回写太频繁导致磁盘 I/O 抖动反而拖慢了读请求。后来才明白dirty_ratio调低是拿「写平滑」换「写吞吐」得看业务是读多还是写多。调优没有银弹每个参数背后都是取舍。希望这些经验能帮你少走点弯路帮到你。本文还有配套的精品资源点击获取