从 TCP 重传率看服务偶发超时
线上有个接口偶尔超时,QPS 不高,P99 却会突然冲到两秒以上。翻应用日志没有报错,数据库连接池也正常。最后是在 TCP 层找到的原因。
先确认有没有重传
netstat -s 的输出太杂,nstat 更直接:
nstat -az TcpRetransSegs TcpOutSegs
-a 是把计数器全打出来,-z 是不显示零值。想算比例就自己除一下:
awk '/TcpRetransSegs/{r=$2} /TcpOutSegs/{o=$2} END{printf "%.4f%%\n", r*100/o}' \
<(nstat -az TcpRetransSegs TcpOutSegs)
经验上,内网重传率低于 0.01% 算正常,公网低于 0.1%。超过 1% 基本可以确定链路有问题。
定位到具体连接
ss -tin state established '( dport = :5432 )' | head -40
每条连接后面会跟一行详细信息,重点看这几个字段:
retrans:重传次数 / 总段数rtt、rttvar:往返时延和抖动cwnd、ssthresh:拥塞窗口和慢启动阈值
当时抓到的是 retrans:12/5231,整体比例不高,但集中在两条连接上,而且那两条的 rtt 抖动特别大,从 0.8ms 跳到 40ms。
原因
跨国链路晚间丢包。后来把连接池的空闲回收时间调短,让长连接不要挂太久,超时就少了很多。
一点经验
重传率是个很便宜的指标,nstat 一条命令就能拿到。但它统计的是主机级、不区分连接,所以顺序应该是:先看总量,再用 ss 定位到具体连接,别反过来。
另外别只看平均值。retrans 摊到几千条连接上显得很小,但单条连接上集中重传,对那一个请求就是几百毫秒到几秒的延迟。