服务器与大带宽专家 · 持牌IDC/CDN/ISP服务商
简米科技官网JIANMI TECH
资讯 2026-09-04 更新于 2026-09-04 简米科技 4,909 字 12 分钟阅读

TCP 传输速度慢但带宽还空闲,问题出在哪?如何提高TCP传输效率?

导读TCP 传输速度慢但带宽还空闲,核心问题多半不在带宽,而在延迟、丢包、窗口大小和CPU处理能力共同决定的“单流吞吐上限”上,为什么带宽明明空闲,TCP 就是跑不满?很多人遇到过这种情况:服务器带宽是 1Gbps,实际传输一个文件却只有 20MB/s,带宽监控显示链路使用率不到 20%,表面看是“带宽不够”,TC……

TCP 传输速度慢但带宽还空闲,核心问题多半不在带宽,而在延迟、丢包、窗口大小和CPU处理能力共同决定的“单流吞吐上限”上。

为什么带宽明明空闲,TCP 就是跑不满?

很多人遇到过这种情况:服务器带宽是 1Gbps,实际传输一个文件却只有 20MB/s,带宽监控显示链路使用率不到 20%,表面看是“带宽不够”,TCP 压根没能力把数据塞满链路。

TCP 的传输速度受制于一个简单公式:吞吐量 ≈ 窗口大小 ÷ 往返延迟(RTT),窗口大小是发送方允许未确认的数据量,RTT 是数据包从发送到确认的往返时间,RTT 是 50ms,窗口只有 64KB,那么算下来极限吞吐大约是 10Mbps带宽再大也没用。

这里的核心矛盾在于:TCP 是“确认一包,发一包”的可靠传输协议(滑动窗口机制),它不像 UDP 那样不管不顾地乱发,每次发送后必须等待 ACK 确认,确认回来之前,发送缓冲区的数据不能释放,确认速度取决于 RTT,而 RTT 里包含了网络设备转发延迟、链路物理距离、操作系统协议栈处理时间等多个环节。

排查 TCP 传输慢的常规步骤

遇到“带宽空闲但速度慢”的问题,别急着怀疑运营商,先按下面顺序排查:

  • 用 iperf3 测本机到对端的 TCP 单流带宽,再开 4 个并发流测总带宽,单流远低于多流,基本可以确定是 TCP 窗口/延迟问题。
  • 检查系统当前 TCP 窗口设置:Linux 下执行 sysctl net.ipv4.tcp_wmemsysctl net.ipv4.tcp_rmem,看默认值是否过小。
  • 检查是否启用了 TCP BBR 或 CUBIC 拥塞控制算法,执行 sysctl net.ipv4.tcp_congestion_control
  • 用 ping 测 RTT 和丢包率,注意 ping 的 ICMP 和 TCP 实际 RTT 有差异,更准确的做法是用 tcpping 或抓包看 TCP 握手和 ACK 间隔。
  • 检查网卡队列、中断绑定和 CPU 软中断占用,尤其是多核服务器上单个网卡 IRQ 是否集中在同一 CPU。

TCP 窗口大小:最容易踩的坑

初始窗口和接收窗口的差别

TCP 窗口分为发送窗口和接收窗口,接收方通过 TCP 头里的 Window 字段告诉发送方“我还有多少缓冲区”,如果接收方程序读取数据慢,或者接收缓冲区设置得太小,发送方就会被“限速”。在很多默认 Linux 配置中,接收缓冲区默认值只有 64KB 到 128KB,这对于跨地域、高延迟链路来说完全是杯水车薪。

你可以用 ss -ti 查看当前连接的实际发送窗口和接收窗口大小,看到 cwndssthresh 的数值,cwnd 长期在几十 KB 徘徊,说明拥塞避免算法限制了增长速度。

窗口缩放因子(Window Scaling)是否生效

TCP 头里的 Window 字段只有 16 位,最大只能表示 65535 字节,要支持更大的窗口,必须开启 RFC 1323 定义的

TCP 传输速度慢但带宽还空闲,问题出在哪?如何提高TCP传输效率?

Window Scaling 选项,如果两端有一方不支持或禁用了这个选项,那么即使你设置了 1MB 的缓冲区,实际生效的窗口还是 64KB。

Linux 下默认开启,但某些路由器、防火墙或老旧系统会改写或丢弃带 window scale 选项的 SYN 包,排查方法是抓包看三次握手中的 SYN 和 SYN-ACK 是否带 WSopt 字段,以及缩放因子的值。

实际调整窗口大小的操作

Linux 下修改接收缓冲区(以 root 执行):

sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

其中第二个值是默认窗口,第三个是最大窗口,修改后需要重启应用或让新连接生效,对于长时间传输的大文件,建议把默认窗口也调大,因为很多应用不会主动扩大窗口。

丢包对 TCP 传输速度的影响远超想象

丢包率 1% 时,TCP 带宽直接腰斩

TCP 的拥塞控制算法对丢包极其敏感,丢包意味着发送方认为网络拥塞,会把拥塞窗口减半,然后进入慢启动重新探测,行业共识认为,只要丢包率超过 1%,TCP 单流吞吐量就会下降到原来的 30% 甚至更低,链路空闲不代表没有丢包,可能是交换机的微突发丢包、网卡缓冲区溢出,或者无线链路的干扰。

用 ping 测丢包并不可靠

很多人用 ping 判断链路质量,但 ping 不通不代表 TCP 丢包,ping 通也不代表 TCP 不丢包,因为 ICMP 和 TCP 在路由器上的队列优先级不同,更准确的方法:

  • iperf3 -u 测试 UDP 丢包率,能直接反映网络物理层丢包。
  • ss -i 查看 TCP 连接的 retrans 重传计数,持续增加说明有丢包。
  • 抓包统计数据包重传比例,tcpdump -i eth0 -w tcp.pcap 后用 Wireshark 分析。

局域网 TCP 传输慢如何解决

如果你的场景是内网传文件,丢包率应该很低,但速度仍然上不去,这时候要怀疑以下因素:

  • 交换机端口协商错误:两端协商成了半双工?检查 ethtool eth0 的 Speed 和 Duplex 信息。
  • MTU 不一致:MTU 设置过大,导致 IP 分片或 PMTU 黑洞,重传会拖垮速度,试试把 MTU 从 1500 调整到 1400 对比。
  • 网卡 offload 功能异常:关闭 TCP 校验和卸载功能,对比测试。
  • 硬件中断分配不均:多队列网卡只有部分队列被使用,单核 CPU 软中断满负荷。

操作系统和 TCP 协议栈的隐藏瓶颈

Linux 默认缓冲区太小

Linux 默认的 tcp_rmem 在较老版本内核中甚至只有 85KB 左右,对于百兆带宽、RTT 20ms 的网络,理论需要 250KB 窗口才能跑满,所以默认配置下,即使链路不丢包,速度也上不去,这也是 Linux 里经典的

TCP 传输速度慢但带宽还空闲,问题出在哪?如何提高TCP传输效率?

TCP 传输速度慢怎么办 的首要修法。

调大缓冲区后,注意观察是否影响内存占用,一条高带宽长连接可能占用数十 MB 内存,如果连接数上千,内存压力会很大,生产环境下可以用 sysctl net.ipv4.tcp_autotuning 相关参数控制,但一般不需要手动干预。

BBR 算法在丢包链路下的优势

传统 CUBIC 算法把丢包当作拥塞信号,一旦丢包就猛降窗口,而 Google 推出的 BBR 算法不把丢包作为主要拥塞信号,而是通过测量带宽和延迟来调控发送速率,在高丢包、高延迟链路上能显著提升吞吐。

启用 BBR 的方法:

modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl net.ipv4.tcp_available_congestion_control  # 确认 bbr 是否可用

但 BBR 也并非万能,在深队列路由器环境下可能加剧延迟,需要根据实际场景测试,服务器端和客户端都要支持 BBR 才能生效,实际上只要发送方启用即可,接收方用普通协议栈也能配合。

CPU 和内存对 TCP 吞吐的影响

TCP 传输不是零成本操作,每发一个数据包都要经过系统调用、协议栈处理、网卡驱动、硬件中断、软中断等多个环节,普通 Linux 服务器处理单流的吞吐瓶颈大约在 3-5Gbps 左右,如果用了流控、防火墙、加密隧道,CPU 占用会大幅上升。

检查一下传输时 CPU 占用:top -d 1%si(软中断)和 %us 用户态占用,如果单个核跑满,可以尝试开启 RPS/RFS 把网卡中断分散到多核,或者使用多线程多连接传输。

应用层设计对 TCP 传输速度的影响

单线程读写 VS 多线程并发

很多程序用的是单连接、单线程,从磁盘读数据到 send,再从 recv 写磁盘,这种串行模型效率很低,尤其当磁盘 IO 和网络 IO 互相等待时。如果单个 TCP 连接窗口已经调大,但仍然跑不满带宽,可以尝试在应用层开多个连接,ftp 的 pget 分块下载、axel 多线程下载,或者用 iperf3 -P 8 做并发测试。

Nagle 算法和延迟 ACK 的交互

Nagle 算法会合并小数据包,而 TCP 延迟 ACK 机制会等待 40ms 才回复 ACK,两者叠加时,就会出现经典的 “确认延迟”问题,导致小数据块传输时吞吐极低,对于需要实时性的应用,可以关闭 Nagle:

int flag = 1;
setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, (char)&flag, sizeof(flag));

但注意,关闭 Nagle 会增加大量小包,反而可能降低整体吞吐,适合交互式请求,不适合大文件传输。

磁盘读写速度成为瓶颈

另一个容易忽略的场景是:

TCP 传输速度慢但带宽还空闲,问题出在哪?如何提高TCP传输效率?

TCP 接收窗口、缓冲区都正常,但问题出在磁盘,如果你从 SSD 读文件传输到远端,本地磁盘速度可能只有 200MB/s,而网络带宽能跑到 1Gbps(约 125MB/s),磁盘看似够用,但如果远端接收方也在写盘,磁盘速度就成瓶颈了,可以用 dd if=/dev/zero of=test bs=1M count=1024htop 中的 IO 等待来判断。

TCP 传输慢的常见场景速查表

场景 典型现象 可能原因 优先排查动作
跨地域文件传输 带宽大但单流慢 RTT 高、窗口小 调整 tcp_rmem/tcp_wmem,启用 BBR
内网 NAS 传文件 百兆带宽只有 20Mbps MTU 过大、网卡半双工 检查 ethtool,换 MTU 测试
数据中心服务器同步 千兆带宽跑不满 CPU 软中断集中、内存带宽不足 开启 RPS,绑核
丢包严重的公网链路 ping 延迟高且有丢包 拥塞控制算法不匹配 换用 BBR,尽量用多连接
Windows 与 Linux 互传 Windows 到 Linux 慢 Windows 自动窗口调优冲突 检查 Windows 网络适配器“接收窗口自动调节级别”

TCP 传输速度的常见问题解答

为什么开启了 BBR 以后,TCP 上传速度反而变慢?

BBR 更适合高带宽高延迟且存在随机丢包的链路,如果你的网络丢包率极低、路由器队列很浅,BBR 的探测机制可能造成额外延迟和重传,此时改用 CUBIC 并调大缓冲区,效果会更稳定。

TCP 传输速度慢和 UDP 传输速度慢的排查思路有什么不同?

TCP 涉及窗口、重传、拥塞控制,瓶颈多在协议栈参数和往返延迟上。UDP 没有拥塞控制,速度慢通常直接指向网络丢包或 QoS 限速,排查重点应放在交换机队列策略和运营商限速策略上。

调整 TCP 缓冲区大小后,为什么速度没有立刻提升?

缓冲区参数只对新建连接生效,已建立的连接仍使用旧的窗口值,需要重启应用、重新连接,或者用 ss -ti 观察实际窗口是否变化,如果对端窗口过小,你的缓冲区调得再大也受限于对端。

回到最初的问题:带宽空闲但 TCP 慢,本质上 “链路容量”和“TCP 传输能力”是两回事,链路像一条宽阔的高速公路,TCP 则是一辆严格遵守限速和车距规则的卡车,要想让卡车跑得更快,不能只加宽公路,还要调整司机的驾驶策略也就是窗口、拥塞控制和系统参数,下次遇到类似问题,先从这五个维度排查:窗口大小、丢包率、往返延迟、CPU 处理能力、应用层并发。

分享本文
本文为 简米科技官网 原创,已由运维技术专家审核。转载请注明来源:原文链接
售前咨询 服务热线 售后 邮箱