已采纳
回答正文
回复
讨论正文
该问题的正文、回答与讨论。
背景
我在写 tc netem 故障注入的文章时(见引用 #1),梳理内核 RTO 退避和应用超时的交互,发现一个一直没被认真讨论的问题:当应用超时(比如 800ms)先于内核 RTO 退避完成而触发时,应用层发起重试(新建连接或重发),此时内核对原始连接还在做 retransmission——等于同一个逻辑请求在网络上跑了两份。社区里 #1508 讨论过 P99 抖动归因,但焦点在「谁的锅」,没深入到「应用重试 vs 内核重试」的时序冲突。
现象(生产环境实抓)
我们一组 32 个 gRPC 微服务,跨机房 RTT 基线 4.2ms,峰值 QPS 约 6800。某次上联链路出现 500ms 抖动窗口:
nstat -az 增量:TcpRetransSeg +340、TcpTimeouts +12tcp_rto_min=100 但实际 RTO 从 SRTT 算出 200ms 起步)已尝试的排查与结果
net.ipv4.tcp_retries2 从 15 降到 3:理论上 RTO 窗口缩到 ~200+400+800=1.4s,但应用 800ms 还是先超时,double-send 依然存在,问题没解决。另外担心:正常链路偶尔 1-2 次 RTO 是正常的,降到 3 会不会把「差一点就恢复」的连接直接 kill?ss -ti 的 rto 值:确认 RTO 确实从 200ms 起步、指数翻倍,retrans 计数和应用超时触发时间对得上——不是观测误差,是时序设计问题。期望得到的答案形态
tcp_retries2 降到 3 或 4 的生产风险:有没有人实际改过?会不会把「正常 2 次 RTO 后恢复」的连接误杀?跨机房 5ms RTT 和同机房 0.5ms RTT 下这个参数该怎么差异化设?getsockopt(TCP_INFO) 读 tcpi_retrans / tcpi_rto,或者用 eBPF 挂 kprobe/tcp_retransmit_skb 感知内核还在退避,再决定应用层要不要发重试?怎么实现的、性能开销多大?TCP_USER_TIMEOUT 替代应用层定时器)?