代理IP出口一切正常,业务却在高并发时偶发超时、部分请求一连就成功部分要重试好几次——多数情况下根因不在代理IP本身,而在目标端口那一侧的两个连接队列。把这两个队列当成”代理IP链路的隐藏带宽”看,很多看似玄学的抖动就解释得通了。
握手里这两个队列扮演什么角色
服务端 listen() 之后,内核会维护两个有上限的队列:收到 SYN 先放进”半连接队列”(backlog),完成三次握手后再移入”全连接队列”等应用 accept。这两个队列的深度都在服务启动时被设定,运行中通常不会动态变化。当连接数逼近上限,新到的 SYN 或已完成握手的连接就会被丢弃或阻塞,表现为客户端偶发的连接超时与重传。
把连接建立过程拆开看,队列的影响是这样一步步累加的:
客户端 → 代理IP出口:代理IP客户端先与目标站完成一次握手,这一步在代理出口侧排队。出口侧若启用连接复用,握手次数会大幅减少,但首次到达新端口时仍要走完整流程。
代理IP出口 → 目标站:真正消耗目标端口队列的是这一步。大量代理IP短连接同时指向同一目标端口,瞬间把半连接队列占满,新 SYN 被悄悄丢弃,客户端看上去就像”网络突然抖了一下”。
服务端 accept 速度:半连接队列即使没满,全连接队列仍可能被应用来不及 accept 而填满。连接建立成功但服务端迟迟不响应,客户端表现为”握手完成了但请求卡住”。
| 队列状态 | 典型现象 | 排查信号 |
|---|---|---|
| 半连接队列溢出 | 新建连接偶发超时,重传后才能成功 | 服务端日志 listen queue overflow、SYN 丢弃计数上涨 |
| 全连接队列溢出 | 握手已完成但首字节迟迟不来 | ss -lnt 显示 Recv-Q 持续高于 Send-Q |
| 队列正常 | 瞬开,耗时稳定 | 两个队列深度长期低位 |
怎么判断是不是队列问题
看 ss -lnt 的 Recv-Q 和 Send-Q:Recv-Q 是已建立但未被应用 accept 的连接数,Send-Q 是队列上限。Recv-Q 长期接近 Send-Q 即可疑。再看目标服务端日志里是否出现 “listen queue overflow” 字样、TCP 的 SYN 丢弃计数是否在高峰期陡增,两者任一命中基本可以下结论。
要把”目标站自身负载”和”代理IP链路”分开验证,最直接的办法是同一时段做两条路径的对比:一条走代理IP、一条直连同一目标端口,看是否只有走代理IP的路径出现抖动。如果是,问题大概率就在队列容量与代理IP并发规模的不匹配上;如果两条都抖,多半是目标站自身问题,代理IP只是把抖动如实放大。
把队列容量、代理IP出口并发、业务节奏这三件事分开看,连接时好时坏的”玄学”就不再玄学。
