先说为什么要调:把这件事拆成小问题

调优的本质就是找瓶颈、找对症下药、再验证效果。很多时候系统表现不佳不是某个神秘参数作怪,而是几个小环节累积起来——比如 socket 缓冲太小、IRQ 在一台 CPU 上被挤爆、应用线程调度不合理或者 NUMA 内存分配导致延迟抖动。把问题拆开,就能用简单、可验证的改动去解决。
用费曼法简单描述一步
想象网络是条高速公路:内核参数是路面和交管,网卡是入口匝道,应用线程是车辆。我们先看哪个路段拥堵(监控/基线),再扩大匝道、优化信号灯(参数),最后回头看车辆是不是按新线路行驶(应用/线程)。
先做这几项基线检查(必须)
- 监控与采样:收集 CPU、网络(tx/rx)、磁盘、内存、上下文切换、softirq、interrupt、队列长度、套接字等待数(ss -s)等指标。
- 日志与版本:记录内核版本、网卡驱动版本、固件、快连快内核版本和配置快照(/etc/sysctl.conf、/proc/sys/net/*)。
- 重现脚本与负载工具:准备好 iperf3、netperf、wrk/fio/sysbench 等,能稳定复现目标场景。
- 性能快照:用 perf/top/htop/vmstat/iostat/sar/ss 取基线;用 tcpdump/trace-cmd/eBPF 做必要的链路级采样。
调优原则(简单明了)
- 先测后改:一次只改一个或一类相关参数,记录改前改后。
- 小步试验:把变更限定在维护窗口或灰度流量上,避免全量发布导致事故。
- 有回滚:每次变更都提供自动回滚脚本或版本化配置。
- 优先级明确:网络缓冲与连接并发 > IRQ/CPU 亲和 > 应用层线程/异步模型 > 磁盘与内存细节(一般场景)
关键参数类别与解释(你要管的都在这里)
按功能把参数分组,先理解“它干什么”,再看“咋调”:
一、网络栈与 TCP 相关(最常动)
- net.core.rmem_max / net.core.wmem_max:单个 socket 最大接收/发送缓冲,影响单连接吞吐。
- net.core.rmem_default / net.core.wmem_default:默认缓冲,影响新连接。
- net.ipv4.tcp_rmem / tcp_wmem:三个值表示最小、默认、最大;用于动态调整。
- net.ipv4.tcp_congestion_control:拥塞控制算法(bbr、cubic 等),不同场景表现不同。
- net.ipv4.tcp_tw_reuse / tcp_tw_recycle(已弃):TIME_WAIT 重用,能在短连接高并发场景降低端口耗尽(注意安全性)。
- net.core.somaxconn / net.ipv4.tcp_max_syn_backlog:影响 listen 队列长度与 SYN backlog。
二、NIC 与链路层(硬件亲和非常有效)
- ethtool 参数:接收/发送队列大小(-G)、中断合并(-C)、卸载功能(-K,如 tso、gso、gro)、RSS/flow steering 配置。
- 中断亲和(IRQ affinity):把网卡 RX/TX 中断分散到多核上,或绑定到应用业务 CPU。
- 驱动与固件:更新到厂商推荐的稳定版本,某些性能问题源于老驱动。
三、CPU 调度与亲和
- isolcpus/cpuset:隔离关键业务线程与中断,让它们不被普通进程打扰。
- thread/pthread 优先级与调度策略(SCHED_FIFO/SCHED_RR):对实时延迟敏感的线程可适当提升优先级(慎用)。
- IRQ 调整:使用 irqbalance 或手动 echo CPU mask 到 /proc/irq/
/smp_affinity。
四、内存与 NUMA
- HugePages:对频繁分配大内存、减少 TLB miss 有帮助。
- numactl / zone_reclaim / vm.zone_reclaim_mode:控制内存跨 NUMA 分配策略。
- vm.swappiness:影响是否倾向交换,低延迟场景一般降到 10 或更低。
五、文件句柄、端口与内核限制
- fs.file-max、ulimit -n、net.ipv4.ip_local_port_range:确保不会因为端口或文件句柄耗尽而失败。
常用调优命令与如何操作(实例化)
下面给出常见操作方式,按“目的→命令→注意事项”来组织。
1) 临时修改 sysctl(实时验证)
目的:快速验证参数效果。
- 命令示例:sysctl -w net.core.rmem_max=134217728
- 注意:重启后失效,需写入 /etc/sysctl.conf 或使用配置管理工具持久化。
2) 修改网卡队列与卸载
- 查看:ethtool -g eth0 / ethtool -k eth0
- 设置接收队列:ethtool -G eth0 rx 4096 tx 4096(依驱动支持)
- 调中断合并:ethtool -C eth0 rx-usecs 5 rx-frames 8(参数按网卡而异)
- 开/关卸载:ethtool -K eth0 tso off gro off gso off
3) IRQ 亲和与分散
- 查看 irq:grep eth0 /proc/interrupts
- 绑定示例:echo 2 > /proc/irq/45/smp_affinity(以位掩码表示 CPU 集合)
- 注意:和 irqbalance 服务可能冲突,先停掉 irqbalance 再手动设置,或配置 irqbalance 的策略。
4) 应用层并发与 IO 模型
- 事件驱动(epoll/kqueue/IO_uring)在高并发短连接下通常胜出;线程池尺寸按 CPU 核数与 IO 模型调整(一般 1-2x CPU 核心数为起点)。
- 避免频繁创建/销毁线程,用连接复用与长连接降低开销。
推荐的 sysctl 参数示例(表格形式,供参考)
| 参数 | 建议值 | 说明 |
| net.core.rmem_max | 134217728 | 最大接收缓冲(128MB),高带宽-高延迟时需要调大 |
| net.core.wmem_max | 134217728 | 最大发送缓冲 |
| net.ipv4.tcp_rmem | 4096 87380 134217728 | 最小/默认/最大接收缓冲 |
| net.ipv4.tcp_wmem | 4096 65536 134217728 | 发送缓冲 |
| net.core.somaxconn | 1024 | listen 队列长度 |
| net.ipv4.tcp_congestion_control | cubic / bbr | 拥塞控制算法,根据场景选择 |
| vm.swappiness | 10 | 降低交换倾向,延迟敏感系统可调低 |
| fs.file-max | 500000 | 文件句柄上限,按业务调整 |
如何验证改动有效(实测为王)
每次改动后都要做三件事:负载测试、采集对比数据、观察异常日志。
- 使用 iperf3/netperf 测吞吐;wrk/hey/ab 测 http 吞吐与延迟分布;fio 测磁盘 IO。
- 对比 p95/p99 延迟而不是只看平均值;看 softirq 时间、context switch 增减、CPU 利用率和队列长度。
- 在生产灰度流量上再跑一次,确保没有异常连接丢失、超时或内存泄露。
常见问题与排查思路(经验)
- “吞吐没有提升”:通常是应用层成为瓶颈(线程不足、同步逻辑、GC 等),用 flamegraph/perf 查看。
- “延迟抖动增大”:多半是 NUMA 错位、频繁 GC、或 IRQ 被集中到某些核,检查 nodebinding 与 meminfo。
- “短连接高并发时端口耗尽”:扩展 ip_local_port_range、启用 tcp_tw_reuse(注意和 NAT 的兼容性)。
- “网卡卸载引入问题”:部分场景(虚拟化、隧道)需要关掉 TSO/GSO/GRO,确认后再调整。
自动化与持续验证
把变更纳入配置管理(Ansible/Puppet/Chef/Terraform + 模板化 sysctl、ethtool 脚本),并在 CI/CD 中加入性能测试用例。长期运行时把关键指标(p95/p99、softirq、RX/TX drops、socket backlog)做趋势监控,异常时自动回滚或告警。
小技巧与贴士(那些容易忽视的点)
- 备份 /proc/sys 与 /etc/sysctl.conf 的差异,方便回溯每次变更。
- 在高并发场景尽量避免 swap,即使内存看起来不高,也可能因内存碎片触发。
- 升级内核或驱动前在测试环境跑一次完整性能回归测试。
- 在云环境注意虚拟化层(vNIC、虚拟交换)对性能的影响,有时把瓶颈转移到了 hypervisor。
示例调整流程(可直接复制到运维 playbook)
- 在非高峰时段采集 15 分钟基线指标;保存快照。
- 把要改的参数写入临时脚本并同步到测试机,逐个执行并记录结果。
- 在灰度流量下验证 24 小时,若无异常则下发到 10% 流量,再扩大到 50%、100%。
- 整个过程自动记录每次变更的 commit id、操作人员和回滚点。
结语(随手记几句)
调优不是一次性任务,而是一个持续的闭环:度量→假设→修改→验证→发布→监控。快连快内核的参数非常多,但不要“贪多”,把问题拆小、按优先级逐步修复,配合观察与自动化,就能把性能稳定地拉上来。下面这些命令、表格和流程给你当工具箱,实际操作中你会不断迭代出更合适的默认值。
