計(jì):從conntrack到iptables的運(yùn)維實(shí)戰(zhàn))
連接跟蹤流量統(tǒng)計(jì)這是Linux網(wǎng)絡(luò)運(yùn)維里一個(gè)特別容易被忽視但關(guān)鍵時(shí)刻能救命的角落。很多人搞iptables、搞防火墻規(guī)則精通得很一說(shuō)到“你線上每秒多少新建連接連接表占用多少到底哪個(gè)IP在持續(xù)往外發(fā)包”就啞火了。原因很簡(jiǎn)單連接跟蹤conntrack和流量統(tǒng)計(jì)這兩件事平時(shí)不會(huì)主動(dòng)出現(xiàn)在監(jiān)控面板上等出了事故你才想起去查往往已經(jīng)晚了。這篇東西我把它定位成一篇實(shí)操經(jīng)驗(yàn)匯總。我不打算從頭講netfilter的論文級(jí)原理更多是站在一個(gè)長(zhǎng)期跟連接表、計(jì)數(shù)器、NAT規(guī)則打交道的老運(yùn)維視角把連接跟蹤是怎么回事、流量統(tǒng)計(jì)到底有哪幾條路可以走、每一步怎么落地、踩過(guò)哪些坑一次說(shuō)清楚。適合剛接手公司網(wǎng)關(guān)、負(fù)載均衡或者K8s節(jié)點(diǎn)的同行也適合那些被“conntrack表滿了”折磨過(guò)的新手??赐昴阒辽倌茏约捍钜惶缀?jiǎn)單但可靠的流量統(tǒng)計(jì)腳本也能在連接表異常時(shí)快速定位方向。1. 連接跟蹤到底在干什么為什么流量統(tǒng)計(jì)繞不開它1.1 連接跟蹤的本質(zhì)內(nèi)核里的“狀態(tài)記賬本”連接跟蹤全稱connection tracking是Linux內(nèi)核netfilter框架提供的一項(xiàng)基礎(chǔ)能力。它的核心工作是把經(jīng)過(guò)主機(jī)的數(shù)據(jù)流抽象成一條“連接”記錄這條連接的五元組信息協(xié)議、源IP、源端口、目的IP、目的端口連同當(dāng)前所處的狀態(tài)NEW新建、ESTABLISHED已建立、RELATED關(guān)聯(lián)連接比如FTP的數(shù)據(jù)通道、INVALID無(wú)效。打個(gè)比方你就懂了。連接跟蹤表就像餐廳前臺(tái)的服務(wù)員每一桌客人進(jìn)來(lái)他會(huì)記一下桌號(hào)、人數(shù)、點(diǎn)沒點(diǎn)菜、吃到哪個(gè)階段。后面上菜、加單、結(jié)賬全靠這本賬。沒有這個(gè)賬本防火墻的state規(guī)則沒法做——你憑什么判斷這個(gè)包是回應(yīng)之前的請(qǐng)求還是外部主動(dòng)打進(jìn)來(lái)的新攻擊NAT也一樣源地址轉(zhuǎn)換后回程的包要能逆轉(zhuǎn)翻譯回去必須查連接跟蹤表里存的映射關(guān)系。所以只要你的機(jī)器做了NAT、開了防火墻并且用了state/ct狀態(tài)匹配、或者跑了Docker、Kubernetes這種重度依賴網(wǎng)絡(luò)策略的容器平臺(tái)連接跟蹤就一定是開啟的。1.2 連接跟蹤表和流量統(tǒng)計(jì)的關(guān)系連接跟蹤表本身不統(tǒng)計(jì)字節(jié)數(shù)。它只管“誰(shuí)跟誰(shuí)在通信現(xiàn)在什么狀態(tài)”。但正因?yàn)樗拇嬖趦?nèi)核可以在連接創(chuàng)建、更新、銷毀的各個(gè)生命周期節(jié)點(diǎn)上天然掛鉤各種計(jì)數(shù)邏輯。這就是為什么我們?cè)趇ptables規(guī)則里能看到-c計(jì)數(shù)器在nftables里能定義counter在conntrack工具里能查到bytes和packets字段。換句話說(shuō)連接跟蹤給了你兩個(gè)維度的數(shù)據(jù)一個(gè)是連接數(shù)橫向規(guī)模一個(gè)是流量字節(jié)縱向體量。這兩個(gè)維度合在一起才能回答運(yùn)維里最常問(wèn)的“誰(shuí)在消耗帶寬”“誰(shuí)在瘋狂發(fā)起連接”“NAT網(wǎng)關(guān)的負(fù)載是否到了瓶頸”。1.3 什么時(shí)候你會(huì)真正需要做流量統(tǒng)計(jì)我遇到過(guò)好幾種典型場(chǎng)景逼著你必須認(rèn)真做連接跟蹤流量統(tǒng)計(jì)第一種公司出口NAT設(shè)備領(lǐng)導(dǎo)想搞清楚每個(gè)部門、每個(gè)應(yīng)用占了多大帶寬。這時(shí)候你得按源IP聚合流量光看交換機(jī)的端口流量沒有任何意義。第二種后端服務(wù)突然被大量異常請(qǐng)求打滿但前端所有QPS指標(biāo)都是正常的。查了半天發(fā)現(xiàn)是某個(gè)內(nèi)網(wǎng)服務(wù)在跟外網(wǎng)建立大量短連接連接表被打爆了。這時(shí)候你得看清楚到底哪個(gè)進(jìn)程、哪個(gè)目的IP在制造連接風(fēng)暴。第三種做安全審計(jì)。要回溯某段時(shí)間某個(gè)IP的往來(lái)流量連接跟蹤日志是最好的“黑匣子”。這些場(chǎng)景沒有一套順手可用的連接跟蹤流量統(tǒng)計(jì)手段基本就是抓瞎。2. 流量統(tǒng)計(jì)的常見實(shí)現(xiàn)路徑——三選一看你有什么牌2.1 路徑一內(nèi)核計(jì)數(shù)器的被動(dòng)統(tǒng)計(jì)iptables/nftables自帶這是最樸素也最可靠的辦法。iptables的每條規(guī)則自帶兩個(gè)計(jì)數(shù)器packets和bytes。你只需要把統(tǒng)計(jì)用的規(guī)則放在合適位置內(nèi)核會(huì)默默幫你累加數(shù)據(jù)。它的優(yōu)勢(shì)在于不需要額外開服務(wù)不占額外CPU數(shù)據(jù)是內(nèi)核精確計(jì)數(shù)的不丟包不采樣。非常適合做“總量統(tǒng)計(jì)”和“按固定維度聚合統(tǒng)計(jì)”比如按源IP段、目的端口、協(xié)議來(lái)查流量。但它的短板也很明顯聚合維度不夠靈活。你寫了十條規(guī)則按十個(gè)IP統(tǒng)計(jì)那以后想按“IP和端口組合”查就得加規(guī)則計(jì)數(shù)器是累計(jì)值想要速率必須拉差值后自己算另外iptables計(jì)數(shù)器在規(guī)則被刷新或者機(jī)器重啟后會(huì)清零需要配套的持久化采集方案。2.2 路徑二連接跟蹤日志的被動(dòng)采集基于日志的大數(shù)據(jù)統(tǒng)計(jì)內(nèi)核提供了一個(gè)開關(guān)net.netfilter.nf_conntrack_acct開啟后連接跟蹤會(huì)對(duì)每條連接記錄packets和bytes數(shù)據(jù)。你可以通過(guò)conntrack -L命令隨時(shí)查看某條連接已經(jīng)傳了多少字節(jié)、多少個(gè)包。更進(jìn)一步可以用ctnetlink機(jī)制把連接事件新建、更新、銷毀推送到用戶態(tài)通過(guò)ulogd2這類工具落日志或者自己寫一段C/Python用netlink庫(kù)接收消息。每條連接的字節(jié)數(shù)、包數(shù)都能被記錄到。好處是統(tǒng)計(jì)維度非常自由——你可以存下來(lái)做離線分析、按任意字段group by也可以回溯歷史某條連接的流量。代價(jià)是量大的機(jī)器上日志會(huì)產(chǎn)生海量事件磁盤和CPU都有壓力實(shí)時(shí)性弱于計(jì)數(shù)器方案而且如果連接長(zhǎng)時(shí)間不斷開字節(jié)數(shù)只累計(jì)不輸出需要按超時(shí)兜底。2.3 路徑三流量采樣與鏡像分析NetFlow/sFlow/pcap旁路這條路嚴(yán)格來(lái)說(shuō)已經(jīng)不算連接跟蹤流量統(tǒng)計(jì)了但實(shí)際運(yùn)維里經(jīng)常拿來(lái)補(bǔ)充。思路是把流量旁路出來(lái)用采樣協(xié)議sFlow/NetFlow或者全量抓包pcap的方式交給外部分析器比如ELK、SQL數(shù)據(jù)庫(kù)做聚合。優(yōu)勢(shì)是靈活、不碰生產(chǎn)路徑、能拿到L7應(yīng)用層信息劣勢(shì)是需要額外部署硬件交換機(jī)支持sFlow還好純服務(wù)器環(huán)境下還得做分光器或者端口鏡像成本高采樣有概率丟數(shù)據(jù)不適合對(duì)準(zhǔn)確性極其敏感的對(duì)賬場(chǎng)景。2.4 三條路徑的選型對(duì)照維度內(nèi)核計(jì)數(shù)器連接跟蹤日志采樣/鏡像精確度精確精確抽樣有誤差實(shí)時(shí)性秒級(jí)主動(dòng)拉取事件級(jí)推送秒級(jí)系統(tǒng)開銷極低連接量大的主機(jī)有壓力網(wǎng)絡(luò)和存儲(chǔ)壓力高持久化需自己采集天然寫入日志分析端存儲(chǔ)聚合靈活度受限于規(guī)則配置任意維度SQL查詢最靈活含L7適合場(chǎng)景網(wǎng)關(guān)/NAT計(jì)數(shù)器安全審計(jì)、連接級(jí)明細(xì)全鏈路監(jiān)控、協(xié)議分析我個(gè)人的建議是日常監(jiān)控、容量預(yù)警這種以路徑一為主簡(jiǎn)單直接需要做安全審計(jì)或查歷史連接時(shí)路徑二配合conntrack工具臨時(shí)看甚至靠journalctl慢慢撈規(guī)模大且有專業(yè)流量分析平臺(tái)的再加路徑三作為補(bǔ)充。3. 實(shí)操環(huán)節(jié)五種最常用的連接跟蹤流量統(tǒng)計(jì)手段3.1 看一臺(tái)機(jī)器當(dāng)前活躍連接數(shù)摸清壓力先別急著寫統(tǒng)計(jì)腳本第一步應(yīng)該是能快速回答“這臺(tái)機(jī)器當(dāng)前同時(shí)在跑多少條連接”。用一行命令# 查看當(dāng)前連接跟蹤總數(shù) cat /proc/sys/net/netfilter/nf_conntrack_count # 查看系統(tǒng)允許的最大連接跟蹤數(shù) cat /proc/sys/net/netfilter/nf_conntrack_max當(dāng)nf_conntrack_count接近nf_conntrack_max的時(shí)候事情就危險(xiǎn)了——新連接會(huì)被內(nèi)核直接丟棄表現(xiàn)為服務(wù)端口telnet不上但ping通業(yè)務(wù)日志里出現(xiàn)“connection reset”且有周期性。這個(gè)數(shù)字應(yīng)該進(jìn)你的監(jiān)控系統(tǒng)告警閾值我一般設(shè)在最大值的80%左右。3.2 iptables計(jì)數(shù)器直接查流量最簡(jiǎn)單粗暴假設(shè)你想統(tǒng)計(jì)“訪問(wèn)本機(jī)8080端口的流量總量”直接加一條規(guī)則iptables -I INPUT 1 -p tcp --dport 8080注意我沒給-j ACCEPT只是把規(guī)則掛在那里純計(jì)數(shù)。因?yàn)镮NPUT鏈默認(rèn)處理完所有規(guī)則會(huì)回到鏈策略只要不顯式跳轉(zhuǎn)計(jì)數(shù)規(guī)則不影響包的去向。這樣加規(guī)則多少有點(diǎn)“臟”更干凈的做法是建一條獨(dú)立的統(tǒng)計(jì)鏈iptables -N TRAFFIC_STAT iptables -A INPUT -j TRAFFIC_STAT iptables -A TRAFFIC_STAT -p tcp --dport 8080隨后想讀取某條規(guī)則累計(jì)的包數(shù)和字節(jié)數(shù)iptables -L TRAFFIC_STAT -v -x-x參數(shù)很關(guān)鍵作用是讓計(jì)數(shù)器輸出精確數(shù)字而不是縮寫成12K、34M這種帶單位的格式方便腳本解析。這個(gè)參數(shù)至少在需要把數(shù)據(jù)丟給監(jiān)控系統(tǒng)的場(chǎng)景里是必須的。3.3 按IP聚合統(tǒng)計(jì)流量拿腳本說(shuō)話計(jì)數(shù)器方案最實(shí)用的形態(tài)是寫一個(gè)腳本定時(shí)拉取計(jì)數(shù)器計(jì)算差值得到速率。我常用的邏輯如下# 清空指定鏈的計(jì)數(shù)器或重建規(guī)則全部歸零 iptables -Z TRAFFIC_STAT # 確認(rèn)規(guī)則存在后每分鐘執(zhí)行一次 # 先保存上一次的計(jì)數(shù)器讀取當(dāng)前值相減再除以間隔時(shí)間即得字節(jié)速率 prev_bytes$(cat /tmp/traffic_last.txt) curr_bytes$(iptables -L TRAFFIC_STAT -v -x -n | awk -v port8080 $3tcp $4dport {print $2}) echo $curr_bytes /tmp/traffic_last.txt rate_bytes$(( (curr_bytes - prev_bytes) / 60 ))實(shí)際生產(chǎn)環(huán)境里我會(huì)把這個(gè)邏輯編程成一段守護(hù)腳本輸出成timestamp ip bytes bytes_per_sec的格式丟給Prometheus文本文件采集器或者寫進(jìn)InfluxDB。核心思路就是不要指望iptables給你速率它只給累計(jì)增量速率永遠(yuǎn)是自己的時(shí)序系統(tǒng)算出來(lái)的。3.4 用conntrack命令查看連接級(jí)明細(xì)深挖單條連接如果你的問(wèn)題不是“總量多大”而是“哪條連接在跑大流量”那就要進(jìn)連接跟蹤表細(xì)看。工具是conntrack安裝包一般叫conntrack-tools。# 查看當(dāng)前所有連接過(guò)濾出字節(jié)數(shù)排序前10 conntrack -L -o extended | awk {print $NF} | sort -rn | head -10conntrack -L輸出長(zhǎng)格式時(shí)每條連接末尾會(huì)有bytes... packets...字段。-o extended這個(gè)參數(shù)很關(guān)鍵它額外輸出標(biāo)記、secmark等擴(kuò)展信息也確保字節(jié)數(shù)字段出現(xiàn)在解析里。如果要做每IP聚合conntrack -L -o extended | awk /udp|tcp/ { for(i1;iNF;i) { if($i ~ /^src/) {split($i,a,); srca[2]} if($i ~ /^bytes/) {split($i,b,); bytesb[2]} } total[src]bytes } END {for(ip in total) print total[ip], ip} | sort -rn | head -20這里的坑在于conntrack -L在高連接數(shù)的機(jī)器上本身就是重操作它會(huì)讀全部連接表可能占用CPU幾十毫秒甚至更多。生產(chǎn)環(huán)境大表比如超過(guò)十萬(wàn)條連接我是絕對(duì)不用它做高頻輪詢的——只用于事故現(xiàn)場(chǎng)手動(dòng)排查。3.5 nftables下的統(tǒng)計(jì)實(shí)現(xiàn)——現(xiàn)代服務(wù)器更推薦如果你用的發(fā)行版已經(jīng)全面轉(zhuǎn)向nftables比如新裝的Debian 12、Ubuntu 22.04而且沒有老iptables套件那么統(tǒng)計(jì)寫作nftables規(guī)則要干凈得多。nftables原生支持counter關(guān)鍵字能直接嵌在規(guī)則里nft add table inet traffic_stat nft add chain inet traffic_stat count_in { type filter hook input priority 0; } nft add rule inet traffic_stat count_in tcp dport 8080 counter讀取時(shí)也更方便nft list table inet traffic_stat輸出里直接能看到packets 12345 bytes 6789012。nftables的counter天生支持動(dòng)態(tài)map你可以定義一張“IP地址-計(jì)數(shù)器”的映射表然后一行規(guī)則對(duì)每個(gè)新源IP自動(dòng)建計(jì)數(shù)器nft add table inet traffic_stat nft add set inet traffic_stat per_ip { type ipv4_addr; flags dynamic; } nft add rule inet traffic_stat count_in ip saddr per_ip counter之后每來(lái)一個(gè)不同的源IP集合里會(huì)自動(dòng)增加一條記錄并配一個(gè)獨(dú)立的計(jì)數(shù)器。這功能比iptables的“限制規(guī)則條數(shù)”思路靈活太多也是我近兩年主推的方案。4. 深度解析連接跟蹤表為什么會(huì)滿以及它怎么拖垮流量統(tǒng)計(jì)4.1 表滿的連鎖反應(yīng)比想象中嚴(yán)重連接跟蹤表設(shè)計(jì)成固定容量的哈希表默認(rèn)值因發(fā)行版而異常見是65536、131072或者262144。當(dāng)表滿時(shí)內(nèi)核無(wú)法為新建連接分配跟蹤條目于是靜默丟包丟棄的位置在netfilter框架的nf_conntrack_in階段后面你再有防火墻、NAT都沒機(jī)會(huì)執(zhí)行。結(jié)果是外部新請(qǐng)求進(jìn)不來(lái)但Server端已經(jīng)在跑的ESTABLISHED連接不受影響。這種故障最有迷惑性的特征是“半通”——用戶訪問(wèn)部分失敗部分成功老連接正常重啟服務(wù)后短暫恢復(fù)又惡化。如果你對(duì)這種場(chǎng)景沒經(jīng)驗(yàn)很容易誤判成應(yīng)用層問(wèn)題反復(fù)重啟服務(wù)浪費(fèi)時(shí)間。4.2 哪些流量會(huì)大量消耗連接表?xiàng)l目UDP和TCP短連接是大頭。TCP短連接三次握手建一條四次揮手后條目不會(huì)立刻消失默認(rèn)TCP連接的超時(shí)時(shí)間是432000秒5天——你沒看錯(cuò)一條已經(jīng)關(guān)閉的TCP連接conntrack條目最長(zhǎng)可以賴在表里5天才被回收。UDP默認(rèn)超時(shí)30秒反而短得多。所以一條TCP連接只要存活超過(guò)超時(shí)時(shí)間或者關(guān)閉后沒被立即回收就會(huì)長(zhǎng)期占據(jù)一個(gè)表項(xiàng)。高并發(fā)短連接的服務(wù)比如Web API、RPC調(diào)用非常容易把表堆滿。業(yè)界普遍的調(diào)優(yōu)手法是修正超時(shí)參數(shù)# 縮短TCP連接超時(shí)從5天改為1小時(shí) sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established3600 # 短連接場(chǎng)景可以進(jìn)一步改小但要評(píng)估業(yè)務(wù)是否有長(zhǎng)連接另外還有兩個(gè)隱藏消耗一是NAT情況下同一個(gè)內(nèi)網(wǎng)IP的大量連接源端口很快耗盡但如果五元組不同conntrack照樣需要獨(dú)立條目二是有很多“半開連接”的場(chǎng)景SYN Flood攻擊會(huì)讓表里充滿SYN_SENT狀態(tài)的殘留條目。4.3 表滿之后的流量統(tǒng)計(jì)直接就廢了這里有個(gè)惡性循環(huán)值得單獨(dú)拉出來(lái)說(shuō)。連接跟蹤表滿后新連接無(wú)法被跟蹤意味著你通過(guò)conntrack日志做流量統(tǒng)計(jì)的那些路徑天然漏掉了被丟棄的連接流量。表現(xiàn)在你的統(tǒng)計(jì)系統(tǒng)上就是流量數(shù)字突然掉下去了但實(shí)際帶寬占用可能還很高。只看統(tǒng)計(jì)結(jié)果的話你會(huì)誤以為攻擊停了其實(shí)只是連接跟蹤已經(jīng)被打癱了。所以做流量統(tǒng)計(jì)必須聯(lián)動(dòng)監(jiān)控連接跟蹤表的使用率。表的使用率本身才是這臺(tái)機(jī)器網(wǎng)絡(luò)健康度的“體溫計(jì)”。一旦超過(guò)80%統(tǒng)計(jì)數(shù)字的可信度就要打折扣得先處理表滿問(wèn)題再來(lái)談流量分析。5. 實(shí)戰(zhàn)案例復(fù)盤一次連接表告警背后的流量統(tǒng)計(jì)排查5.1 現(xiàn)象與初步定位去年我接手一個(gè)內(nèi)網(wǎng)網(wǎng)關(guān)的維護(hù)某天凌晨告警網(wǎng)關(guān)的nf_conntrack_count超過(guò)閾值且連續(xù)三次采樣都在攀升。開始時(shí)我沒有著急調(diào)大nf_conntrack_max因?yàn)闄C(jī)器的內(nèi)存并不緊張盲調(diào)大只會(huì)掩蓋問(wèn)題——如果真是攻擊流量你調(diào)再大也會(huì)被打滿。我的排查順序先看系統(tǒng)連接跟蹤狀態(tài)里的TCP狀態(tài)分布cat /proc/net/nf_conntrack | awk -F {print $4} | sort | uniq -c | sort -rn輸出的狀態(tài)里大量集中在SYN_SENT和TIME_WAIT。SYN_SENT偏多說(shuō)明可能有對(duì)外異常連接在積壓TIME_WAIT大是正常的但配合連接數(shù)持續(xù)上漲就不是正常的了。5.2 順著連接表挖出元兇接著我用conntrack -L過(guò)濾出SYN_SENT狀態(tài)的連接按目的IP聚一下conntrack -L -o extended | grep SYN_SENT | awk -F dst {print $2} | awk {print $1} | sort | uniq -c | sort -rn | head結(jié)果一目了然有一個(gè)外網(wǎng)IP被大量去連而且都是SYN_SENT——對(duì)方根本不回包。netstat -antp確認(rèn)是某個(gè)Java服務(wù)在瘋狂重試外部接口調(diào)用對(duì)方接口有問(wèn)題重試機(jī)制沒做熔斷很快把連接表堆滿。這個(gè)案例最有價(jià)值的經(jīng)驗(yàn)是先看連接跟蹤的狀態(tài)分布再看異常的遠(yuǎn)端IP最后回到應(yīng)用層的重試邏輯。流量統(tǒng)計(jì)的表象是“連接數(shù)暴漲”但真實(shí)兇手是應(yīng)用層沒有保護(hù)。我當(dāng)時(shí)把服務(wù)的超時(shí)時(shí)間從3秒改成1秒并且加了熔斷連接跟蹤表立刻回到正常水位。5.3 事后補(bǔ)上的流量統(tǒng)計(jì)方案處理完事故后我給網(wǎng)關(guān)加了完整的流量統(tǒng)計(jì)與告警體系/proc/sys/net/netfilter/nf_conntrack_count每30秒采集一次超過(guò)nf_conntrack_max的75%發(fā)P2告警90%發(fā)P1。按源IP聚類統(tǒng)計(jì)TCP SYN連接速率每5分鐘計(jì)算一次超過(guò)基線十倍以上觸發(fā)告警。iptables統(tǒng)計(jì)鏈按月保留每天早上把前一天的累計(jì)字節(jié)和包數(shù)推到表格存儲(chǔ)供業(yè)務(wù)方按IP查月度用量。這套體系上線之后同樣的問(wèn)題再次出現(xiàn)時(shí)監(jiān)控能在我還沒被用戶投訴之前就發(fā)出告警。6. 常見問(wèn)題速查與避坑經(jīng)驗(yàn)6.1 為什么計(jì)數(shù)器統(tǒng)計(jì)的流量和實(shí)際帶寬對(duì)不上這件事最容易引起業(yè)務(wù)方質(zhì)疑。首先要搞清楚iptables計(jì)數(shù)器統(tǒng)計(jì)的是“經(jīng)過(guò)這臺(tái)主機(jī)網(wǎng)絡(luò)棧處理的IP層流量”不含以太網(wǎng)幀頭、不含交換機(jī)層面的廣播流量也不含被DPDK這種用戶態(tài)驅(qū)動(dòng)繞過(guò)的數(shù)據(jù)包。如果你的機(jī)器上有部分流量走XDP/DPDK旁路了那計(jì)數(shù)器天生就統(tǒng)計(jì)不到。另外本機(jī)回環(huán)流量lo口算不算你的業(yè)務(wù)流量取決于你規(guī)則鏈掛的位置。我做統(tǒng)計(jì)時(shí)通常會(huì)把lo接口排除在外避免重復(fù)計(jì)數(shù)。6.2 conntrack日志丟失統(tǒng)計(jì)出現(xiàn)空洞用conntrack日志方案時(shí)事件通過(guò)netlink socket傳遞給用戶態(tài)如果用戶態(tài)程序處理不過(guò)來(lái)內(nèi)核socket緩沖區(qū)滿了就會(huì)丟棄消息。這種丟棄是靜默的日志里看不出異常只會(huì)表現(xiàn)為某段時(shí)間的連接事件缺失。解決思路一是加大接收緩沖區(qū)net.core.rmem_default二是做降級(jí)——如果事件吞吐量過(guò)大就不追求逐條記錄改為周期性全量快照的增量式統(tǒng)計(jì)犧牲實(shí)時(shí)性換完整性三是把連接表Dump快照定期落盤比如每5分鐘把/proc/net/nf_conntrack導(dǎo)出壓縮存一份事故后直接翻歷史快照就行。6.3 計(jì)數(shù)器反向增長(zhǎng)數(shù)據(jù)出現(xiàn)氣泡我踩過(guò)一次很典型的坑。寫統(tǒng)計(jì)腳本時(shí)拿iptables計(jì)數(shù)器差值計(jì)算速率結(jié)果符號(hào)寫反了還是其次問(wèn)題是計(jì)數(shù)器在某個(gè)時(shí)間點(diǎn)突然跳變到超大值。查原因發(fā)現(xiàn)是有人手動(dòng)清空了規(guī)則重新加載后計(jì)數(shù)器歸零然后腳本認(rèn)為是“反向回繞”算出來(lái)的速率變成了天量數(shù)字。這個(gè)問(wèn)題的魯棒解法是腳本里判定如果當(dāng)前計(jì)數(shù)比上次小就丟棄這一輪差值一律輸出0而不是輸出負(fù)數(shù)。同時(shí)規(guī)則文件的變更操作要規(guī)范走自動(dòng)化發(fā)布避免人工干預(yù)計(jì)數(shù)器。6.4 如何應(yīng)對(duì)Kubernetes節(jié)點(diǎn)上的連接跟蹤統(tǒng)計(jì)盲區(qū)Kubernetes節(jié)點(diǎn)上Kube-proxy的iptables或IPVS模式大量依賴連接跟蹤。特別是IPVS模式它本身有更多連接條目因?yàn)槊總€(gè)Service的每個(gè)后端組合都會(huì)占據(jù)獨(dú)立的連接跟蹤項(xiàng)。流量統(tǒng)計(jì)的難點(diǎn)在于Service的ClusterIP只是虛擬IP你按源IP分類能聚合按目標(biāo)Service歸類就有難度了。我的建議是K8s場(chǎng)景下連接跟蹤統(tǒng)計(jì)盡量按Pod所在節(jié)點(diǎn)和網(wǎng)段聚合配合Service Mesh的sidecar流量指標(biāo)綜合判斷。純靠conntrack做細(xì)粒度業(yè)務(wù)流量拆解不僅效率低而且容易誤判。7. 終點(diǎn)之前留幾句實(shí)用閑話最后說(shuō)點(diǎn)不寫在教科書里的感受。連接跟蹤流量統(tǒng)計(jì)這個(gè)技術(shù)點(diǎn)不像高并發(fā)框架那樣能帶來(lái)炫酷的架構(gòu)升級(jí)也出不了什么精彩的PPT但在真實(shí)的生產(chǎn)環(huán)境里它就是我這種人賴以為生的“底層能力”。說(shuō)實(shí)話我自己最初踩的坑很多都不是技術(shù)難題而是沒把“連接跟蹤表也是要監(jiān)控的”這件事當(dāng)回事。給主機(jī)加內(nèi)存、加CPU、加帶寬都不如提前把nf_conntrack_count盯牢來(lái)得實(shí)在。還有一個(gè)心得是統(tǒng)計(jì)不是為了做日?qǐng)?bào)而是為了發(fā)現(xiàn)“異?!?。一個(gè)穩(wěn)定運(yùn)行的系統(tǒng)連接數(shù)、字節(jié)數(shù)、包數(shù)在時(shí)間軸上應(yīng)該是平滑的。任何突兀的抖動(dòng)都值得你去連接跟蹤表里翻一翻。與其研究更花哨的流量分析平臺(tái)不如先把自己的計(jì)數(shù)器腳本和告警閾值搞好。如果你現(xiàn)在手頭正好管著幾臺(tái)NAT網(wǎng)關(guān)或K8s節(jié)點(diǎn)建議今天就跑一遍cat /proc/net/nf_conntrack | wc -l cat /proc/sys/net/netfilter/nf_conntrack_max先把這兩個(gè)數(shù)記下來(lái)再順手看一眼你的監(jiān)控系統(tǒng)里有沒有這兩個(gè)指標(biāo)。沒有的話補(bǔ)上它們比任何花架子優(yōu)化都實(shí)在。