再次深入到ip_conntrack的conntrack full问题

简介:
增加nf_conntrack_max固然可以缓解这个问题,或者说减小conntrack表项占据内核内存的时间也可以缓解之,然而这种补救措施都是治标不治本的.

注解:不要过度减小NEW以及TCP的establish的CT状态的timeout的原因

尽量不要减小NEW状态时间,因为对于某些恶劣的网络,一个数据包的来回确实需要很长时间,对于TCP而言,此时RTT还没有测量呢。如果NEW状态的conntrack保留时间过短,就会导致大量NEW状态的连接,而对于很多依赖ctstate的模块而言,这样就会有问题,比如iptables的filter表中使用ESTABLISH状态来放过前向包的返回包就会有问题,此时ip_conntrack很有可能由于NEW状态时间过短而将返回包作为NEW状态处理而不是ESTABLISH状态,如此一来,返回包就无法通过了。如下图所示:


使用简单的实验可以很容易证实上面的图示,以简单的udp通信为例,编写一个udp-echo程序,服务器简单echo客户端送达的字符串:
    for(;;)     {      n = recvfrom(sd, msg, MAXLINE, 0, pcliaddr, &len);           sleep(5);           sendto(sd, msg, n, 0, pcliaddr, len);     }

然后在客户端上执行echo $sec /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
其中sec要比服务器端的sleep参数更小即可。
如此udp客户端将收不到服务器eho回来的字符串,因为客户端只是放行状态为establish的入流量,如果ip_conntrack_udp_timeout配置过于短暂,NEW状态的conntrack过早被释放,这样将不会有establish状态的流量了。对于UDP而言,由于它是不确认无连接允许丢包的,因此影响还不是很大,TCP也有类似的问题,那就是如果你连接一个很远的且网络状况很恶劣的TCP服务器,然后你把ip_conntrack_tcp_timeout_synsent设置很小,这样就几乎完不成三次握手了,更进一步,如果你把ip_conntrack_tcp_timeout_established设置过小,那么一旦三次握手建立连接之后,客户端和服务器之间很久不发包,当establish状态到期后,conntrack被释放,此时服务器端主动发来一个包,该包的conntrack状态会是什么呢?因此给予tcp的establish状态5天的时间,是可以理解的。需要注意的是,对于tcp而言,由于无法简单的控制服务器发送syn-ack的延时,因此需要在establish状态而不是new状态做文章了(实际上,ip_conntrack的establish状态映射成了tcp的多个状态,包括syn-ack,ack,established),试试看,效果和udp的一样。
        前面关于ip_conntrack扯的太远了,我们的首要问题是conntrack full的问题。实际上,如果深入思考这个conntrack full的问题,就会发现,并不是conntrack容量太小或者表项保留时间过长引发的full。现实中的万事万物都不是无限的,对于计算机资源而言,更应该节约使用,不能让无关人士浪费这种资源,另外既然内核默认了一个表项的存活时间,那肯定是经过测试的经验值,自有它的道理。因此本质问题在于很多不需要conntrack的包也被conntrack了,这样就会挤掉很多真正需要conntrack的流量。
        那么都是哪些流量需要conntrack呢?常用的就两个,一个是任何使用ctstate或者state这些match的iptables规则,另外一个就是所有的iptables的nat表中的规则,如果我们事先知道哪些流量需要使用iptables的[ct]state来控制,并且也知道哪些流量需要做NAT,那么余下的流量就都是和conntrack无关的流量了,可以不被ip_conntrack来跟踪。
        幸运的是,Linux的Netfilter在PREROUTING以及OUTPUT这两个HOOK的conntrack之前安插了一个优先级更高的table,那就是raw,通过它就可以分离出不需要被conntrack的流量。如果你确定只有某个网卡进来的流量才需要做NAT,那么就执行下面的规则:
iptables -t raw -A PREROUTING ! –I $网卡 -j NOTRACK iptables –t raw –A OUTPUT –j NOTRACK
这样一来,资源就不会浪费在无关人士身上了,性能也会有所提高,因为凡是NOTRACK的流量,都不会去查询conntrack的hash表,因为在ip(nf)_conntrack_in的内部的开始有一个判断:
if ((*pskb)->nfct)     return NF_ACCEPT;
而NOTRACK这个target的实现也很简单:
(*pskb)->nfct = &ip_conntrack_untracked.info[IP_CT_NEW];
事实上将一个占位者设置给skb的nfct,这样可以保持其它代码的一致性。
     可见,必要时同时采取三种方式比较有效:1.增大conntrack_max;2.减少状态保存时间;3.分离无关流量。然而除了第三种方式,其余两种方式在操作时必须给自己十足的理由那么做才行,对于1,比必须明白内核内存被占有的方式,对于2,看看本文的前半部分。
iptables -A FORWARD -m state --state UNTRACKED -j ACCEPT

最后有个提问:

对于没有keepalive的TCP连接而言,试想服务器和客户端在establish状态之后5天内都没有互相通信,5天后的一天,服务器主动发送了一个数据包给客户端,然而此时防火墙/NAT设备上的conntrack状态已经过期被删除,此时该数据包将会被认为是NEW状态的数据包,被DROP,客户端永远收不到这个数据包,进而也不会发送ACK,服务器端不断重发,不断被防火墙DROP,当重发次数达到一定次数后,服务器RESET该连接,然而客户端如何得知,只有客户端主动发包才能打破这个僵局,然而谁能保证客户端一定会主动发包?这是不是Linux的ip_conntrack的一种缺陷,设计5天时间的establish状态是不是一种极限措施,然而谁又能保证5天内两端不断通信呢?



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1269007

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
网络协议 数据库
nf_conntrack模块导致服务器Drop Packet
nf_conntrack模块导致服务器Drop Packet
176 0
|
网络协议 网络安全 网络架构
IPV6错误: IP is not ICMP pingable. Please make sure ICMP is not blocked. If you are blocking ICMP
IPV6错误: IP is not ICMP pingable. Please make sure ICMP is not blocked. If you are blocking ICMP
220 0
iptable和netfilter
https://www.cnblogs.com/ilinuxer/p/6364064.html https://www.cnblogs.com/ggjucheng/archive/2012/08/19/2646466.html
937 0
|
存储 算法 网络架构
|
网络协议 网络安全
|
网络协议 Linux 开发工具