4、端口状态监控:从状态模型到告警阈值
端口监控这事儿,说白了就是看你的端口在干什么、干得怎么样。我见过不少团队,监控面板铺了一整面墙,但端口状态一塌糊涂却没人发现。嗯,今天咱们就把这块彻底讲透。
4.1 端口状态模型:TCP 的三种核心状态
TCP 连接的状态机其实挺复杂的,但日常运维中你只需要盯住三个状态——Listening、Established、Time_Wait。其他的像 SYN_SENT、CLOSE_WAIT 这些,要么是瞬态,要么是异常信号。
| 状态 | 含义 | 正常范围 | 异常信号 |
|---|---|---|---|
| Listening | 端口正在监听,等待客户端连接 | 固定值(等于你启动的服务数) | 突然消失 → 服务挂了;突然暴增 → 可能被恶意扫描 |
| Established | 连接已建立,正在传输数据 | 随业务波动,有上限 | 持续接近上限 → 端口耗尽风险;突降 → 服务异常 |
| Time_Wait | 连接已关闭,等待 2MSL 后彻底释放 | 通常几百到几千 | 持续数万 → 端口被占满,新连接无法建立 |
核心原则:Listening 看「有没有」,Established 看「多不多」,Time_Wait 看「堵不堵」。
我个人习惯把 Time_Wait 叫做「幽灵连接」。它不占 CPU,不占带宽,但占着端口号。你想想看,如果一台机器上 Time_Wait 堆了五六万个,新连接就只能干瞪眼。
4.2 监控指标:连接数、带宽、延迟
指标不用多,三个维度就够了。我管它叫「量、宽、时」。
4.2.1 连接数指标
- 当前连接数:实时 Established 数量,反映并发压力
- 连接速率:每秒新建连接数,反映请求涌入速度
- 连接错误率:比如 connection refused、timeout 的比例
4.2.2 带宽指标
- 入站带宽:客户端→服务器的流量
- 出站带宽:服务器→客户端的流量
- 带宽利用率:当前带宽 / 端口所在链路带宽上限
4.2.3 延迟指标
- TCP 握手延迟:SYN→SYN-ACK 的耗时
- 首字节时间:从发请求到收到第一个数据字节
- 往返时间:RTT,反映网络质量
我的经验:连接数和带宽是「快指标」,延迟是「慢指标」。延迟升高往往比连接数暴涨早出现 5-10 秒。我曾经靠延迟告警提前发现了某次数据库连接池泄漏——连接数还没涨,延迟已经翻了三倍。
4.3 监控工具:Netstat、SS、Prometheus
工具分两类:查问题用的和长期盯着的。Netstat 和 SS 属于前者,Prometheus 属于后者。
4.3.1 Netstat —— 老牌工具,但有点慢
Netstat 读取 /proc/net/tcp,当连接数上万时,执行一次可能要好几秒。我一般只在排查单机问题时用。
# 查看所有 Listening 端口
netstat -tlnp
# 统计各状态连接数
netstat -ant | awk '{print $6}' | sort | uniq -c | sort -rn
# 查看某个端口的 Established 连接
netstat -ant | grep :8080 | grep ESTABLISHED | wc -l
4.3.2 SS —— 更快,更现代
SS 直接读取内核的 sock_diag 接口,速度比 Netstat 快一个数量级。我现在基本只用 SS。
# 查看所有 TCP 连接,带状态统计
ss -ant
# 只看 Time_Wait
ss -ant state time-wait
# 按端口过滤,显示进程
ss -antp sport = :443
# 输出 JSON 格式,方便脚本处理
ss -antj
注意:SS 的 state 过滤语法是精确匹配,比如 state time-wait 不能写成 state TIME_WAIT。大小写错了查不出结果,我踩过这个坑。
4.3.3 Prometheus + node_exporter —— 规模化监控
单机用 SS,集群必须上 Prometheus。node_exporter 默认暴露了 node_netstat_Tcp_* 指标,但粒度不够细。我建议自己写 exporter 或使用 textfile collector。
# 自定义监控脚本示例(采集端口级指标)
#!/bin/bash
# 采集 :8080 端口的连接状态分布
ss -ant sport = :8080 | awk '
/ESTAB/ {est++}
/TIME-WAIT/ {tw++}
/LISTEN/ {lis++}
END {
print "port_connections{port=\"8080\",state=\"established\"} " est
print "port_connections{port=\"8080\",state=\"time_wait\"} " tw
print "port_connections{port=\"8080\",state=\"listening\"} " lis
}
' > /var/lib/node_exporter/textfile_collector/port_8080.prom
4.4 告警阈值设置:别让告警变成噪音
告警阈值设得太松,出事了没人知道;设得太紧,运维群一天刷几千条消息。我总结了一套「三层阈值法」。
| 指标 | 警告(Warning) | 严重(Critical) | 说明 |
|---|---|---|---|
| Established 连接数 | 达到端口上限的 70% | 达到端口上限的 90% | 上限 = 系统配置的端口范围(通常 28232-65535) |
| Time_Wait 数量 | > 10000 | > 30000 | 超过 30000 时新连接可能被拒绝 |
| 连接错误率 | > 1% | > 5% | 基于每分钟采样 |
| TCP 握手延迟 | > 200ms | > 500ms | 内网环境通常 < 10ms |
| 带宽利用率 | > 70% | > 90% | 持续 5 分钟以上 |
关键原则:告警必须带「持续时间」条件。比如「Time_Wait > 30000 持续 2 分钟」才触发,避免瞬态抖动导致误报。
我曾经遇到过一个案例:某业务高峰期 Time_Wait 每 30 秒冲到 35000 然后回落,如果按瞬时值告警,一天能收到 2000 条。加了「持续 2 分钟」条件后,告警量降到每天 3-5 条,而且每一条都是真问题。
4.5 端口状态监控知识体系
下面这张图把整个监控链路串起来了。从状态模型到指标,再到工具和告警,是一条完整的闭环。
4.6 避坑指南
- 别只看连接数,不看连接速率。连接数 1000 但速率是 0,说明服务可能已经僵死了。速率才是活性的指标。
- Time_Wait 不是洪水猛兽。正常业务中 Time_Wait 几千个是常态。只有持续增长且不回落时才需要干预。
- 告警阈值要按业务调。我见过直接把网上教程的阈值复制粘贴的——内网延迟 5ms 的服务,设了个 500ms 告警,等于没设。
- Prometheus 采集间隔别太短。15 秒一次足够。5 秒一次对 node_exporter 压力不大,但 SS 命令本身有开销,高并发机器上可能反噬性能。
一个小技巧:把 SS 的 JSON 输出接到 Prometheus Pushgateway,可以实现秒级端口监控。但注意 Pushgateway 不持久化数据,适合临时调试,不适合生产长期使用。