第一百二十七章:航速
问道期涉及内核源码:
一
林小源在网络之海的航道上看到两艘船——一艘飞快地掠过水面,另一艘却缓慢地爬行,像是被什么东西拖住了。
"为什么速度差这么多?"他问旁边的船夫。
船夫是一个满头白发的老人,坐在一艘经过精心调优的船上。船上的帆绷得紧紧的,舵灵敏得像活的一样,船底光滑如镜。
"因为调优。"船夫说,"那艘慢船——缓冲区太小,丢包后不断重传。中断处理太慢,CPU 在处理中断而不是转发数据。拥塞控制算法太保守,带宽用不满。"
"调优具体做什么?"
船夫拍了拍自己的船:"看我这艘——缓冲区调到 16MB,net.core.rmem_max 和 net.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 算。"
林小源看着那艘飞快的船,忽然明白了——网络性能不是单一因素决定的,而是缓冲区、中断、协议栈、硬件卸载等多个因素的综合结果。调优不是改一个参数,而是理解整个系统,找到瓶颈,对症下药。
"没有万能的配置。"船夫说,"每个场景不同——高吞吐量和低延迟的配置不同,局域网和广域网的配置不同,小包和大包的配置不同。你得先测量,再优化。"
/*
* 网络性能调优:
*
* 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");#include <stdio.h>
/*
* 网络性能调优:
*
* 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 卸载
*/
int main() {
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");
return 0;
}道藏笔记
内核启示
网络性能调优需要理解瓶颈。
调优方向:
- 缓冲区 — 大小影响吞吐量和延迟
- 中断 — 减少中断开销
- 协议栈 — 窗口大小、拥塞控制
- 硬件卸载 — TSO、GSO、checksum
监控工具:
- iftop — 网络流量
- ss — socket 统计
- netstat — 网络统计
网络调优是"找瓶颈"的艺术——知道在哪里优化。
网络调优之试
网络调优章中,船夫把拥塞控制算法设置成哪一种以提高带宽利用?