用 ss 看清一条 TCP 连接卡在哪
接口偶发超时的时候,我不再先重启进程。先用 ss 把这条连接的状态看清楚,往往能分清是对端没回包、本机队列堆住,还是根本没人在听端口。ss 读的是内核里的套接字表,比抓一整段包更轻,也比只看应用日志更直接。
先确认有没有人在听。例如服务应该开在 8080:
ss -lnt sport = :8080
-l 只看监听,-n 不解析端口名,-t 只看 TCP。如果没有任何一行,请求会在本机就被拒绝,应用日志里甚至不会出现这次访问。这时先查进程有没有起来、配置里的端口是不是写错,而不是去怀疑下游。
连接已经建立,但调用方一直等,再看具体状态:
ss -ntp state established
Recv-Q 和 Send-Q 两列很有用。Recv-Q 持续很大,说明数据已经到了本机,应用没把它读走,常见原因是处理线程堵住,或者只起了一个工作线程。Send-Q 一直不降,多半是对端接收窗口太小,或者中间链路把包丢掉了。这两列如果接近 0,而应用仍报超时,问题更可能在业务逻辑,而不是 TCP 本身。
握手阶段的失败也能看见。处于 syn-sent 的行很多,通常是本机发出了 SYN,对端或安全组没有回 SYN-ACK。syn-recv 很多,则是本机已经收到 SYN,回复还没完成,有时是半连接被打满。我习惯先数一下数量,再决定要不要去看防火墙和路由,避免一上来就改规则。
看某一条连接时,带上进程号更省事。-p 需要足够权限,普通用户往往只能看到自己的进程。确认是目标进程后,再对照它的工作队列,比在所有连接里盲找快得多。
还有一类容易误判的状态是 close-wait。它表示对端已经关闭,本机应用还没有调用关闭。如果这种行随时间增加,多半是代码里漏了释放连接,而不是网络抖动。time-wait 则相反,它出现在本机主动关闭之后,用来吃掉迟到的旧报文。短连接很多时,time-wait 升高是正常现象。
ss -s 给出一个总览:TCP 总数、处于 time-wait 的数量、UDP 数量。只有当 time-wait 多到占满本地端口,新连接开始报地址不可用,才需要回头看是不是没有复用连接。我不会一看到 time-wait 就去改内核参数。
我把这几条收成固定顺序:先看监听,再看 established 的两个队列,然后看 syn-sent、syn-recv 和 close-wait,最后用 ss -s 看总量。排障记录里写上当时的数字,下次对比才知道是偶发还是已经恶化。ss 不能代替抓包,但它足够回答卡在哪一层这个问题。
地址写错和端口写错,在 ss 里看起来不一样。端口没人听时,监听表是空的;地址写成了只绑定回环,则监听行的本地地址是 127.0.0.1,从别的机器访问会失败,本机访问却正常。我每次改完监听地址,都会再跑一次 ss -lnt,确认本地地址是预期的网卡,而不是只留在回环上。
- 点赞
- 收藏
- 关注作者
评论(0)