小包的问题不是「慢」,是「头比数据还多」:1 个字节要配 40 字节头。 Nagle 和延迟确认能省包,但两者同时开会互相等,这是一个经典的坑。
6.4.9 讲的是「别把网络淹了」,这一节讲「别把网络浪费了」。 6.1.2 算过封装开销,这一节讲「怎么把开销摊薄」。
一、小包的浪费有多严重
1 字节数据加 40 字节头,有效占比只有 2.4%:如果每个字节都单独发一个包,网络基本在传头。 这种用法在「远程登录」时代非常常见——敲一个键发一个包,每个包 41 字节。 问题不只是浪费带宽,还有「包数」:路由器处理的是「包」,不是「字节」, 所以一万个小包比一个大包消耗更多处理能力。 这就是「小包攻击」能拖垮设备的原理——它不需要大流量,只需要大量小包。
二、三个省包的技巧
| 技巧 | 做什么 | 代价 |
|---|---|---|
| Nagle 算法 | 小包攒着一起发 | 最后一个可能多等 |
| 延迟确认 | 确认攒着一起回 | 发送方等确认更久 |
| 捎带确认 | 确认搭在数据包上 | 没数据可搭就白等 |
第一行的规则很具体:「已经发出去但还没被确认的小包,先攒着」。 等确认回来,或者攒够一个 MSS,再一起发。 它把「很多小包」变成「一个大包」,代价是「最后一个包要多等一个往返」。 第三行是最理想的:「我正好有数据要发,就顺手把确认带上」,这样确认不占额外的包。 但「正好有数据」是可遇不可求的,所以它只是「省一点」,不能当主力。
三、那个经典的坑
Nagle 和延迟确认同时开,会互相等: 发送方等确认才发下一个小包,接收方等「有数据或超时」才回确认。 结果谁都不动,卡到超时。 所以「一问一答」的协议里,这两个至少要关一个: 要么关 Nagle(TCP_NODELAY),要么关延迟确认。 实际做法通常是前者——因为 Nagle 在「请求响应」模式里本来就没什么收益。 这也是「游戏和交易系统都要关 Nagle」的原因:它们宁可多传几个头,也不愿多等那几十毫秒。 所以在这些场景里,「省包」和「低延迟」是直接冲突的——没有两全的方案,只能按需求取舍。
四、动手 Demo:一个字节也要 40 个字节的头
算四种载荷下的有效占比。 第一行只有 2.4%,这就是 Nagle 想解决的问题。
for payload in (1, 2, 10, 100):
total = payload + 40
print('%4d 字节 -> 线路 %3d 字节,有效 %5.1f%%'
% (payload, total, 100.0 * payload / total))
实跑输出:
--------------------------------------------------------------------
一个字节也要 40 个字节的头
--------------------------------------------------------------------
**「小包」的效率问题是 TCP 的老毛病**:**头和载荷的比例太悬殊。**
应用数据 线路上合计 有效占比
-------------------------------------
1 41 2.4%
2 42 4.8%
10 50 20.0%
100 140 71.4%
**第一行只有 2.4% 是「有用的」**:**如果每个字节都单独发一个包,网络基本是在传头。**
**这种用法在「远程登录」时代很常见**——**敲一个键发一个包,每个包 41 字节。**
**Nagle 算法的做法很直接**:**「发出去但还没被确认的小包,先攒着」**,
**等确认回来或者攒够一个 MSS 再一起发。**
**它把「很多小包」变成「一个大包」**,**代价是「最后一个包可能要多等一会儿」。**
**所以游戏和交易系统会关掉它**(TCP_NODELAY),**宁可多传头,也要少等那几十毫秒。**
**这里有个经典的坑**:
**Nagle 和「延迟确认」同时开,会互相等**——**发送方等确认才发小包,接收方等数据才回确认**,
**结果谁都不动,卡到超时。**
**所以在「一问一答」的协议里,这两个至少要关一个。**
「有效占比」这个指标比「带宽」更贴近真实体验: 因为「有效数据少」意味着「同样的带宽传不了多少东西」。 所以「小包业务占满带宽但没用」是真实现象。 注意 100 字节那一行也只有 71%:所以「包大一点」的收益是连续的, 不是「小包很差、大包就好」。 这也是「MTU 越大越好」的直觉来源,只是实际受路径限制。 最后一个提醒:「关掉 Nagle」不是「永远更好的选择」。批量传输时开着它,能显著减少包数; 只有「一问一答」和「实时交互」才该关。 所以这个开关要按业务类型决定,不能一刀切。
30 秒实验
- 算一下:10 字节数据走 TCP,有效占比是多少?
- 想一下:Nagle 和延迟确认为什么会互相等?
- 想一下:什么业务应该关掉 Nagle?
常见误区
- 以为「Nagle 总是好的」。 它增加延迟,实时业务要关掉。
- 以为「关掉 Nagle 就没有延迟问题」。 延迟确认还会在,两个要一起看。
- 以为「小包只是浪费带宽」。 还浪费路由器的处理能力,包数比字节数更影响设备。
自测三问(点开对答案)
1. Nagle 算法的规则是什么? —— **已发出但未确认的小包先攒着**,等确认回来或攒够一个 MSS 再发。 2. Nagle 和延迟确认为什么会死等? —— **一个等确认才发,一个等数据才回确认**,双方互相等,卡到超时。 3. 什么时候该关掉 Nagle? —— **实时交互的业务**:游戏、交易、远程操作,宁可多传头也不愿多等。下一节看哪些应用跑在 TCP 上。
- ☐ (本节完,下一节 6.4.11 使用TCP的应用)