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