技术指南

Linux 新连接失败:区分临时端口、conntrack 与监听队列

从新连接错误与计数增量出发,区分临时端口、conntrack 和 SYN/accept 队列耗尽,再做单变量恢复。

已有连接仍能传输、但新连接开始超时或报错时,先把故障分成三条独立路径:客户端是否还能分配本地临时端口,状态防火墙是否还能创建 conntrack 条目,服务端是否还能把新连接放进 SYN/accept 队列。三者都发生在连接建立阶段,却有不同作用域、计数器和修复方法;`TIME_WAIT` 很多、连接数很高或一次 `curl` 失败都不能单独定案。

用症状和增量把故障分流

观察更接近哪一层需要的确认
应用 `connect()` 返回 EADDRNOTAVAIL,且本地端口范围内连接持续增长出站临时端口分配同一网络命名空间的端口范围、保留端口、四元组分布和应用 errno
`nf_conntrack_count` 接近 `nf_conntrack_max`,内核同窗出现 table fullNetfilter 连接跟踪计数增量、状态分布、流量来源与防火墙是否实际启用 conntrack
监听存在,但 `TcpExtListenOverflows`/`ListenDrops` 在失败窗增长服务端监听队列或 accept 不及时目标 listener 的 Recv-Q/Send-Q、应用 backlog、CPU/阻塞与两次计数差
ECONNREFUSED、ENETUNREACH、TLS 或 DNS 错误,以上计数不增长不是这三种耗尽的直接证据回到监听、路由、防火墙、名称解析和应用协议层

固定 UTC、目标和网络命名空间

把 203.0.113.10 换成实际目标;地址、进程和连接清单可能包含客户或内部网络信息,限制权限并在共享前脱敏
umask 077
stamp=$(date --utc +%Y%m%dT%H%M%SZ)
evidence="new-connect-$stamp"
install -d -m 0700 "$evidence"
{
  date --utc --iso-8601=seconds
  uname -r
  printf 'netns='; readlink /proc/$/ns/net
  ip -brief address
  ip route get 203.0.113.10
} >"$evidence/context.txt"
ss -s >"$evidence/ss-summary.txt"
ss -Htan >"$evidence/tcp-sockets.txt"

网络命名空间隔离设备、协议栈、路由、防火墙、`/proc/net`、部分 `/proc/sys/net` 和端口。宿主机、容器、sidecar 或独立 netns 的计数不能混用;先从报错进程读取 `/proc/<PID>/ns/net`,再在同一命名空间执行 `ss`、`nstat` 和 sysctl 读取。

出站失败先证明临时端口分配耗尽

必须在失败进程的网络命名空间中执行;`ss` 的状态名称来自当前 iproute2 输出,若发行版显示不同先保存原始清单再调整过滤
sysctl net.ipv4.ip_local_port_range \
       net.ipv4.ip_local_reserved_ports \
       net.ipv4.ip_unprivileged_port_start
ss -Htan \
  | awk '$1 ~ /^(ESTAB|TIME-WAIT|SYN-SENT|FIN-WAIT-1|FIN-WAIT-2|CLOSE-WAIT)$/ {print $1, $4, $5}' \
  | sort | uniq -c | sort -nr | head -n 80

Linux 对未显式绑定的 IPv4 socket 会从 `ip_local_port_range` 选择可用本地端口,`ip_local_reserved_ports` 还会排除保留项。`connect(2)` 在无法分配临时端口时可返回 `EADDRNOTAVAIL`。端口是否可复用取决于本地地址、远端地址与端口、协议和 socket 选项,所以不能用 `TIME_WAIT` 总数直接减去范围宽度;应按应用、源地址和目标四元组查看分布,并保存真实 errno。

conntrack 要看 count/max 与同窗证据

`nf_conntrack_count` 是当前已分配 flow entries,`conntrack -L` 可能昂贵且需要权限;繁忙主机先保存 count/max 与内核日志,再决定是否列全表
for name in nf_conntrack_count nf_conntrack_max nf_conntrack_buckets; do
  path="/proc/sys/net/netfilter/$name"
  if test -r "$path"; then printf '%s=' "$name"; cat "$path"; else printf '%s=unavailable\n' "$name"; fi
done
command -v conntrack >/dev/null && sudo conntrack -S
command -v conntrack >/dev/null && sudo conntrack -L -o extended 2>/dev/null \
  | awk '{print $1}' | sort | uniq -c | sort -nr
journalctl -k --since '-15 minutes' --no-pager \
  | grep -Ei 'nf_conntrack|table full|dropping packet'

内核把 `nf_conntrack_count` 定义为当前分配条目数,把 `nf_conntrack_max` 定义为允许的最大条目数。接近上限只是容量风险;要把失败归因于 conntrack,还需要失败窗口内的计数、内核丢弃信息或 conntrack 统计,以及流量来源。未加载 Netfilter conntrack、绕过状态跟踪或位于另一命名空间时,文件缺失不是零使用。

入站失败检查两级监听队列

先把 443 换成目标端口,并在同一失败窗口前后各保存一次绝对计数;`nstat -a` 忽略历史文件并显示绝对值,累计值本身不能证明本次事故
port=443
ss -Hlnpt "sport = :$port"
ss -Htan state syn-recv "sport = :$port"
nstat -az TcpExtListenOverflows TcpExtListenDrops TcpPassiveOpens TcpAttemptFails
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog

Linux 的 `listen()` backlog 限制已经完成握手、等待应用 `accept()` 的连接;内核会用 `somaxconn` 静默截断应用请求的更大值。未完成握手的 SYN_RECV 队列由 `tcp_max_syn_backlog` 约束。内核文档说明 accept queue 满时 `ListenOverflows` 与 `ListenDrops` 会增长,而 `ListenDrops` 也可能因内存分配失败等原因单独增加。因此只看当前 Recv-Q、只看 sysctl 或只看累计 drops 都不够。

按根因做一个最小缓解

根因优先动作扩大容量前必须证明
应用无界出站连接或重试限并发、启用连接池/keep-alive、退避并停止失败扇出目标端依赖允许复用,连接生命周期与超时正确
临时端口确实耗尽减少 churn,分散目标或增加经规划的源地址范围、保留端口、NAT 与安全策略没有冲突
conntrack 被异常流量占满限流或隔离来源,修复不合理超时/重试条目状态和来源分布解释增长,宿主内存有明确预算
应用 accept 不及时恢复 worker、解除阻塞、修复事件循环或依赖应用 backlog、somaxconn 与 SYN 队列的实际瓶颈已分别确认

只有最小动作让对应计数停止增长且真实新连接恢复,因果链才成立。修改 `ip_local_port_range`、`nf_conntrack_max`、`somaxconn` 或 `tcp_max_syn_backlog` 都会改变容量与内存/安全边界;先保存原值和配置所有者,在 canary 或维护窗口单项变更,并明确撤销条件。

用新连接、增量和已有连接共同验收

  • 已有长连接保持健康,新建 TCP/TLS/应用请求在目标用户路径连续通过,错误类型不再出现。
  • 同一观察窗前后的端口分布、conntrack count/max、ListenOverflows/ListenDrops 和应用 accept 指标已保存并计算增量。
  • 重试率、连接创建速率和队列深度回到基线,没有把压力转移到 NAT、代理、数据库或上游。
  • 容器与宿主分别在正确网络命名空间复核;缺失的字段记录为 unavailable,不填零。
  • 候选变更失败、内存压力增加或错误转移时,恢复原 sysctl/应用配置并用相同探针复测。

把容量门槛绑定到速率和作用域

监控新连接成功率与 errno、每秒 active/passive opens、重试率、端口与目标分布、conntrack count/max 比例及增量、监听 overflow/drop 增量和应用 accept 延迟。部署、流量模型、NAT、容器网络、内核或代理版本变化后重新建立基线;不要维护一组脱离命名空间、内存预算和应用 backlog 的通用 sysctl 大数。

本文命令在 2026-08-19 按 Linux 内核、Linux man-pages、iproute2 与 Netfilter 当前文档完成语义和语法审阅,没有在生产机制造端口耗尽、填满 conntrack、压满监听队列或修改 sysctl。发行版补丁、内核/iproute2 版本、IPv6、NAT、容器网络、eBPF/代理和托管防火墙会改变可见字段与故障边界;执行前先确认实际进程、网络命名空间、独立控制台和配置所有者。

返回知识库