问题现象:
服务器负载正常,但请求大量超时,服务器/应用访问日志看不到相关请求记录。
在 dmesg 或 /var/log/messages 看到大量以下记录:
kernel: nf_conntrack: table full, dropping packet.
原因:
服务器访问量大,内核 netfilter 模块 conntrack 相关参数配置不合理,导致 IP 包被丢掉,连接无法建立。
查看nf_conntrack表最大连接数:
sudo sysctl net.netfilter.nf_conntrack_buckets #只读
cat /proc/sys/net/netfilter/nf_conntrack_max查看nf_conntrack表当前连接数:
cat /proc/sys/net/netfilter/nf_conntrack_count
sudo sysctl net.netfilter.nf_conntrack_max
#默认 nf_conntrack_buckets * 4
max 是 bucket 的多少倍决定了每个桶里的链表有多长,因此默认链表长度为 4
跟踪连接记录
Ubuntu 通常没有 /proc/net/nf_conntrack 文件,用 conntrack 命令代替,输出一样
sudo conntrack -L -o extended | tail -n 50
CentOS:
sudo tail -n 50 /proc/net/nf_conntrack
输出例:
ipv4 2 tcp 6 295019 ESTABLISHED src=47.96.117.250 dst=125.109.193.42 sport=40888 dport=18348 src=125.109.193.42 dst=47.96.117.250 sport=18348 dport=40888 [ASSURED] mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
#记录格式:
#网络层协议名、网络层协议编号、传输层协议名、传输层协议编号、记录失效前剩余秒数、连接状态(不是所有协议都有)
#之后都是 key=value 或 flag 格式,1 行里最多 2 个同名 key(如 src 和 dst),第 1 次出现的来自请求,第 2 次出现的来自响应
#flag:
#[ASSURED] 请求和响应都有流量
#[UNREPLIED] 没收到响应,哈希表满的时候这些连接先扔掉
四层协议类型和连接数:
sudo conntrack -L -o extended | awk '{sum[$3]++} END {for(i in sum) print i, sum[i]}'
或:
sudo cat /proc/net/nf_conntrack | awk '{sum[$3]++} END {for(i in sum) print i, sum[i]}'TCP 连接各状态对应的条数:
sudo conntrack -L -o extended | awk '/^.*tcp.*$/ {sum[$6]++} END {for(i in sum) print i, sum[i]}'
或:
sudo cat /proc/net/nf_conntrack | awk '/^.*tcp.*$/ {sum[$6]++} END {for(i in sum) print i, sum[i]}'三层协议类型和连接数:
sudo conntrack -L -o extended | awk '{sum[$1]++} 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 conntrack -L -o extended | awk '{print $7}' | cut -d "=" -f 2 | sort | uniq -c | sort -nr | head -n 10
或:
sudo cat /proc/net/nf_conntrack | awk '{print $7}' | cut -d "=" -f 2 | sort | uniq -c | sort -nr | head -n 10
/proc/sys/net目录
所有的TCP/IP参数都位于/proc/sys/net目录下(请注意,对/proc/sys/net目录下内容的修改都是临时的,任何修改在系统重启后都会丢失)
/etc/sysctl.conf文件
/etc/sysctl.conf是一个允许你改变正在运行中的Linux系统的接口。它包含一些TCP/IP堆栈和虚拟内存系统的高级选项,可用来控制Linux网络配置,由于/proc/sys/net目录内容的临时性,建议把TCPIP参数的修改添加到/etc/sysctl.conf文件, 然后保存文件,使用命令“/sbin/sysctl –p”使之立即生效。
解决办法:
1、临时修改
echo 262144 | sudo tee /sys/module/nf_conntrack/parameters/hashsize
sysctl net.netfilter.nf_conntrack_max=1048576
sysctl net.netfilter.nf_conntrack_tcp_timeout_established=3600
2、修改配置文件(永久)
用 sysctl [-w] 或 echo xxx > /pro/sys/net/netfilter/XXX 做的修改在重启后会失效。如果测试过没问题,在 /etc/sysctl.d/ 下新建配置文件,这里以 90-conntrack.conf 为例(CentOS 6 等旧系统编辑 /etc/sysctl.conf),系统启动时会加载里面的设置:
vi /etc/sysctl.conf或者vi /etc/sysctl.d/90-conntrack.conf
#格式:<参数>=<值>,等号两边可以空格,支持 # 注释
net.nf_conntrack_max=1048576
net.netfilter.nf_conntrack_max=104857
net.netfilter.nf_conntrack_buckets = 262144
net.netfilter.nf_conntrack_max=104857
net.netfilter.nf_conntrack_icmp_timeout=10
net.netfilter.nf_conntrack_tcp_timeout_syn_recv=5
net.netfilter.nf_conntrack_tcp_timeout_syn_sent=5
net.netfilter.nf_conntrack_tcp_timeout_established=300
net.netfilter.nf_conntrack_tcp_timeout_fin_wait=10
net.netfilter.nf_conntrack_tcp_timeout_time_wait=10
net.netfilter.nf_conntrack_tcp_timeout_close_wait=10
net.netfilter.nf_conntrack_tcp_timeout_last_ack=10
如果修改了配置文件,要马上应用配置文件里的设置:
sudo sysctl -p /etc/sysctl.d/90-conntrack.conf
#不传文件路径默认加载 /etc/sysctl.conf
tail -f /var/log/messages #查看是否正常
参考信息:
http://keithmo.me/post/2018/08/25/conntrack-tuning/#b-%E8%B0%83%E6%95%B4%E5%86%85%E6%A0%B8%E5%8F%82%E6%95%B0
https://testerhome.com/topics/7509
http://keithmo.me/post/2018/08/25/conntrack-tuning/