問題描述
連接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連接,僅供參考。現場以實際情況為準。