linux的nf_conntrack问题排查


linux的nf_conntrack问题排查

问题

线上一台机器上线后,在高峰期频繁的出现redis time out的情况 image

排查

安装的软件
1 tengine
2 lua
3 开放iptables

由于采用tengine+lua的方式来收集缓存并且更新,首先怀疑是lua连接池那边的问题

在排查后发现最开始的lua中的配置有问题。最开始的keepalive的使用有问题。查询官方网站后发现 https://github.com/openresty/lua-resty-redis#set_keepalive

image 在每一个redis的命令过后都需要调用keealive来讲连接还会连接池。另外,还需要开启lua cache,这样lua的redis连接池才有效果

在所有的redis操作之后都加上keepalive后,问题仍然复现。接着排查系统的报错,发现系统中存在大量的nf_contrack的报错

nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.
nf_conntrack: table full, dropping packet.

由于这里开了防火墙,所有对包都有进行过滤,在流量超过100Mbps的时候会存在大量的包需要跟踪,导致相关内核的跟踪table满了。

  • /proc/sys/net/netfilter/nf_conntrack_count 查看内核中的跟踪记录数
    cat /proc/sys/net/netfilter/nf_conntrack_count  |more
    77143
  • /proc/sys/net/netfilter/nf_conntrack_max 内核配置的允许的最大跟踪数
  • /proc/net/nf_conntrack 跟踪的详细记录
    # cat /proc/net/nf_conntrack | more
    ipv4     2 tcp      6 0 TIME_WAIT src=111.107.193.1 dst=47.1.7.22 sport=50340 dport=443 src=47.100.37.202 dst=20
    2.107.193.175 sport=443 dport=50340 [ASSURED] mark=0 secmark=0 use=2
    ipv4     2 tcp      6 119 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=42901 dport=6379 src=127.0.0.1 dst=127.0.0.1 spo
    rt=6379 dport=42901 [ASSURED] mark=0 secmark=0 use=2
    ipv4     2 tcp      6 69 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=2799 dport=6379 src=127.0.0.1 dst=127.0.0.1 sport
    =6379 dport=2799 [ASSURED] mark=0 secmark=0 use=2
    ipv4     2 tcp      6 22 TIME_WAIT src=111.107.193.175 dst=44.157.12.16 sport=43786 dport=443 src=42.157.193.156 dst
    =202.107.193.175 sport=443 dport=43786 [ASSURED] mark=0 secmark=0 use=2

统计了一下相关nf_conntrack的数量。发现大量的是redis,80,443的跟踪记录。在超过这个最大限制之后,iptables就会把包丢掉。所以导致lua中的链接大量的timeout

解决办法

  • 关闭iptables 如果业务允许的话,可以关闭IPtable是服务

  • 添加raw链表 ``` cat /etc/sysconfig/iptables *raw :PREROUTING ACCEPT [14134737349:2610943907421] :OUTPUT ACCEPT [13834757992:17915396331600] -A PREROUTING -p tcp -m tcp --dport 80 -j NOTRACK -A PREROUTING -p tcp -m tcp --dport 443 -j NOTRACK #-A PREROUTING -p tcp -m tcp --dport 6379 -j NOTRACK -A OUTPUT -p tcp -m tcp --sport 80 -j NOTRACK -A OUTPUT -p tcp -m tcp --sport 443 -j NOTRACK #-A OUTPUT -p tcp -s 127.0.0.1 --dport 6379 -j NOTRACK #-A OUTPUT -p tcp -s 127.0.0.1 --sport 6379 -j NOTRACK COMMIT

这里添加针对相关端口的tpc协议不进行跟踪。这样的话,在其他链表中的规则就不用记录

- 修改内核参数

net.netfilter.nf_conntrack_max = 1048576
net.netfilter.ip_conntrack_tcp_timeout_established = 3600
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120

其中nf_conntrack_max这个内存有关。计算公式 CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32)  
64G的内存的机器,最大值为CONNTRACK_MAX = 64*1024*1024*1024/16384/2 = 2097152  

另外,还需要设置哈希表大小。通常为总表的1/8, 最大为1/2. CONNTRACK_BUCKETS = CONNTRACK_MAX / 8。  
64G的内存的系统,通常为262144 ~ 1048576  
运行状态中通过 sysctl net.netfilter.nf_conntrack_buckets 进行查看,通过文件 /sys/module/nf_conntrack/parameters/hashsize 进行设置,或者编辑/etc/modprobe.d/iptables.conf,然后重载模块生效

options nf_conntrack hashsize = 262144

ip_conntrack_tcp_timeout_established这表示连接的最大超时时间,默认为5天。如果tcp连接5天没有使用的话,跟踪记录才认为连接断开了。  



nf_conntrack_tcp_timeout_close_wait: closewait的等待时间,默认120s

nf_conntrack_tcp_timeout_fin_wait: fin wait的超时时间,默认120s

nf_conntrack_tcp_timeout_time_wait: time wait的等待时间。默认120s



### lua那边修改

- 都设置的keepalive
- lua开启cache模式

lua_code_cache on; ```