为什么我们总在乱改参数
很多团队在遇到 Linux 服务器响应变慢时,第一反应往往是去搜索引擎找一堆“性能优化参数”,然后一股脑儿塞进 /etc/sysctl.conf。结果呢?运气好的,系统似乎快了一点;运气差的,直接引入新的稳定性问题,甚至引发难以排查的偶发性故障。
真正的性能调优,从来不是一场参数的军备竞赛。它更像是一次外科手术,需要精确的术前诊断(监控)、清晰的手术目标(优化指标)和术后的效果验证。内核参数是手术刀,而不是万能药。胡乱挥舞手术刀,只会让系统伤得更重。
这篇文章想和你聊的,就是如何放下对“神秘参数”的迷信,建立一套基于证据的、可持续的 Linux 性能调优思路。我们会重点讨论,在 CPU、内存、磁盘 I/O 和网络这四个核心领域,哪些参数调整是真正有高回报率的,以及它们分别在什么场景下生效。
第一步:调优的绝对前提——看清系统在干什么
在动任何参数之前,你必须回答一个问题:系统的瓶颈到底在哪里?是 CPU 算力不足,还是内存不够用,或者是磁盘读写太慢,甚至是网络卡在了哪里?
一个经典的误区是看到 top 命令里 CPU 使用率 90% 就断定是 CPU 瓶颈。实际上,高 CPU 使用率中的 %wa(I/O 等待)占比如果很高,说明 CPU 在空转等待慢速的磁盘,真正的瓶颈在 I/O。这时你给 CPU 调频或者调整调度策略,基本是徒劳的。
你需要一套快速诊断的命令组合拳。下面这个简单的脚本可以作为一个起点,它每隔5秒采集一次关键指标:
#!/bin/bash
while true; do
clear
echo "======= $(date) ======="
echo "1. CPU & Load:"
uptime
echo -e "
2. Memory & Swap:"
free -h | grep -E "(total|available|Swap)"
echo -e "
3. Top 5 CPU Processes:"
ps aux --sort=-%cpu | head -6
echo -e "
4. Disk I/O Wait (from vmstat):"
vmstat 1 2 | tail -1 | awk '{print "wa:" $16 "%"}'
echo -e "
5. TCP Connection Summary:"
ss -s | head -2
sleep 5
done
运行它,观察几分钟。如果某个指标(如内存可用值、I/O等待、TCP重传)持续异常,那才是你需要深入调查的方向。没有明确瓶颈的“预防性调优”,大多是在制造复杂度。
CPU:关注调度与中断,而非盲目提频
对于 CPU,最容易产生误解的是“负载高”。系统负载(Load Average)反映的是处于可运行状态和不可中断状态(通常是在等 I/O)的平均进程数。一个单核 CPU,负载持续高于 1.0 就说明有进程在排队了。
在确认是 CPU 计算资源真正紧张(%us 或 %sy 持续高位,且 %wa 很低)后,可以看看两个方向:
- 进程优先级与绑定:对于关键服务(如数据库、消息队列),可以使用
nice/renice提高其静态优先级,或者用taskset将其进程/线程绑定到特定的 CPU 核心上。这能减少缓存失效和上下文切换的开销,对于延迟敏感型应用效果显著。 - 中断平衡:在高网络包吞吐的场景下(如网关、代理服务器),网络中断(NET_RX)可能会集中打满某一个 CPU 核心,导致性能瓶颈。你可以通过查看
/proc/interrupts和/proc/irq/[IRQ号]/smp_affinity_list来调整中断的亲和性,将其分摊到多个核心。
至于调整 CPU 频率调速器为 performance,这确实能避免因频率缩放带来的延迟抖动,但它会显著增加功耗。这更适合对延迟极其敏感、且运行在受控机房环境中的服务器,而不是所有的云主机或虚拟机。
内存:理解“用了”和“没了”的区别
Linux 的内存管理策略非常积极:它会用尽所有空闲内存来作为磁盘缓存(Page Cache)和缓冲区(Buffer),以加速后续的磁盘读写。所以,看到 free -h 输出中“free”内存很少,完全不必惊慌,这通常是系统高效工作的表现。
关键要看 MemAvailable 这个指标(在较新内核的 free 命令或 /proc/meminfo 中)。它估算的是在不发生交换(swap)的情况下,可以立即分配给新程序的内存总量。
真正值得动的内存相关参数不多,vm.swappiness 是其中最著名的一个。它控制内核将匿名页(程序数据)交换到磁盘的积极程度,范围是0-100。
| swappiness 值 | 行为倾向 | 适用场景 |
|---|---|---|
| 60 (默认) | 平衡内存回收与交换 | 通用服务器 |
| 10-30 | 尽量避免交换,优先回收Page Cache | 数据库服务器、内存充足时希望减少交换延迟 |
| 接近 0 | 除非绝对必要(内存耗尽),否则不交换 | 对延迟极度敏感,且有充足物理内存保证的服务 |
| > 80 | 更积极地使用交换分区 | 内存极度紧张,且磁盘性能尚可的桌面或特定场景 |
对于大多数数据库或应用服务器,将其设置为 10-30 是一个稳妥的选择。这能让系统在内存压力下,优先清理可以丢弃的磁盘缓存,而不是把正在运行的程序挤到慢速的 swap 中,从而避免性能断崖式下跌。
# 临时生效
sudo sysctl -w vm.swappiness=20
# 永久生效,写入 /etc/sysctl.conf
echo "vm.swappiness=20" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
另一个参数 vm.dirty_ratio / vm.dirty_background_ratio 控制着脏页(待写回磁盘的数据)的比例。对于写入密集型应用(如 Kafka、ES),适当调高这些值(例如分别到 40 和 10)可以利用更多内存进行写缓冲,平滑写入峰值,但会增加宕机时数据丢失的风险。这是一个典型的性能与可靠性的权衡。
磁盘 I/O:调度器与挂载选项的取舍
磁盘 I/O 的优化,硬件(HDD vs. SSD)的选择往往比软件调参带来的提升大一个数量级。在软件层面,最值得关注的是 I/O 调度器和文件系统挂载选项。
首先,确认你的磁盘类型和当前调度器:
# 查看块设备及其调度器,例如 sda
cat /sys/block/sda/queue/scheduler
# 输出可能为:[mq-deadline] kyber bfq none
对于 SSD,它没有磁头寻道时间,所以复杂的调度算法收益很小。推荐使用 none(即 Noop 的多队列版本,如 kyber 或 mq-deadline),它们延迟更低。对于 HDD,bfq(Budget Fair Queueing)或 mq-deadline 能在混合读写负载下提供更好的公平性和吞吐量。
其次,是文件系统挂载选项。无论什么文件系统,加上 noatime 或 relatime 几乎总是有益的。每次读取文件都更新其访问时间(atime)会产生大量微小的、随机的写操作,这对性能尤其是 SSD 寿命无益。noatime 完全禁用此功能,relatime 则只在文件被修改后才更新 atime,是一个更安全的折中。
# 在 /etc/fstab 中修改
/dev/sdb1 /data ext4 defaults,noatime,nodiratime 0 2
# 重新挂载
sudo mount -o remount /data
网络:高并发下的连接管理
网络调优在低并发场景下感知不强,但在高并发 Web 服务、API 网关、代理等场景下,几个关键参数能解决大问题。
最常见的问题是连接数耗尽或 TIME_WAIT 状态堆积。下面这三个参数组合是经过大量实践检验的:
- net.core.somaxconn:定义了 socket 监听队列的最大长度。如果服务器在高峰时出现连接被拒绝或延迟建立,而 CPU 和内存都有余量,很可能就是这个队列满了。默认值 128 对于现代 Web 服务来说太小了。
- net.ipv4.tcp_max_syn_backlog:半连接队列大小,需要与
somaxconn配合调整。 - net.ipv4.tcp_tw_reuse 与 net.ipv4.tcp_fin_timeout:前者允许内核复用处于 TIME_WAIT 状态的 socket 用于新的出站连接(对客户端有效),后者控制 FIN-WAIT-2 状态的超时时间。它们有助于缓解短时间内大量短连接导致的端口耗尽问题。
一个针对高并发服务的参考配置如下:
# 添加到 /etc/sysctl.conf
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# 允许重用 TIME_WAIT 套接字(仅对出站连接安全)
net.ipv4.tcp_tw_reuse = 1
# 加快 TCP 连接回收
net.ipv4.tcp_fin_timeout = 30
# 增加 TCP 读写缓冲区大小范围
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
特别注意:net.ipv4.tcp_tw_recycle 这个参数在 RFC 1323 时间戳启用且位于 NAT 网络后时,会导致严重问题,在现代内核中已被废弃,绝对不要启用。
调优的最后一步:验证与回滚
无论你调整了哪个参数,都必须进行验证。调优的目标不是让某个监控指标“看起来更好”,而是提升业务的真实度量,比如:
- API 的平均响应时间和 P99 延迟是否下降?
- 应用吞吐量(QPS/RPS)是否提升?
- 错误率(如 5xx 错误)是否减少?
在修改生产系统前,务必在测试环境用模拟负载进行验证。每次只修改一个变量,观察效果。如果可能,记录下变更前的基准性能数据。
最后,永远准备好回滚方案。对于 sysctl 参数,临时修改在重启后会失效;对于写入配置文件的修改,确保你有备份。如果调整后出现不稳定现象,第一时间回退到已知的稳定状态,而不是尝试用另一个“优化”去修补前一个“优化”。
性能调优是一场与系统复杂性的长期对话,而不是一次性的魔法。理解原理,敬畏生产,用数据和证据驱动决策,你改动的每一个参数才会真正变得“值得”。
原创文章,作者:,如若转载,请注明出处:https://fczx.net/wiki/234