Linux conntrack 表满导致丢包:现场定位与容量评估

    发布时间:2026-09-23 12:30 更新时间:2026-09-23 12:30 阅读量:0

    如果服务器上出现间歇性丢包、新连接建立失败,而 CPU、内存、带宽看起来都不高,可以在 dmesg 里搜一下有没有 nf_conntrack: table full, dropping packet 这类提示。它意味着内核的连接跟踪表已经装不下新条目,新到的包被直接丢弃。对做 NAT 转发的网关、反向代理、容器宿主机来说,这是很典型的故障点。本文按“先确认现场、再理解参数、最后评估容量”的顺序讲清楚怎么定位,以及在 NAT 与纯防火墙两种场景下应该往哪个方向调。

    一、现场定位:先确认是不是 conntrack 满了

    第一步是确认报错来源和当前用量。dmesg 或 journalctl 中如果出现 table full,基本可以锁定方向;同时看两个关键文件:当前条目数和上限。

    # 查看当前连接跟踪条目数与上限
    cat /proc/sys/net/netfilter/nf_conntrack_count
    cat /proc/sys/net/netfilter/nf_conntrack_max
    
    

    搜索内核日志中的丢包提示(需要 root)

    dmesg -T | grep -i conntrack journalctl -k --since "1 hour ago" | grep -i conntrack

    观察条目数是否贴着上限

    watch -n 2 'cat /proc/sys/net/netfilter/nf_conntrack_count'

    如果 count 长时间接近 max,说明容量确实不够,或者存在大量短命连接、无效连接占位。还可以借助 conntrack 工具查看明细(不同发行版包名可能是 conntrack-tools,具体以官方文档为准):

    # 按协议统计当前跟踪的条目数量
    conntrack -C
    

    查看某状态(如 SYN_SENT)的条目,判断是否有大量半开连接

    conntrack -L -p tcp 2>/dev/null | head -n 20

    按源 IP 统计条目数,找出异常来源

    conntrack -L 2>/dev/null | awk '{print $5}' | cut -d= -f2 | sort | uniq -c | sort -rn | head

    注意:conntrack -L 在条目多时开销较大,生产环境建议短时间采样,别长时间挂着跑。

    二、参数含义:哈希桶与超时,不只是 max

    很多人一看到 table full 就直接把 nf_conntrack_max 调大,这往往治标不治本。先理解几个参数:

    nf_conntrack_max 是整张表的条目上限,写满后新连接被丢。nf_conntrack_buckets(部分内核通过 /sys/module/nf_conntrack/parameters/hashsize 调整)决定哈希桶数量,桶太少会让链表变长、查找变慢,即使条目没满也可能拖累转发性能。经验上桶数约为 max 的 1/4 到 1/2,具体以官方文档和实测为准。

    超时参数决定一条连接在表里停留多久。TCP 已建立连接默认超时较长(常见 432000 秒),UDP、TCP 半开等状态超时短得多。对短连接密集的代理或 NAT 场景,超时过长会让历史条目迟迟不释放,等于人为压缩了可用容量。

    # 查看与超时相关的参数(路径可能随内核版本略有差异)
    sysctl net.netfilter.nf_conntrack_tcp_timeout_established
    sysctl net.netfilter.nf_conntrack_tcp_timeout_time_wait
    sysctl net.netfilter.nf_conntrack_udp_timeout
    sysctl net.netfilter.nf_conntrack_udp_timeout_stream
    
    

    查看哈希桶相关参数

    cat /sys/module/nf_conntrack/parameters/hashsize 2>/dev/null sysctl net.netfilter.nf_conntrack_buckets 2>/dev/null

    调参时还要注意内存开销:每条 conntrack 条目会占用几百字节级别的内核内存,max 越大、超时越长,占用越高。盲目把 max 拉到几十万上百万,在小内存机器上可能带来内存压力,反而引发别的问题。

    三、NAT 与防火墙场景:调优方向不同

    同样是 table full,成因和调法并不一样。

    NAT 场景(网关、路由器、Docker/K8s 宿主机):每条被转发的连接都要建表,且需要保存地址转换信息。这里的瓶颈通常来自并发连接数本身,以及连接回收速度。合理方向是:适度提高 max 与 buckets,同时把 TCP/UDP 超时压到业务可接受的范围,减少僵尸条目;并检查是否有应用在疯狂建短连接却不复用,这属于应用层问题,调内核参数只能缓解不能根治。

    纯防火墙场景(仅用 iptables/nftables 做过滤,不做地址转换):可以评估是否真的需要全量跟踪。对明确只需放行的流量,可用 NOTRACK 或 nftables 的 notrack 跳过跟踪,直接减少表内条目。这样比一味放大上限更健康。

    # 临时生效:适度调大上限与桶数(重启或模块重载后可能失效)
    sysctl -w net.netfilter.nf_conntrack_max=262144
    sysctl -w net.netfilter.nf_conntrack_buckets=65536
    
    

    缩短已建立连接与 TIME_WAIT 超时,加快条目回收

    sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=86400 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=60

    永久生效写入配置文件(各发行版路径可能不同,以实际环境为准)

    /etc/sysctl.d/99-conntrack.conf

    net.netfilter.nf_conntrack_max = 262144

    net.netfilter.nf_conntrack_buckets = 65536

    用 iptables 跳过跟踪的示例(仅示意语法,规则需按实际业务调整):

    # 对某类无需跟踪的流量打 NOTRACK(raw 表)
    iptables -t raw -A PREROUTING -p tcp --dport 8080 -j NOTRACK
    iptables -t raw -A OUTPUT -p tcp --sport 8080 -j NOTRACK

    调整前建议记录基线:峰值连接数、平均连接时长、是否有异常来源。这样调完能判断是容量真的不够,还是连接被浪费掉了。

    小结

    conntrack 表满本质是“条目产生速度超过释放速度”或“容量确实不足”。排查顺序建议固定为:dmesg 确认报错 → 看 count/max 比值 → 按来源和时间分布找异常 → 最后再动 max、buckets 和超时。NAT 场景重点在连接回收与上限匹配,纯防火墙场景优先考虑对无需跟踪的流量 NOTRACK。把上限一味放大,只会把问题往后拖,并在内存紧张时带来新的风险。

    继续阅读

    📑 📅
    Nginx客户端与后端长连接谁在复用:端口耗尽排查顺序 2026-09-23
    Linux 服务器 CPU 软中断 si 偏高排查:网卡多队列、RPS 与内核参数调整 2026-09-23
    Docker 容器启动即退出排查:exit code、logs 与前台进程 2026-09-23
    MySQL单表过亿后的分页优化:延迟关联与覆盖索引 2026-09-23
    Nginx 反代下 Cookie 域与 Path 错乱排查实战 2026-09-23
    rsyslog 与 journald 双写日志重复或丢失排查 2026-09-23
    PostgreSQL表膨胀与autovacuum不生效排查实战 2026-09-23
    Redis 主从切换后写入报 READONLY:三种拓扑的误配排查 2026-09-23
    Linux负载高但CPU空闲:D状态进程与不可中断睡眠排查 2026-09-24
    Nginx 与 CDN 回源 IP 不一致:XFF 取值顺序与日志字段 2026-09-24