问题描述
连接ECS实例中的应用时偶尔出现丢包现象。经排查,ECS实例的外围网络正常,但内核日志(dmesg)中存在kernel: nf_conntrack: table full, dropping packet
的错误信息。存在此问题的ECS实例符合如下条件。
镜像:
aliyun-2.1903-x64-20G-alibase-20190327.vhd
及之后的所有镜像版本。内核:
kernel-4.19.24-9.al7
及以后的所有内核版本。
问题原因
nf_conntrack是Linux系统内NAT的一个跟踪连接条目的模块。nf_conntrack模块会使用一个哈希表记录TCP协议established connection记录,当这个哈希表满之后,新的连接会引发nf_conntrack: table full, dropping packet
错误。关于nf_conntrack模块中的重要参数,可参考如下信息。
nf_conntrack_buckets
:哈希表的大小,可在模块加载时指定参数,也可以通过sysctl
命令修改。当系统内存大于等于4 GB时,它的默认值是65536。nf_conntrack_max
:哈希表的最大节点个数,即nf_conntrack模块支持的最大连接数。当系统内存大于等于4 GB时,它的默认值是262144。对于处理大量连接的服务器来说,该默认值相对较小。nf_conntrack_tcp_timeout_time_wait
:nf_conntrack模块中保存time_wait状态的TCP连接时间,默认值为120s。
解决方案
请您结合现场实际情况,从如下两种解决方案中选择最适合您业务场景的方法。
方案一:通过sysctl接口调整nf_conntrack模块中的参数值
业务侧应提前自行确认应用程序可能使用的nf_conntrack最大连接数,并参考如下命令,通过sysctl接口调整nf_conntrack模块中的参数值。
sysctl -w net.netfilter.nf_conntrack_max=1503232
sysctl -w net.netfilter.nf_conntrack_buckets=375808 # 如果使用非4.19内核,该选项可能无法在运行时修改
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=60
命令中的参数值仅供参考,现场请结合实际业务情况进行调整。在调整前,建议提前创建快照或备份重要文件,确保数据安全。
参数配置建议:
如果您的业务本身符合并发连接数较高,其中主要是短连接的特性。建议增大
nf_conntrack_max
和nf_conntrack_buckets
的参数值,以确保不会由于连接数过多导致nf_conntrack的哈希表满。一般建议nf_conntrack_max
参数值为nf_conntrack_buckets
参数值的4倍 。建议一起调整
nf_conntrack_buckets
和nf_conntrack_max
参数。如果只改动nf_conntrack_max
参数值,可能会导致哈希表上的链表过长,查询效率低。如果只改动nf_conntrack_buckets
参数值,不能解决该问题。调整
nf_conntrack_tcp_timeout_time_wait
参数务必在理解其原理和可能影响的基础上,结合实际应用场景和性能监测结果,谨慎实施;以下是一些业务场景参数配置参考:对于需要处理大量短期连接的高并发服务(如Web服务器),可以考虑将
nf_conntrack_tcp_timeout_time_wait
设置为一个较短的时间,比如30秒或60秒。这样可以更快地回收端口资源,支持更多新连接。但请确保您的应用程序能够容忍潜在的少量数据重传或延迟问题。如果您的应用对数据传输的完整性有极高要求,比如金融交易系统,那么保持默认或接近默认的
nf_conntrack_tcp_timeout_time_wait
时间可能是更安全的选择,以确保所有数据包都能正确送达。在有较高网络延迟或不稳定的网络环境下,较短的
nf_conntrack_tcp_timeout_time_wait
时间可能增加数据丢失的风险,因此可能需要更保守的设置。
方案二:通过iptables过滤不需要追踪的连接
您可以在iptables规则中增加-j notrack参数 ,即过滤不需要追踪(track)的连接。该方式可以将不需要追踪的连接直接进行notrack处理,不会占用哈希表的空间,也就不会引发报错。
sudo iptables -t raw -A PREROUTING -p udp -j NOTRACK
sudo iptables -t raw -A PREROUTING -p tcp --dport 22 -j NOTRACK
此处的命令表示不追踪UDP和22端口的TCP连接,仅供参考。现场以实际情况为准。