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 端口状态监控知识体系

下面这张图把整个监控链路串起来了。从状态模型到指标,再到工具和告警,是一条完整的闭环。

端口状态监控知识体系 端口状态监控知识体系 端口状态模型 Listening(监听) Established(已建立) Time_Wait(等待释放) 监控指标(量·宽·时) 连接数(并发/速率/错误率) 带宽(入站/出站/利用率) 延迟(握手/首字节/RTT) 监控工具 Netstat(单机排查) SS(快速诊断) Prometheus(集群监控) 告警阈值设置(三层阈值法) Warning(70%) → Critical(90%) → 持续条件(防误报) 闭环逻辑:状态模型决定「看什么」,指标决定「怎么看」,工具决定「用什么看」,告警决定「什么时候该动」

4.6 避坑指南

  • 别只看连接数,不看连接速率。连接数 1000 但速率是 0,说明服务可能已经僵死了。速率才是活性的指标。
  • Time_Wait 不是洪水猛兽。正常业务中 Time_Wait 几千个是常态。只有持续增长且不回落时才需要干预。
  • 告警阈值要按业务调。我见过直接把网上教程的阈值复制粘贴的——内网延迟 5ms 的服务,设了个 500ms 告警,等于没设。
  • Prometheus 采集间隔别太短。15 秒一次足够。5 秒一次对 node_exporter 压力不大,但 SS 命令本身有开销,高并发机器上可能反噬性能。

一个小技巧:把 SS 的 JSON 输出接到 Prometheus Pushgateway,可以实现秒级端口监控。但注意 Pushgateway 不持久化数据,适合临时调试,不适合生产长期使用。