1、背景
使用netfilter實現NAT功能是網絡技術中常用的一種方式,但是在未對netfilter的參數做任何優化的情況下,且業務流量比較大的情況下會遇到部分NAT失效的情況。
2、技術分析
在使用netfilter的NAT規則后,會生成對應的Conntrack連接跟蹤記錄信息,在對應連接跟蹤記錄表滿的情況下,新的請求將會被drop,因此會遇到NAT失效的情況。
Conntrack連接跟蹤記錄會存儲在hashtable里面,涉及到一個查詢時間與存儲空間的效率問題: 連接跟蹤entry hash到對應的hash桶(bucket)中,每個bucket中只有一個link node,每個link node中只存儲一個entry(直接把entry放在bucket里),能達到效率最高O(1),但是hashtable表中占用很大的存儲空間; 采用hashtable + linknode list的方案能在存儲空間和查詢效率之間取個平衡,其中連接跟蹤entry會hash到對應hash桶(bucket)中,bucket里面是常用的link node list單鏈表來存放多個entry的信息,其中bucket里面存儲的是頭指針,其中bucket是直接占用內存,若按照nf_conntrack的struck結構體來分配則占用大約300字節,若桶里放的是該單鏈表的頭指針則一般為8字節,可以大幅度減少內存空間;官方推薦一般bucket中存儲4個entry,即nf_conntrack_max = nf_conntrack_buckets *4,四倍的關系,其查詢效率為O(1)+O(4),即查詢hash表到bucket,再插敘link node list單鏈表到具體entry的地址;

3、參數優化
其中在內核中Conntrack重要相關的參數有:
net.netfilter.nf_conntrack_count,表示當前連接跟蹤數;
net.netfilter.nf_conntrack_max,表示最大連接跟蹤數;
net.netfilter.nf_conntrack_buckets,表示連接跟蹤表的大小(bucket桶數量);
net.netfilter.nf_conntrack_tcp_timeout_established,tcp會話的超時時間,默認是432000 (5天); net.netfilter.nf_conntrack_tcp_timeout_time_wait,tcp處于 TIME_WAIT 的超時時間,默認 120s;
conntrack_max和conntrack_buckets參數計算和設置:
CONNTRACK_MAX的最大值取與宿主機內存有關系,對應計算關系為CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32),其中 ARCH 為 CPU 架構,值為 32 或 64位,即32 位系統使用內存的 1/16384,64 位系統再減半,如32位的64G系統,conntrack_max = (64 * 1024^3) / 16384 / (32 / 32) =4,194,304,約為400萬的entry,bucket的數量按照官方推薦的為entry的四分之一計算,conntrack_buckets = 4194304/4 = 1048576 約為100萬;則這兩個參數可設置在系統中;
計算算內存占用,其中nf_conntrack struck本身初始化就得占用300左右字節,bucket中link node指針占用個8個字節,則內存占用 = 4194304 * 300 + 1048576 * 8 = 1266679808字節 = 1208M
若在已經配置合理conntrack_max和conntrack_buckets情況下,實際的conntrack數量超過max,則需要進行如下優化: nf_conntrack_tcp_timeout_time_wait,time_wait為了讓包收收尾,早前網絡不穩定,預留2分鐘為了讓這些釋放連接的包能在2分鐘內順利到達,現在網絡環境好了,connection track沒必要跟蹤這么長時間,可以設置成60s或更小,connection track的數量立馬下降; nf_conntrack_tcp_timeout_established也會影響conntrack track數量 ,該參數會跟蹤一個記錄5days(官方推薦),這個值對應的場景是 “雙方建立了連接后一直不發包,直到 5 天后才發”,可以把該值改為600s。