服务器运行网心云导致Docker网络爆卡的解决方案

  1. 网心云(PCDN)本质上是 UDP/TCP 海量短连接 + 长时 UDP 会话 的混合流量,会在几分钟内把 conntrack 表打满;
  2. 一旦表满,Linux 会丢弃 所有新建连接 的包,包括 Docker 里 MySQL 的 TCP 握手 / DNS 解析 报文,于是出现「MySQL 连不上」;
  3. 虽然内存够大,但 默认的 conntrack_max、buckets 以及 UDP timeout 仍然是小路由器级别的 65 535 / 16 384 / 30 s,所以必须专门调优,否则一样会丢包。
  4. 下面给出「症状 → 原理 → 解决」一条龙方案。
    ──────────────────
    1. 症状复现与确认
    复制
    # 1. 看表是否已打满
    dmesg | grep "nf_conntrack: table full"
    cat /proc/sys/net/netfilter/nf_conntrack_count
    cat /proc/sys/net/netfilter/nf_conntrack_max
    如果 count≈max,且 dmesg 持续出现 table full, dropping packet,就可以确定是 conntrack 溢出导致的丢包。
    ──────────────────
    2. 为什么内存够也会丢
    • conntrack 条目本身很小(≈380 byte),但 UDP 默认 30 s 老化 对 PCDN 来说太长,导致 UDP 会话堆积;
    • 默认 buckets=16 384,链表长度暴增后查找退化,CPU 软中断飙高,进一步放大“假死”现象;
    • Docker 的 NAT 规则(iptables -t nat) 同样走 conntrack,一旦丢 NEW 包,3306 端口三次握手直接被内核扔掉,于是 MySQL 客户端表现为「timeout」。
    ──────────────────
    3. 立即止血(临时命令)
    复制
    # 扩大表
    sudo sysctl -w net.netfilter.nf_conntrack_max=1048576
    echo 262144 | sudo tee /sys/module/nf_conntrack/parameters/hashsize
    
    # 缩短 UDP 老化,减少堆积
    sudo sysctl -w net.netfilter.nf_conntrack_udp_timeout=10
    sudo sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=30
    改完后可立刻恢复 MySQL 访问。
    ──────────────────
    4. 永久生效
    把下面内容写到 /etc/sysctl.d/99-conntrack.confsysctl -p
    复制
    net.netfilter.nf_conntrack_max = 1048576
    net.netfilter.nf_conntrack_buckets = 262144
    net.netfilter.nf_conntrack_udp_timeout = 10
    net.netfilter.nf_conntrack_udp_timeout_stream = 30
    net.netfilter.nf_conntrack_tcp_timeout_established = 3600   # 可选,回收长连接更快
    ──────────────────
    5. 进阶:直接限制网心云的连接数(可选)
    如果仍嫌 UDP 数量多,可在 nftables/iptables 里给网心云容器/进程做 connlimithashlimit
    复制
    # 例:限制 192.168.31.100(网心云宿主机)每秒最多 1000 条 UDP
    iptables -I FORWARD -s 192.168.31.100 -p udp -m hashlimit \
      --hashlimit-mode srcip --hashlimit-upto 1000/sec \
      --hashlimit-name wx_udp -j ACCEPT
    ──────────────────
    一句话总结
    网心云把 conntrack 打满 → 新建连接受阻 → Docker MySQL 握手包被丢 → 看起来 “MySQL 无法访问”。把 max 调到 1 048 576、buckets 调到 262 144,并把 UDP 超时降到 10 s,问题即可彻底解决。
点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注