Skip to content

第一百二十七章:航速

问道期

涉及内核源码:

林小源在网络之海的航道上看到两艘船——一艘飞快地掠过水面,另一艘却缓慢地爬行,像是被什么东西拖住了。

"为什么速度差这么多?"他问旁边的船夫。

船夫是一个满头白发的老人,坐在一艘经过精心调优的船上。船上的帆绷得紧紧的,舵灵敏得像活的一样,船底光滑如镜。

"因为调优。"船夫说,"那艘慢船——缓冲区太小,丢包后不断重传。中断处理太慢,CPU 在处理中断而不是转发数据。拥塞控制算法太保守,带宽用不满。"

"调优具体做什么?"

船夫拍了拍自己的船:"看我这艘——缓冲区调到 16MB,net.core.rmem_maxnet.core.wmem_max。TCP 窗口缩放开启,net.ipv4.tcp_window_scaling = 1。拥塞控制用 BBR,net.ipv4.tcp_congestion_control = bbr。连接队列调大,net.core.somaxconn = 65535。"

"这些都是 sysctl 参数?"

"对。"船夫说,"但调优不是随便改参数——你得先找到瓶颈。CPU 瓶颈?软中断太高?内存瓶颈?缓冲区不足丢包?网络瓶颈?带宽满了?延迟高了?不同的瓶颈,不同的解法。"

"怎么找瓶颈?"林小源问。

船夫从口袋里掏出几件工具:"iftop 看网络流量——哪个连接占了多少带宽。nethogs 看每个进程的网络使用——哪个进程在吃带宽。ss 看 socket 统计——有多少连接,什么状态。netstat -s 看协议栈统计——重传了多少,丢包了多少。"

"还有 。"船夫补充道,"sar -n DEV 看网卡统计——收发了多少包,错误了多少。 看 CPU 热点——协议栈的哪个函数占了最多时间。"

"中断调优呢?"

船夫指着自己的网卡:"多队列网卡——RSS(Receive Side Scaling),把中断分散到多个 CPU。每个 CPU 处理一部分队列,避免单个 CPU 成为瓶颈。如果网卡不支持多队列,可以用 RPS/RFS——软件层面的多队列。"

"中断合并呢?"

"减少中断次数。"船夫说,"网卡收到一个包就中断一次,太频繁了。中断合并让网卡攒几个包再中断一次——减少中断开销,但增加延迟。对高吞吐量的场景有好处,对低延迟的场景可能是坏处。"

"硬件卸载是什么?"林小源看到船夫的船上有一个奇怪的装置。

"TSO——TCP Segmentation Offload。"船夫指着那个装置,"本来 TCP 要把数据分成 MSS 大小的段,每段一个包。有了 TSO,内核把大块数据交给网卡,网卡负责分段。CPU 不用做分段,省了大量计算。"

"还有 GSO?"

"Generic Segmentation Offload。"船夫说,"类似 TSO,但更通用——不限于 TCP。如果网卡不支持 TSO,内核在发送前用 GSO 做软件分段。还有 checksum 卸载——网卡计算校验和,不用 CPU 算。"

林小源看着那艘飞快的船,忽然明白了——网络性能不是单一因素决定的,而是缓冲区、中断、协议栈、硬件卸载等多个因素的综合结果。调优不是改一个参数,而是理解整个系统,找到瓶颈,对症下药。

"没有万能的配置。"船夫说,"每个场景不同——高吞吐量和低延迟的配置不同,局域网和广域网的配置不同,小包和大包的配置不同。你得先测量,再优化。"

c
/*
 * 网络性能调优:
 *
 * 1. 缓冲区调优
 *    net.core.rmem_max — 接收缓冲区最大值
 *    net.core.wmem_max — 发送缓冲区最大值
 *    net.ipv4.tcp_rmem — TCP 接收缓冲区
 *    net.ipv4.tcp_wmem — TCP 发送缓冲区
 *
 * 2. 中断调优
 *    中断合并 — 减少中断次数
 *    RSS — 多队列网卡
 *    RPS/RFS — 软件层面的多队列
 *
 * 3. 协议栈调优
 *    TCP 窗口大小
 *    拥塞控制算法
 *    连接队列大小
 *
 * 4. 硬件卸载
 *    TSO — TCP 分段卸载
 *    GSO — 通用分段卸载
 *    checksum 卸载
 */

printf("=== 网络性能调优 — 提高航速 ===\n\n");

printf("网络性能调优:\n\n");

printf("1. 缓冲区调优:\n");
printf("   net.core.rmem_max = 16777216\n");
printf("   net.core.wmem_max = 16777216\n");
printf("   net.ipv4.tcp_rmem = 4096 87380 16777216\n");
printf("   net.ipv4.tcp_wmem = 4096 65536 16777216\n\n");

printf("2. 中断调优:\n");
printf("   中断合并: 减少中断次数\n");
printf("   RSS: 多队列网卡\n");
printf("   RPS/RFS: 软件多队列\n\n");

printf("3. 协议栈调优:\n");
printf("   net.ipv4.tcp_window_scaling = 1\n");
printf("   net.ipv4.tcp_congestion_control = bbr\n");
printf("   net.core.somaxconn = 65535\n\n");

printf("4. 硬件卸载:\n");
printf("   TSO: TCP 分段卸载\n");
printf("   GSO: 通用分段卸载\n");
printf("   checksum 卸载\n\n");

printf("--- 监控工具 ---\n");
printf("iftop: 网络流量\n");
printf("nethogs: 进程网络使用\n");
printf("ss: socket 统计\n");
printf("netstat: 网络统计\n\n");

printf("--- 瓶颈分析 ---\n");
printf("CPU 瓶颈:\n");
printf("  软中断高\n");
printf("  协议栈处理慢\n\n");
printf("内存瓶颈:\n");
printf("  缓冲区不足\n");
printf("  丢包\n\n");
printf("网络瓶颈:\n");
printf("  带宽满\n");
printf("  延迟高\n");

道藏笔记

内核启示

网络性能调优需要理解瓶颈。

调优方向:

  • 缓冲区 — 大小影响吞吐量和延迟
  • 中断 — 减少中断开销
  • 协议栈 — 窗口大小、拥塞控制
  • 硬件卸载 — TSO、GSO、checksum

监控工具:

  • iftop — 网络流量
  • ss — socket 统计
  • netstat — 网络统计

网络调优是"找瓶颈"的艺术——知道在哪里优化。


破关试炼

网络调优之试

网络调优章中,船夫把拥塞控制算法设置成哪一种以提高带宽利用?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道