(服务器用的阿里云主机,CentOS 7.3,似乎不管内存多少阿里云都把 conntrack_max 设成 65536)
症状
CentOS服务器,负载正常,但请求大量超时,服务器/应用访问日志看不到相关请求记录。
在dmesg或/var/log/messages看到大量以下记录:
kernel: nf_conntrack: table full, dropping packet.
原因
服务器访问量大,内核netfilter模块conntrack相关参数配置不合理,导致新连接被drop掉。
详细
nf_conntrack模块在kernel 2.6.15(2006-01-03发布) 被引入,支持ipv4和ipv6,取代只支持ipv4的ip_connktrack,用于跟踪连接的状态,供其他模块使用。
最常见的使用场景是 iptables 的 nat 和 state 模块:
nat 根据转发规则修改IP包的源/目标地址,靠nf_conntrack的记录才能让返回的包能路由到发请求的机器。
state 直接用 nf_conntrack 记录的连接状态(NEW/ESTABLISHED/RELATED/INVALID)来匹配防火墙过滤规则。
iptables
nf_conntrack用1个哈希表记录已建立的连接,包括其他机器到本机、本机到其他机器、本机到本机(例如 ping 127.0.0.1 也会被跟踪)。
如果连接进来比释放的快,把哈希表塞满了,新连接的数据包会被丢掉,此时netfilter变成了一个黑洞,导致拒绝服务。 这发生在3层(网络层),应用程序毫无办法。
各发行版区别:
CentOS (7.3) 默认加载该模块
Ubuntu (16.10+) 和 Kali Linux (2016.1+) 默认不加载,不会有这问题
查看
netfilter 相关的内核参数:
sudo sysctl -a | grep conntrack
只看超时相关参数(超时时间 = 连接在哈希表里保留的时间)
sudo sysctl -a | grep conntrack | grep timeout
netfilter模块加载时的bucket和max配置:
sudo dmesg | grep conntrack
找类似这样的记录:
nf_conntrack version 0.5.0 (16384 buckets, 65536 max)
哈希表使用情况:
grep conntrack /proc/slabinfo
前4个数字分别为:
当前活动对象数、可用对象总数、每个对象的大小(字节)、包含至少1个活动对象的分页数
当前跟踪的连接数:
sudo sysctl net.netfilter.nf_conntrack_count
或 cat /proc/net/nf_conntrack | wc -l
跟踪的每个连接的详情:
cat /proc/net/nf_conntrack
统计里面的TCP连接的各状态和条数
cat /proc/net/nf_conntrack | awk '/^.tcp.$/ {count[$6]++} END {for(state in count) print state, count[state]}'
记录数最多的10个ip
cat /proc/net/nf_conntrack | awk '{print $7}' | cut -d "=" -f 2 | sort | uniq -c | sort -nr | head -n 10