ss -tni 的 timer 字段仅表示内核定时器(如 keepalive 或重传)剩余时间,非连接建立耗时;测 TCP 建连应使用 curl -w %{time_connect}、time + nc 或 socket 程序精确计时,并排查服务端队列积压与内核参数。

ss -tni 的 timer 字段不是连接建立耗时
当执行 ss -tni 后,看到类似 timer:(on,15sec,0) 的输出,很多人可能会错误地认为这意味着“该连接已经存在了15秒”。但实际上,它仅仅表示某个内核定时器(比如keepalive或retransmit)处于激活状态,并且剩余时间约为15秒,这并不能反映连接从 SYN_SENT 到 ESTABLISHED 的真实建立耗时。因为内核根本不会向用户空间暴露连接建立的精确时间戳,ss 也没有对应的字段。
用 curl -w 测 HTTP 连接各阶段耗时(含 TCP 建连)
如果你实际想测的是「HTTP 请求中 TCP 连接建立花了多久」,curl -w 是最直接可用的方案:
-o /dev/null -s必须加,否则响应体或进度条会污染输出%{time_connect}表示从请求发起 → TCP 连接成功(三次握手完成),单位秒,精度纳秒级%{time_namelookup}是 DNS 耗时,%{time_connect} - %{time_namelookup}才是纯 TCP 建连时间- HTTPS 下可叠加
%{time_appconnect}观察 TLS 握手是否拖慢建连
示例命令:curl -o /dev/null -s -w "DNS:%{time_namelookup}nTCP:%{time_connect}n" https://example.com
测裸 TCP 连接建立耗时:用 time + nc 或自写 socket 程序
对非 HTTP 场景(如 Redis、MySQL 直连),curl 不适用,需绕过应用层:
time nc -zv host port可粗略测单次建连,但time统计含进程启动开销,误差常达 10–50ms- 更准的做法是写一个最小 socket 程序(C/Python),调用
connect()前后用clock_gettime(CLOCK_MONOTONIC, ...)计时 - 批量测量时,避免复用连接:每次新建 socket,禁用
SO_REUSEADDR,防止 TIME-WAIT 干扰
下面是一段Python示例代码:
import socket, time
s = socket.socket()
start = time.monotonic()
s.connect(('example.com', 443))
print(f"连接耗时{(time.monotonic() - start)*1000:.2f}毫秒")
生产环境排查:看 %sy 和 ss -lnt 是否有队列积压
如果大量连接建连慢,往往不是单次耗时高,而是服务端资源瓶颈:
- 运行
top观察%sy是否持续 >30%,说明内核协议栈处理压力大 ss -lnt查看监听端口的Recv-Q(全连接队列)和Send-Q(半连接队列),非零且持续增长即表明队列溢出- 确认内核参数:
net.core.somaxconn(全队列上限)、net.ipv4.tcp_max_syn_backlog(半队列上限)是否足够
真正耗时的从来不是单次 connect 系统调用本身,而是它在内核里排队等待被 accept 的那几百毫秒——这点最容易被忽略。