首页 / 资讯中心 / 文章详情

conntrack 表满导致丢包:nf_conntrack_max 与 3 个排查命令

conntrack 表满导致丢包:nf_conntrack_max 与 3 个排查命令 ★ FEATURED ARTICLE
我不会起名字322· 后端 / 算法 / 数据库 技术栈 力扣 Hot100 Go 项目 Redis MySQL文章目录conntrack 表满导致丢包nf_conntrack_max 与 3 个排查命令一、先认识 conntrack二、症状这些现象都可能是 conntrack 满了三、3 个排查命令命令 1看表的使用率命令 2看谁在占表命令 3看各项超时配置四、怎么调大第一步算合适的大小第二步持久化第三步治本五、K8s 环境下的特别说明六、带走物conntrack 表满导致丢包nf_conntrack_max 与 3 个排查命令一、先认识 conntrackconntrackconnection tracking是 Linux 内核 netfilter 的一个模块它记录每条经过本机的网络连接的状态。它在这些场景下是必需的有 iptables NAT 规则做 SNAT/DNAT有基于状态的防火墙规则-m state --state ESTABLISHEDKubernetes 环境kube-proxy 的 iptables 模式、大部分 CNI 插件、Service 的 DNAT全都依赖 conntrack。所以只要你在跑 K8s或者机器上有 Docker 的 bridge 网络conntrack 就在工作。它维护的是一张哈希表每条连接一项。表有上限cat/proc/sys/net/netfilter/nf_conntrack_max# 常见默认 26214425 万老版本可能是 65536# 当前已用了多少cat/proc/sys/net/netfilter/nf_conntrack_count表满之后新的连接会被直接丢弃drop而且是在内核层面静默丢弃——应用层完全不知道发生了什么只会表现为连接超时。二、症状这些现象都可能是 conntrack 满了conntrack 满的表现非常不像网络问题这也是它难排查的原因间歇性的Connection timed out重试试试又能通curl卡住不返回也没有 RST同一台机器上有的连接能建、有的不能看起来完全随机DNS 解析偶尔超时K8s 里 Pod 访问 Service 时好时坏业务日志里出现No buffer space available/Cannot assign requested address。最直接的证据在内核日志里dmesg|grep-iconntrack# nf_conntrack: table full, dropping packet或者journalctl-k|greptable full只要看到这一行就可以确诊——不用再怀疑应用、怀疑网络、怀疑 DNS。三、3 个排查命令命令 1看表的使用率# 当前值 / 上限cat/proc/sys/net/netfilter/nf_conntrack_countcat/proc/sys/net/netfilter/nf_conntrack_max# 一行看比例echoscale2;$(cat/proc/sys/net/netfilter/nf_conntrack_count)/$(cat/proc/sys/net/netfilter/nf_conntrack_max)|bc超过 80% 就该警惕到 100% 就开始丢包了。如果装了conntrack-tools可以看更细# 按状态统计conntrack-L|awk{print $4}|sort|uniq-c# 看哪种协议占得最多conntrack-L|awk{print $3}|sort|uniq-c|sort-rn|head命令 2看谁在占表# 按目标 IP:端口 聚合找出连接数最多的下游conntrack-L2/dev/null|awk{print $6}|sort|uniq-c|sort-rn|head-20常见的表杀手DNS 查询每个 UDP 短连接也会占一项而且 UDP 的超时默认是 30 秒。DNS 抖动 重试会瞬间灌满表没有连接池的 HTTP 客户端大量的短连接爬虫、压测到同一个下游的 TIME_WAIT 堆积。命令 3看各项超时配置sysctlnet.netfilter.nf_conntrack_tcp_timeout_established# 默认 432000 秒 5 天sysctlnet.netfilter.nf_conntrack_udp_timeout# 默认 30 秒ESTABLISHED状态的默认超时是 5 天——这意味着一条已经半死不活的连接比如对端早就关了但没走完四次挥手会在表里躺 5 天才被清理。这是表被占满的一个常见原因。合理的值sysctl-wnet.netfilter.nf_conntrack_tcp_timeout_established1200# 20 分钟sysctl-wnet.netfilter.nf_conntrack_tcp_timeout_time_wait60sysctl-wnet.netfilter.nf_conntrack_tcp_timeout_close_wait60sysctl-wnet.netfilter.nf_conntrack_udp_timeout30注意把established调得太短会有副作用——真正空闲的长连接会被 conntrack 提前遗忘之后来的包会被当成无效连接丢弃。所以对有长连接的机器这个值要和 TCP keepalive 配合keepalive 间隔 established 超时。四、怎么调大第一步算合适的大小conntrack 表是哈希表每项大约占300 字节内核内存。经验公式nf_conntrack_max 期望并发连接数 × 1.2对于一台 8GB 内存的机器设 262144 大约占 78MB 内核内存是可以接受的。sysctl-wnet.netfilter.nf_conntrack_max524288但要注意哈希表桶的数量cat/sys/module/nf_conntrack/parameters/hashsize# 建议 hashsize nf_conntrack_max / 4echo131072/sys/module/nf_conntrack/parameters/hashsize桶太少会导致哈希链变长查找变慢表现为 CPU 升高而不是丢包。第二步持久化sysctl -w重启就没了。写进配置cat/etc/sysctl.d/90-conntrack.confEOF net.netfilter.nf_conntrack_max 524288 net.netfilter.nf_conntrack_tcp_timeout_established 1200 net.netfilter.nf_conntrack_tcp_timeout_time_wait 60 net.netfilter.nf_conntrack_tcp_timeout_close_wait 60 net.netfilter.nf_conntrack_udp_timeout 30 EOFsysctl-p/etc/sysctl.d/90-conntrack.conf第三步治本调大表只是缓解真正要做的通常是这几件DNS 用本地缓存nscd / systemd-resolved / CoreDNS 的 cache减少 UDP 短连接客户端开连接池别每次都新建连接排查短连接来源——往往是某个客户端没复用连接如果是 K8s 节点考虑节点规格是否与并发量匹配或者把高并发服务分散到更多节点。五、K8s 环境下的特别说明在 K8s 节点上conntrack 问题会表现为非常随机的故障因为每条 Service 访问都要走 DNAT conntrackPod 访问 ClusterIP 时好时坏NodePort 偶发不通CoreDNS 解析偶发超时DNS 是 UDP非常吃 conntrack。CoreDNS 相关的 conntrack 问题尤其值得单独说DNS 是 UDP默认 30 秒超时。如果集群里 DNS 查询量大比如应用没做缓存、或者ndots配置导致放大查询conntrack 表会被 DNS 连接快速填满然后所有网络都开始出问题——因为 DNS 是网络访问的前置环节。这就是为什么很多K8s 网络抖动的根因其实是DNS 查询放大 → conntrack 满 → 全节点丢包。六、带走物排查流程# 1. 确诊dmesg|grep-iconntrack: table full# 看到就是它# 2. 看水位cat/proc/sys/net/netfilter/nf_conntrack_countcat/proc/sys/net/netfilter/nf_conntrack_max# 3. 看谁在用conntrack-L|awk{print $6}|sort|uniq-c|sort-rn|head# 4. 临时缓解sysctl-wnet.netfilter.nf_conntrack_max524288sysctl-wnet.netfilter.nf_conntrack_tcp_timeout_established1200# 5. 治本# DNS 本地缓存 / 客户端连接池 / 消灭短连接一句话结论conntrack 满导致的丢包是内核静默行为应用层只会看到随机超时确诊只看一处——dmesg里有没有nf_conntrack: table full。
阅读完成 · 觉得有帮助?
咨询建站