5. 传输层:TCP协议实现深度拆解

TCP(Transmission Control Protocol,传输控制协议)是互联网的核心基石,也是Linux网络协议栈中最复杂、最成熟的传输层协议。它基于IP层的不可靠数据包传输,实现了面向连接、端到端的可靠字节流传输,保证数据的有序、无丢失、无重复、无差错交付,同时通过流量控制、拥塞控制机制,适配不同的网络环境,平衡吞吐量与延迟。
我们日常使用的HTTP/HTTPS、数据库、微服务RPC、文件传输等绝大多数业务,都基于TCP协议实现。生产环境中90%以上的网络问题,都与TCP协议的内核实现、参数配置、状态管理相关。本章节基于Linux 6.6 LTS内核,源码覆盖net/ipv4/tcp.h(核心数据结构)、net/ipv4/tcp_input.c(接收处理)、net/ipv4/tcp_output.c(发送处理)、net/ipv4/tcp_cong.c(拥塞控制)四大核心路径,深度拆解TCP协议的内核实现原理,同时提供生产环境的问题排查、性能调优、避坑指南。

5.1 TCP的核心设计目标与协议特性

TCP的设计完全围绕「在不可靠的IP网络上,实现可靠的端到端字节流传输」这一核心目标,衍生出五大核心协议特性,所有内核实现都围绕这些特性展开:
  1. 面向连接:通信双方必须先通过三次握手建立连接,才能传输数据;数据传输完成后,通过四次挥手断开连接,释放内核资源。内核会为每个TCP连接维护独立的连接状态、缓冲区、定时器、统计信息,实现端到端的独立通信。
  2. 可靠传输:通过序列号、确认应答、超时重传、校验和机制,保证数据100%完整交付,不会出现丢失、重复、乱序。哪怕IP层出现丢包、错包、乱序,TCP也能自动恢复,对上层应用完全透明。
  3. 有序字节流:TCP把上层应用的数据看做无边界的字节流,不保留消息边界,保证接收端收到的字节顺序,和发送端写入的顺序完全一致。上层应用无需处理乱序问题,只需按字节流读取即可。
  4. 流量控制:通过滑动窗口机制,保证发送端的发送速率不超过接收端的处理能力,避免发送端发送过快,导致接收端缓冲区溢出、数据包被丢弃。
  5. 拥塞控制:通过拥塞控制算法,实时探测网络的带宽、延迟、丢包情况,动态调整发送速率,避免发送过多数据包导致网络拥塞,最大化利用网络带宽,同时保证网络的公平性。

5.2 TCP核心数据结构深度拆解

Linux内核中,TCP连接的所有状态、配置、缓冲区、统计信息,都存储在struct tcp_sock结构体中。它是struct sock的继承与扩展,通过结构体嵌套实现了面向对象的协议扩展,完整定义在include/net/tcp.h中。
这里拆解生产环境与原理理解最核心的字段,剔除调试、统计类非核心字段,同时衔接前序章节的struct sock结构:
// TCP传输控制块,继承自struct inet_sock → struct sock
struct tcp_sock {
    // ===================== 1. 继承的基础结构 =====================
    struct inet_sock inet;  // IPv4专用结构,包含源目IP、端口等信息

    // ===================== 2. 连接状态核心字段 =====================
    u8		tcp_state;      // TCP连接状态,对应11种标准状态(ESTABLISHED/TIME_WAIT等)
    u8		repair;         // 连接修复状态,用于TCP连接迁移
    __be16		sport;         // 源端口
    __be16		dport;         // 目的端口
    u32		flags;          // TCP连接全局标志位,如TSO开启、SACK支持等

    // ===================== 3. 序列号核心字段(可靠传输的基石) =====================
    u32		snd_nxt;        // 下一个要发送的序列号
    u32		snd_una;        // 已发送但未收到ACK的最小序列号(发送窗口左边界)
    u32		snd_wnd;        // 对端通告的发送窗口大小(字节)
    u32		rcv_nxt;        // 下一个期望接收的序列号(接收窗口左边界)
    u32		rcv_wnd;        // 本机通告的接收窗口大小(字节)
    u32		write_seq;      // 应用层写入的最高序列号
    u32		acked_seq;      // 已收到ACK确认的最高序列号
    u32		fin_seq;        // FIN包的序列号,用于连接关闭

    // ===================== 4. 窗口与流量控制字段 =====================
    u32		snd_wl1;        // 上次窗口更新的序列号
    u32		snd_wl2;        // 上次窗口更新的ACK序列号
    u32		mss_cache;      // 缓存的MSS(最大分段大小),避免重复计算
    u16		advmss;         // 向对端通告的MSS
    u8		window_clamp;   // 接收窗口的最大上限,用于窗口缩放
    u32		rcv_wup;        // 上次接收窗口更新的序列号
    __u32		rcv_wnd_space;  // 接收缓冲区的剩余可用空间

    // ===================== 5. 拥塞控制核心字段 =====================
    u32		snd_cwnd;       // 拥塞窗口大小(单位:MSS),核心控制发送速率
    u32		snd_ssthresh;    // 慢启动阈值,区分慢启动和拥塞避免阶段
    u32		prior_cwnd;     // 拥塞前的拥塞窗口,用于丢包后恢复
    u32		prr_delivered;  // 比例降速恢复(PRR)的已交付数据包数
    u32		prr_out;        // PRR的已发送数据包数
    const struct tcp_congestion_ops *ca_ops;  // 拥塞控制算法操作集(BBR/CUBIC等)
    u32		ca_priv[16];    // 拥塞控制算法的私有数据区

    // ===================== 6. 重传机制核心字段 =====================
    u32		retrans_out;    // 正在重传的数据包数量
    u32		lost_out;       // 标记为丢失的数据包数量
    u32		sacked_out;     // 被SACK标记的数据包数量
    u8		dupacks;        // 重复ACK的数量,用于快速重传
    u32		rto;            // 当前的RTO(重传超时时间),单位毫秒
    u32		srtt;           // 平滑后的RTT(往返时间),单位微秒
    u32		mdev;           // RTT的平均偏差,用于RTO计算
    u32		mdev_max;       // 最大RTT偏差
    u32		rttvar;         // RTT方差,RTO计算的核心参数

    // ===================== 7. 定时器核心字段 =====================
    struct timer_list	retrans_timer;   // 重传定时器,超时触发重传
    struct timer_list	delack_timer;    // 延迟ACK定时器
    struct timer_list	timewait_timer;  // TIME_WAIT状态定时器
    unsigned long		timeout;         // 超时时间戳
    int			icsk_retransmits;  // 重传次数计数
    int			icsk_syn_retries;  // SYN包重传次数

    // ===================== 8. 队列核心字段 =====================
    struct sk_buff_head	out_of_order_queue;  // 乱序接收队列,存储乱序到达的数据包
    struct sk_buff_head	write_queue;         // 发送队列,待发送的数据包
    struct sk_buff_head	retransmit_queue;    // 重传队列,已发送未收到ACK的数据包
};

核心字段深度解析:
  1. 序列号四元组:snd_una、snd_nxt、rcv_nxt、rcv_wnd是TCP可靠传输的核心,定义了发送窗口和接收窗口的边界,所有的发送、接收、确认逻辑都基于这四个字段展开。
  2. 拥塞窗口snd_cwnd:TCP发送速率的核心控制字段,单位是MSS。TCP的实际发送窗口 = min(对端通告的接收窗口snd_wnd, 拥塞窗口snd_cwnd),也就是「流量控制」和「拥塞控制」的最小值,保证既不超过接收端的处理能力,也不超过网络的承载能力。
  3. RTT与RTO:srtt是平滑后的往返时间,rto是重传超时时间。Linux内核通过srtt和RTT方差动态计算RTO,最小RTO为200ms,最大为120s,超时后会触发重传,同时指数退避延长RTO。
  4. 三大核心队列:
  • write_queue:应用层写入、等待发送的数据包队列;
  • retransmit_queue:已发送但未收到ACK的数据包队列,用于超时重传;
  • out_of_order_queue:乱序到达的数据包队列,TCP会等待缺失的数据包到达后,再按序交给上层应用。

5.3 TCP连接生命周期管理

TCP连接的生命周期分为三个阶段:连接建立(三次握手)、数据传输、连接断开(四次挥手),内核为每个阶段维护对应的连接状态,同时处理各种异常场景。生产环境中绝大多数的连接问题(连接超时、被拒绝、TIME_WAIT/CLOSE_WAIT堆积),都源于对连接生命周期内核实现的认知不足。
5.3.1 连接建立:三次握手的内核全流程
TCP三次握手的核心目标是:同步通信双方的初始序列号(ISN)、协商MSS、窗口缩放、SACK等TCP选项,同时验证双方的收发能力,建立可靠的连接。
Linux内核中,三次握手分为服务端监听流程和客户端连接流程,完整链路如下:
1. 服务端监听准备

1.服务端调用socket()创建TCP监听Socket,内核初始化tcp_sock结构,状态设置为TCP_CLOSE;

2.调用bind()绑定IP和端口,内核校验端口权限、端口占用情况,更新tcp_sock的源端口、IP;

3.调用listen()将Socket状态设置为TCP_LISTEN,初始化两个核心队列:

  • 半连接队列(SYN队列):存储已收到客户端SYN、已回复SYN+ACK、等待客户端ACK的连接,状态为TCP_SYN_RECV;
  • 全连接队列(ACCEPT队列):存储已完成三次握手、等待服务端accept()取出的连接,状态为TCP_ESTABLISHED;

4.服务端调用accept()阻塞等待,等待全连接队列中有新的连接。

2. 三次握手完整内核流程
客户端 → 发送SYN包(ISN=c,SYN标志位=1) → 服务端
客户端 ← 回复SYN+ACK包(ISN=s,ACK=c+1,SYN+ACK标志位=1) ← 服务端
客户端 → 发送ACK包(ACK=s+1,ACK标志位=1) → 服务端

内核逐包处理逻辑:

1.第一次握手:客户端SYN → 服务端

  • 客户端调用connect(),内核创建tcp_sock结构,随机生成初始序列号ISN,封装SYN包发送,状态设置为TCP_SYN_SENT;
  • 服务端网卡收到SYN包,经过协议栈处理后,进入TCP层tcp_v4_do_rcv()函数;
  • 服务端校验SYN包合法性,检查监听端口、半连接队列是否已满,若队列满且未开启syncookies,直接丢弃SYN包;
  • 服务端随机生成自己的初始序列号ISN,分配struct request_sock请求结构,放入半连接队列,回复SYN+ACK包,状态设置为TCP_SYN_RECV;
  • 开启重传定时器,若超时未收到客户端ACK,会重传SYN+ACK包,重传次数由tcp_synack_retries控制(默认5次)。

2.第二次握手:服务端SYN+ACK → 客户端

  • 客户端收到SYN+ACK包,校验ACK序列号是否正确,更新自己的tcp_sock序列号、窗口信息;
  • 客户端状态从TCP_SYN_SENT更新为TCP_ESTABLISHED,回复第三次握手的ACK包;
  • 客户端Socket已完成连接建立,可调用send()发送数据。

3.第三次握手:客户端ACK → 服务端

  • 服务端收到ACK包,校验序列号是否正确,从半连接队列中取出对应的request_sock结构;
  • 服务端创建新的tcp_sock结构,初始化序列号、窗口、MSS等信息,状态设置为TCP_ESTABLISHED;
  • 把新的连接放入全连接队列,唤醒阻塞在accept()的服务端进程;
  • 服务端accept()取出全连接队列中的连接,返回新的文件描述符,连接正式建立完成,可进行数据传输。
生产环境高频问题:连接被拒绝
现象:客户端并发连接过高时,出现connection refused错误,服务端netstat -s看到times the listen queue of a socket overflowed计数增长。
根因:全连接队列/半连接队列溢出,核心配置如下:
  • 全连接队列最大长度 = min(net.core.somaxconn, listen()的backlog参数);
  • 半连接队列最大长度 = max(net.ipv4.tcp_max_syn_backlog, 表项上限);
    解决方案:
  1. 调大net.core.somaxconn到4096,同时应用层listen()的backlog参数同步调大;
  2. 调大net.ipv4.tcp_max_syn_backlog到8192;
  3. 开启net.ipv4.tcp_syncookies = 1,半连接队列满时,用syncookies机制处理SYN包,避免连接被丢弃;
  4. 优化服务端accept()处理逻辑,避免accept线程阻塞,及时取出全连接队列的连接。
5.3.2 连接断开:四次挥手的内核全流程
TCP是全双工通信,连接断开需要双方分别关闭自己的发送通道,因此需要四次挥手。分为主动关闭方和被动关闭方,内核为每个阶段维护对应的状态,完整流程如下:
主动关闭方 → 发送FIN包(FIN标志位=1) → 被动关闭方
主动关闭方 ← 回复ACK包(ACK标志位=1) ← 被动关闭方
主动关闭方 ← 发送FIN包(FIN标志位=1) ← 被动关闭方
主动关闭方 → 回复ACK包(ACK标志位=1) → 被动关闭方

内核逐阶段处理逻辑:

1.第一次挥手:主动关闭方发送FIN

  • 主动关闭方调用close(),内核发送FIN包,状态从TCP_ESTABLISHED更新为TCP_FIN_WAIT1;
  • 主动关闭方关闭自己的发送通道,不能再向被动关闭方写入数据,但仍可以接收数据。

2.第二次挥手:被动关闭方回复ACK

  • 被动关闭方收到FIN包,内核回复ACK包,状态从TCP_ESTABLISHED更新为TCP_CLOSE_WAIT;
  • 被动关闭方的接收通道关闭,read()会返回EOF,通知应用层连接即将关闭;
  • 主动关闭方收到ACK包,状态从TCP_FIN_WAIT1更新为TCP_FIN_WAIT2,等待被动关闭方的FIN包。

3.三次挥手:被动关闭方发送FIN

  • 被动关闭方调用close(),内核发送FIN包,状态从TCP_CLOSE_WAIT更新为TCP_LAST_ACK;
  • 被动关闭方关闭自己的发送通道,不能再向主动关闭方写入数据。

4.第四次挥手:主动关闭方回复ACK

  • 主动关闭方收到FIN包,内核回复ACK包,状态从TCP_FIN_WAIT2更新为TCP_TIME_WAIT;
  • 被动关闭方收到ACK包,状态从TCP_LAST_ACK更新为TCP_CLOSE,连接完全关闭,释放内核资源;
  • 主动关闭方进入TIME_WAIT状态,等待2MSL(最长报文寿命,默认60s)后,状态更新为TCP_CLOSE,释放内核资源。
生产环境两大高频问题
1. TIME_WAIT状态连接堆积
现象:短连接场景下,ss -s看到TIME_WAIT连接数达到数万,客户端无法建立新连接,报错cannot assign requested address。
根因:主动关闭方会进入TIME_WAIT状态,停留2MSL,短连接场景下大量连接快速关闭,导致TIME_WAIT堆积,占用本地端口和内核资源,最终端口耗尽。
解决方案:
  1. 客户端场景:开启net.ipv4.tcp_tw_reuse = 1,允许将TIME_WAIT状态的端口用于新的TCP连接,这是最安全的优化方式;
  2. 架构优化:短连接改长连接复用(如HTTP Keep-Alive、数据库连接池),从根源减少TIME_WAIT的产生;
  3. 调大本地端口范围:net.ipv4.ip_local_port_range = 1024 65535,增加可用端口数量;
  4. 注意:Linux 4.12+内核已移除tcp_tw_recycle参数,该参数在NAT场景下会导致大量连接失败,禁止使用。
2. CLOSE_WAIT状态连接堆积
现象:服务端ss -s看到CLOSE_WAIT连接数持续增长,最终耗尽进程的文件句柄,无法建立新连接。
根因:被动关闭方收到FIN包后,内核回复了ACK,但应用层没有调用close()关闭Socket,导致连接一直停留在CLOSE_WAIT状态,内核无法释放资源。这是100%的应用层代码bug,和内核参数无关。
解决方案:
  1. 排查应用层代码,确保所有Socket的异常分支、EOF场景都有对应的close()逻辑;
  2. 给Socket设置SO_KEEPALIVE保活机制,检测到对端断开后自动关闭连接;
  3. 监控进程的CLOSE_WAIT连接数,超过阈值触发告警,及时定位代码问题。

5.4 TCP可靠传输核心机制

TCP的可靠传输,基于四大核心机制实现:序列号与确认应答、滑动窗口、流量控制、超时重传,所有机制都围绕「保证数据有序、无丢失、无重复」展开。
5.4.1 序列号与确认应答机制
TCP把发送的每个字节都分配了唯一的序列号,接收端通过确认应答(ACK)机制,告知发送端已经成功收到的字节序列号,实现可靠传输。
  • 核心规则:
  1. 发送端发送的每个TCP包,都包含本次数据的起始序列号和数据长度;
  2. 接收端收到数据后,回复ACK包,ACK序列号 = 已成功收到的最高序列号 + 1,代表这个序列号之前的所有字节都已成功接收;
  3. 发送端收到ACK后,就可以释放对应序列号的数据包,无需再保留重传副本;
  4. 若发送端超时未收到ACK,会触发重传机制,重新发送对应的数据包。
  • 核心优势:通过累计确认机制,哪怕ACK包丢失,只要后续的ACK包到达,发送端就能确认之前的数据都已收到,无需重传,提升传输效率。
5.4.2 滑动窗口与流量控制
流量控制的核心目标是:保证发送端的发送速率不超过接收端的处理能力,避免发送端发送过快,导致接收端的Socket接收缓冲区溢出,数据包被丢弃。
TCP通过滑动窗口机制实现流量控制,核心是「接收窗口」:
  1. 接收端在ACK包中,通过Window字段,通告自己当前的接收缓冲区可用空间大小,也就是接收窗口rcv_wnd;
  2. 发送端的发送窗口上限,就是接收端通告的接收窗口大小,发送端已发送未收到ACK的数据量,不能超过这个窗口大小;
  3. 随着接收端应用层读取数据,接收缓冲区可用空间增加,接收窗口会向右滑动,通告更大的窗口大小;
  4. 发送端收到新的窗口通告后,发送窗口也向右滑动,发送更多的数据。
核心问题解决:
  • 糊涂窗口综合征:当接收端缓冲区只剩少量空间时,会通告很小的窗口,发送端发送小数据包,导致网络中充斥大量小包,带宽利用率极低。Linux内核通过Clark算法解决:接收端只有当可用空间达到MSS的一半时,才会通告非零的窗口;发送端只有当数据大小达到MSS,或者窗口足够大时,才会发送数据,避免小包发送。
  • 零窗口处理:当接收端缓冲区满时,会通告零窗口,发送端停止发送数据,开启持续定时器,定期发送窗口探测包,直到接收端通告新的非零窗口,恢复发送。

5.5 TCP拥塞控制深度拆解

流量控制解决的是「发送端与接收端」的速率匹配问题,而拥塞控制解决的是「发送端与整个网络」的速率匹配问题,核心目标是:在不造成网络拥塞的前提下,最大化利用网络带宽,同时保证网络的公平性。
Linux内核实现了可插拔的拥塞控制框架,通过struct tcp_congestion_ops结构体定义拥塞控制算法的标准接口,支持动态加载、切换算法,无需重新编译内核。
6.5.1 拥塞控制的核心框架
TCP拥塞控制分为四个核心阶段,所有算法都基于这个基础框架实现:
  1. 慢启动阶段:连接建立后,拥塞窗口cwnd从初始值(默认10个MSS)开始,每收到一个ACK,cwnd翻倍,呈指数增长,快速探测网络带宽;
  2. 拥塞避免阶段:当cwnd达到慢启动阈值ssthresh后,进入拥塞避免阶段,cwnd线性增长(每个RTT增加1个MSS),缓慢增加发送速率,避免网络拥塞;
  3. 拥塞触发阶段:当检测到网络丢包(超时重传、3个重复ACK),判定网络出现拥塞,降低慢启动阈值,减小拥塞窗口,降低发送速率;
  4. 快速恢复阶段:快速重传触发后,进入快速恢复阶段,通过PRR(比例降速恢复)算法调整cwnd,避免拥塞窗口降得过低,快速恢复发送速率。
5.5.2 主流拥塞控制算法对比与选型
Linux内核中,生产环境最主流的两个算法是CUBIC和BBR,也是内核默认支持的算法,详细对比与选型如下:

特性

CUBIC(内核默认)

BBR

核心原理

基于三次函数的拥塞窗口增长,以丢包作为拥塞信号,丢包时降低窗口

基于带宽和最小RTT探测,不以丢包作为拥塞信号,以网络的最大带宽和最小延迟作为发送速率的依据

核心优势

高带宽长延迟网络中表现稳定,带宽利用率高,对不同网络环境的兼容性好,公平性强

不依赖丢包调整速率,在有随机丢包的广域网、跨地域网络中,带宽利用率远高于CUBIC,重传率更低,延迟更稳定

劣势

把随机丢包判定为拥塞,在有丢包的无线网络、跨地域网络中,会过度降低发送速率,带宽利用率低

在内网、低延迟无丢包的网络中,表现不如CUBIC;多流场景下的公平性略差于CUBIC;需要配合fq_codel排队规则使用

最佳适用场景

内网IDC环境、局域网、数据中心内部通信、无随机丢包的稳定网络

广域网、跨地域网络、CDN、大文件传输、有随机丢包的无线网络、跨境通信

配置方法:
# 查看内核支持的拥塞控制算法
cat /proc/sys/net/ipv4/tcp_available_congestion_control
# 临时设置默认拥塞控制算法为BBR
sysctl -w net.ipv4.tcp_congestion_control=bbr
# 永久配置,写入/etc/sysctl.conf
net.ipv4.tcp_congestion_control = bbr
# 配合BBR使用,开启FQ排队规则
tc qdisc replace dev eth0 root fq

5.6 工程实践:TCP生产环境调优与问题排查

5.6.1 生产环境核心调优参数
以下是Linux 6.6内核TCP协议栈的最佳实践调优参数,适用于绝大多数服务器场景,写入/etc/sysctl.conf永久生效:
# ===================== 连接管理参数 =====================
# 全连接队列最大长度
net.core.somaxconn = 4096
# 半连接队列最大长度
net.ipv4.tcp_max_syn_backlog = 8192
# 开启syncookies,应对SYN洪水攻击
net.ipv4.tcp_syncookies = 1
# SYN包重传次数
net.ipv4.tcp_syn_retries = 3
# SYN+ACK包重传次数
net.ipv4.tcp_synack_retries = 2
# 允许TIME_WAIT端口复用
net.ipv4.tcp_tw_reuse = 1
# TIME_WAIT超时时间,默认60s
net.ipv4.tcp_fin_timeout = 30
# 系统最大TIME_WAIT连接数
net.ipv4.tcp_max_tw_buckets = 262144

# ===================== 缓冲区与窗口参数 =====================
# Socket接收缓冲区默认值/最小值/最大值
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
# Socket发送缓冲区默认值/最小值/最大值
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
# TCP接收缓冲区:最小值/默认值/最大值
net.ipv4.tcp_rmem = 4096 262144 16777216
# TCP发送缓冲区:最小值/默认值/最大值
net.ipv4.tcp_wmem = 4096 262144 16777216
# 开启TCP窗口缩放,支持大带宽长延迟网络
net.ipv4.tcp_window_scaling = 1

# ===================== 可靠传输与重传参数 =====================
# 开启SACK选择性确认,提升丢包重传效率
net.ipv4.tcp_sack = 1
# 开启DSACK,检测重复包和虚假重传
net.ipv4.tcp_dsack = 1
# 开启FACK,前向重传,提升重传效率
net.ipv4.tcp_fack = 1
# TCP数据重传最大次数
net.ipv4.tcp_retries2 = 8
# 最小RTO,默认200ms
net.ipv4.tcp_min_rto = 200

# ===================== 拥塞控制参数 =====================
# 默认拥塞控制算法
net.ipv4.tcp_congestion_control = bbr
# 开启TCP时间戳,提升RTT计算精度
net.ipv4.tcp_timestamps = 1
# 开启ECN显式拥塞通知
net.ipv4.tcp_ecn = 1

# ===================== 保活机制参数 =====================
# TCP保活探测时间(连接空闲2小时后开始探测)
net.ipv4.tcp_keepalive_time = 7200
# 保活探测间隔
net.ipv4.tcp_keepalive_intvl = 75
# 保活探测失败次数,超过后断开连接
net.ipv4.tcp_keepalive_probes = 9
5.6.2 高频问题标准化排查流程
1. TCP重传率过高
现象:cat /proc/net/snmp | grep TcpRetransSegs看到重传段数持续增长,重传率超过2%,业务延迟升高、吞吐量下降。
排查流程:
  1. 确认丢包位置:用mtr/traceroute检测链路的丢包率,定位是内网、运营商、还是对端网络的丢包;
  2. 检查链路质量:用ping -f检测链路的延迟抖动、丢包情况,确认是否有随机丢包;
  3. 检查拥塞控制算法:广域网场景切换到BBR算法,内网场景使用CUBIC;
  4. 检查网卡与驱动:用ethtool -S eth0查看网卡是否有丢包、错误,是否有协商错误;
  5. 检查防火墙/TC规则:确认是否有限速、丢包规则导致的丢包;
  6. 优化参数:开启SACK/DSACK,调大TCP发送/接收缓冲区,优化MSS配置。
2. TCP连接超时
现象:客户端连接服务端超时,telnet/curl连接失败,报错connection timed out。
排查流程:
  1. 网络连通性检查:用ping/telnet检查服务端IP、端口是否可达,确认是否有防火墙拦截;
  2. 服务端监听检查:用ss -tulnp检查服务端是否在正确的IP、端口上监听;
  3. 连接队列检查:用netstat -s查看是否有监听队列溢出,调大somaxconn和backlog参数;
  4. 路由检查:用ip route检查客户端和服务端的路由是否正确,是否有路由不可达;
  5. 安全组/防火墙检查:确认服务端iptables、云厂商安全组是否放行了对应端口的访问;
  6. 内核参数检查:确认tcp_syn_retries、tcp_synack_retries是否设置过大,导致超时时间过长。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐