连接跟踪模块导致的网络不可用

今天将一个业务的流量切到新部署的一台机器上。前几天已经灰度了一个业务到这台机器上,一直很稳定,所以准备切更多的流量。
11点左右开始把业务的流量切到这台机器上,没多久业务反馈服务不可访问,紧急把流量切回到原服务,留下新机器备查。
这台机器的操作系统是CentOS 7.0:

[root@localhost product]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
[root@localhost product]#uname -a
Linux localhost 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

查找原因

查看业务日志发现的日志:

2019-07-30 11:49:04 [ERROR] [metrics] sendto failed: operation not permitted
2019-07-30 11:49:04 [ERROR] can't watch /cloud/redisservice/xxx.xxx.xxx.xxx:9207: Get http://config.xxx.xxx.com/: dial tcp: lookup config.xxx.xxx.com on xxx.xxx.xxx.xxx:53: write udp xxx.xxx.xxx.xxx:42381->xxx.xxx.xxx.xxx:53: write: operation not permitted
2019-07-30 11:49:05 [ERROR] [metrics] sendto failed: operation not permitted
2019-07-30 11:49:08 [ERROR] [metrics] sendto failed: operation not permitted
2019-07-30 11:49:09 [ERROR] [metrics] sendto failed: operation not permitted
2019-07-30 11:49:11 [ERROR] [metrics] sendto failed: operation not permitted
2019-07-30 11:49:12 [ERROR] [metrics] sendto failed: operation not permitted
2019-07-30 11:49:13 [ERROR] [metrics] sendto failed: operation not permitted

发现有大量的UDP的错误,比如DNS查询, 以及发送metric消息(我们是通过UDP发送的), 错误类型 operation not permitted
。通过google发现有类似的问题: Linux UDP sendto error: Operation not permitted解决方法
, 原因是连接跟踪表满了,导致丢包,所以先朝着这个方向跟踪。

查看内核的消息

使用 dmesg
查看内核的消息:

[27772673.752270] nf_conntrack: table full, dropping packet
[27772678.728802] net_ratelimit: 1367 callbacks suppressed
[27772678.728809] nf_conntrack: table full, dropping packet
[27772678.728857] nf_conntrack: table full, dropping packet
[27772678.729754] nf_conntrack: table full, dropping packet
[27772678.732953] nf_conntrack: table full, dropping packet
[27772678.733410] nf_conntrack: table full, dropping packet
[27772678.734449] nf_conntrack: table full, dropping packet
[27772678.740774] nf_conntrack: table full, dropping packet
[27772678.742810] nf_conntrack: table full, dropping packet
[27772678.743280] nf_conntrack: table full, dropping packet
[27772678.746589] nf_conntrack: table full, dropping packet
[27783682.308966] sysctl (13991): drop_caches: 3
[27786553.698652] sysctl (2160): drop_caches: 3

果然连接跟踪表满了。

查看连接跟踪日志

那么既然我们确定是连接跟踪表满了,那么检查一下连接跟踪的日志信息:

[root@dbl14195 redisservice_product]# tail -f /proc/net/nf_conntrack
ipv4     2 tcp      6 28 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=63518 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=63518 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 64 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=60390 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=60390 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 86 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8788 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=8788 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 111 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=57070 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=57070 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 37 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=12400 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=12400 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 9 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=43830 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=43830 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 40 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=33886 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=33886 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 30 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=41580 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=41580 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 42 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=51388 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=51388 [ASSURED] mark=0 zone=0 use=2
ipv4     2 tcp      6 117 TIME_WAIT src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=63766 dport=8063 src=xxx.xxx.xxx.xxx dst=xxx.xxx.xxx.xxx sport=8063 dport=63766 [ASSURED] mark=0 zone=0 use=2

不光是UDP的,还包括TCP的连接。
查看nf_conntrack的有些参数配置:

[root@localhost product]# cat /proc/sys/net/netfilter/nf_conntrack_count
4489

[root@localhost product]# cat /proc/sys/net/netfilter/nf_conntrack_max
65536

默认情况下 nf_conntrack_max
是65536,可能的原因是短时间内有大量的短连接到了这台机器,超过了这个最大值,导致连接大量丢包,服务不可能用。

解决办法

尝试移除 conntrack 模块

查看conntrack模块的情况:

[root@localhost product]# lsmod|grep conntrack
xt_conntrack           12760  1
nf_conntrack_ipv4      14862  2
nf_defrag_ipv4         12729  1 nf_conntrack_ipv4
nf_conntrack          105702  6 xt_CT,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_ipv4

看到这台机器加载了 nf_conntrack
相关的模块,在原来的业务的机器上查看没有加载这些模块,这也是原来业务跑的好好的,切换到现在的机器上出就出问题的原因。
尝试移除这些模块:

[root@localhost product]# modprobe -r nf_conntrack_netbios_ns nf_conntrack_ipv4 xt_conntrack
modprobe: FATAL: Module nf_conntrack_ipv4 is in use.

[root@localhost product]# lsmod|grep nf_conntrack_ipv4
nf_conntrack_ipv4      14862  2
nf_defrag_ipv4         12729  1 nf_conntrack_ipv4
nf_conntrack          105702  6 xt_CT,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_ipv4


[root@localhost product]# rmmod nf_conntrack
rmmod: ERROR: Module nf_conntrack is in use by: xt_CT nf_nat nf_nat_ipv4 xt_conntrack nf_nat_masquerade_ipv4 nf_conntrack_ipv4

模块被其它模块所使用,而且其它模块又被另外的模块所使用,不容易删除,而且删很多的模块还是一个计较危险的操作。

禁用连接跟踪

提高跟踪连接的最大数只是一个临时的办法,因为不确定的连接数最大又多少,而且跟踪连接数还耗费一定的资源,既然暂时美誉办法把模块卸载,所以想办法禁用掉。
然后找到一个简单的办法,执行下面的命令可以对所有的连接停止跟踪:

iptables -t raw -A PREROUTING -j NOTRACK
iptables -t raw -A OUTPUT -j NOTRACK

如果只想禁掉对特定端口的跟踪,可以使用下面的命令:

iptables -t raw -I PREROUTING -p tcp --dport 80 -j NOTRACK
iptables -t raw -I PREROUTING -p tcp  --sport 80 -j NOTRACK
iptables -t raw -I OUTPUT -p tcp --dport 80 -j NOTRACK
iptables -t raw -I OUTPUT -p tcp --sport 80 -j NOTRACK

如果你正在配置一个高吞吐的机器,一定要关注 conntrack
Linux调优
也介绍了调整conntrack的参数,网上业余很多相关的介绍。