TCP 滑动窗口的作用是什么?
- 标签:网络
🏛 业务架构师
滑动窗口是 TCP 可靠传输与流量控制的核心机制,作用可以从两个视角讲:
- 发送方视角:窗口大小=无需等待确认可连续发送的数据量,ACK 确认后窗口向前滑动,继续发送——把"发一段停一次"的串行模式变成流水线并行,网络带宽利用率数量级提升;
- 接收方视角:接收方通过 TCP 头部的 window 字段通告自己的剩余缓冲,发送方据此收缩窗口——这就是流控:接收方处理不过来时,发送自动减速,防止快生产方淹没慢消费方。
业务架构视角,滑动窗口是限流与背压设计的原型,我在多个场景直接复用这个思想:
- 接口限流:滑动窗口计数(按分钟切成 60 个小格)比固定窗口更平滑——固定窗口在边界处可放过双倍流量(上一秒末尾 + 下一秒开头),滑动窗口消除了这个毛刺,保护下游=保护收入;
- 异步系统背压:消费者按处理能力拉取(Kafka 的 fetch.min/max.bytes 本质是窗口协商),生产快于消费时反压到上游,而不是无限堆积打爆存储;
- 批量窗口:攒批发送(每 N 条或每 100ms 触发)提升吞吐,本质也是窗口。
一句话总结:TCP 滑动窗口回答的问题是**"在不压垮对方的前提下,怎么跑满管道"**——这恰好也是一切高并发业务系统的核心命题:限流保护弱势方、窗口批量摊薄成本、ACK 驱动节奏(反馈驱动流量)。把协议机制抽象成业务模式,是架构举一反三能力的来源。
🏗 系统架构师
滑动窗口是 TCP 流量控制的核心机制,作用是让发送方"在接收方可承受的范围内连续发送",本质是用管道化(批量在途数据)换取吞吐,同时避免接收方被冲垮:
- 接收窗口(rwnd):接收方在每个 ACK 里通告自己剩余缓冲区大小,发送方未确认数据量不能超过 rwnd——接收缓冲区满了窗口收缩为 0,发送方暂停(配合窗口探测报文唤醒);
- 发送窗口内数据连续发出不必逐包等 ACK,ACK 确认一段窗口就向前滑动一段,形成"边发边确认"的流水线;
- 与**拥塞窗口(cwnd)**共同决定实际发送量:min(rwnd, cwnd)——流量控制保护对端,拥塞控制保护网络。
工程价值:没有窗口机制,每个 RTT 只能发一个包(停等协议),100ms RTT 链路上 1KB 包吞吐仅 80KB/s;窗口打开后可塞满带宽时延积(BDP)。这也是长肥管道(高带宽高延迟)要调 TCP 缓冲区的原因:跨机房传输大文件吞吐上不去,十有八九是 rwnd/缓冲区太小,而不是带宽不足——调大 buffer 或用多连接并行才能吃满 BDP。我做跨地域数据同步时对这类参数做过专项调优,收益数倍。
💻 全栈开发专家
先区分两件事:滑动窗口做流量控制(对端接收能力),拥塞窗口做网络控制(网络承载能力),实际发送窗口 = min(rwnd, cwnd)。
流量控制滑动窗口的原理:
- 接收方在每个 ACK 里通告自己剩余缓冲区大小(rwnd);
- 发送方维护"已发送未确认"的窗口,窗口内的数据可以连续发,不必每包都等 ACK——把"停等协议"的串行 1RTT/包 变成流水线;
- 累计确认 + 窗口滑动:收到 ACK 后窗口前沿前移,新数据入窗。
它解决的问题:快发送方打慢接收方。没有窗口控制,接收方缓冲区溢出只能丢包重传,白白浪费带宽。
工程关联:
- 长肥管道问题:带宽 × RTT 大的链路(跨机房专线 RTT 50ms),窗口太小就吃不满带宽。需要
window scale选项(窗口扩到 GB 级)和足够大的 socket buffer(net.core.rmem_max)——我调过跨城机房同步吞吐,调缓冲区后从 200Mbps 提到 900Mbps。 - 零窗口死等:接收方窗口为 0 时发送方定时发窗口探测(persist timer),不是干等。
- 拥塞控制的慢启动/拥塞避免/快速恢复控制的其实是 cwnd 这个窗口,和 rwnd 一起决定真实吞吐。