一、背景
我们灰度线上业务的时候,有一次遇到了业务反馈资源没有读写,当时正好将流量切到了线上的一台机器上,在将业务的资源迁移回滚之后,经过一番查找,发现/var/log/message
中打印了很多关于kernel: nf_conntrack: table full, dropping packet
的错误信息,网上查找了一下,这个错误主要是由于启用了nf_conntrack模块
,之前很多人都遇到了这个问题,解决方案也很多,这里以我的角度详细记录一下,/var/log/message
中错误信息如下:
Jul 30 11:50:01 dbl14192 systemd: Starting Session 486429 of user root. |
1.1、原因/复现
由于启用了nf_conntrack模块
,业务短链接请求访问量大,由于conntrack采用默认的配置参数,短时间内导致conntrack的连接追踪表达到65536*4=262144
默认的最大限制,新的连接无法建立,导致大量的丢包,业务因此无法正常访问;
短连接为什么也会导致爆表?
- 针对于各种协议的各种连接状态,连接追踪表中会保留对应的记录一段时间,具体时间可参考下文中的详细配置值,因此短链接又可能也会爆表;
后续尝试使用redis-benchmark
进行client为400000
的短链接
压测却未能复现,原因是操作系统启用了端口复用(对应参数:/proc/sys/net/ipv4/tcp_tw_reuse
),并且单机的socket连接数限制在65535,对于启用了conntrack模块
的链接追踪表来说,测试的时候,记录的连接数不会超过65536,后续将/proc/sys/net/netfilter/nf_conntrack_max
参数调小之后,稳定复现。
1.2、修复
如何避免再次出现这种问题,一下提供两种方式可供参考:
- 禁用模块:
sudo iptables -t raw -A OUTPUT -j NOTRACK |
- 调整
nf_conntrack_max
:
sysctl -w net.netfilter.nf_conntrack_max = 65536000 |
二、conntrack模块
nf_conntrack模块在kernel 2.6.15(2006-01-03 发布) 被引入,支持IPv4 和IPv6,取代只支持IPv4 的ip_connktrack,用于跟踪一个连接的状态。连接状态跟踪可以供其他模块使用,最常见的两个使用场景是 iptables 的 nat 的 state 模块。
2.1、模块管理
nf_conntrack模块对应存在一个管理工具:conntrack-tools,该工具可手动安装,它是一款基于GNU / Linux的免费软件工具,允许系统管理员从用户空间与内核中的连接跟踪系统进行交互,该软件主要提供两个具体的工具:
conntrack
:通过使用命令行指令提供比直接使用/proc/net/ip_conntrack
更灵活的接口来管理连接跟踪系统。通过使用conntrack指令,您可以显示/删除/更新现有的状态条目,同时也可以监听流事件;conntrackd
:用户空间连接跟踪守护程序,可用于部署容错GNU/Linux防火墙,也可以使用它来收集防火墙中流的相关统计信息;
2.2、模块配置信息
官方详细介绍地址:https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt
# 启用连接跟踪流记帐。每个流添加64位字节和数据包计数器。(BOOLEAN:默认为零) |
三、相关指令
conntrack内核参数列表:
sudo sysctl -a | grep conntrack
;conntrack超时相关参数:
sudo sysctl -a | grep conntrack | grep timeout
;conntrack跟踪表的大小(桶的数量):
sudo sysctl net.netfilter.nf_conntrack_buckets
;conntrack最大跟踪连接数:
sudo sysctl net.netfilter.nf_conntrack_max
;netfilter模块加载时的默认值:
sudo dmesg | grep conntrack
;conntrack跟踪表使用情况:
sudo sysctl net.netfilter.nf_conntrack_count
;四层协议类型和连接数:
sudo cat /proc/net/nf_conntrack | awk '{sum[$3]++} END {for(i in sum) print i, sum[i]}'
;TCP 连接各状态对应的条数:
sudo cat /proc/net/nf_conntrack | awk '/^.*tcp.*$/ {sum[$6]++} END {for(i in sum) print i, sum[i]}'
;三层协议类型和连接数:
sudo cat /proc/net/nf_conntrack | awk '{sum[$1]++} END {for(i in sum) print i, sum[i]}'
;连接数最多的10个IP地址:
sudo cat /proc/net/nf_conntrack | awk '{print $7}' | cut -d "=" -f 2 | sort | uniq -c | sort -nr | head -n 10
;