[轉帖]netstat -st輸出解析(二)

济南小老虎發表於2024-06-20
https://perthcharles.github.io/2015/08/27/timestamp-NAT/

  


netstat -st輸出的兩個重要資訊來源分別是/proc/net/snmp和/proc/net/netstat
本文將分類整理這些counterd的含義以及一些注意事項。


在整理的過程中,發現Rover Yu前輩已經
對這些counter做過詳細的整理。關於Rover Yu前輩的整理請檢視參考資料中的前三篇。
本著不重複造輪子的原則。本文將盡量遵循以下原則,以期從不同的角度呈現對這些counter的理解。

a. 分類整理:根據涉及的不同TCP細節,對counter做更細緻的分類
b. 結合sysctl配置:強調sysctl配置與counter之間的關聯
c. 強調異常:哪些counter出現非零值,往往就意味著出現了值得關注的問題
d. 資訊抽取: 如何從counter中獲取有價值的資訊
e. 僅關注TCP相關計數器

計數器分類

類別涉及counters
常量 RtoAlgorithm、RtoMin、RtoMax、MaxConn
建連統計 ActiveOpens、PassiveOpens、AttemptFails、CurrEstab、EstabResets
資料包統計 InSegs、OutSegs、RetransSegs、InErrs、OutRsts、InCsumErrors、EmbryonicRsts
syncookies功能 SyncookiesSent、SyncookiesRecv、SyncookiesFailed
TIME_WAIT回收 TW、TWRecycled、TWKilled、TCPTimeWaitOverflow
RTO次數 TCPTimeouts、TCPSpuriousRTOs、TCPLossProbes、TCPLossProbeRecovery、
TCPRenoRecoveryFail、TCPSackRecoveryFail、
TCPRenoFailures、TCPSackFailures、
TCPLossFailures
Retrans數量 TCPFastRetrans、TCPForwardRetrans、
TCPSlowStartRetrans、TCPLostRetransmit、
TCPRetransFail
FastOpen TCPFastOpenActive、TCPFastOpenPassive、
TCPFastOpenPassiveFail、TCPFastOpenListenOverflow、
TCPFastOpenCookieReqd
MD5 TCPMD5NotFound、TCPMD5Unexpected
DelayedACK DelayedACKs、DelayedACKLocked、DelayedACKLost、
TCPSchedulerFailed
DSACK TCPDSACKOldSent、TCPDSACKOfoSent、
TCPDSACKRecv、TCPDSACKOfoRecv、
TCPDSACKIgnoredOld、TCPDSACKIgnoredNoUndo
Reorder TCPFACKReorder、TCPSACKReorder、
TCPRenoReorder、TCPTSReorder
Recovery TCPRenoRecovery、TCPSackRecovery、
TCPRenoRecoveryFail、TCPSackRecoveryFail
Abort TCPAbortOnData、TCPAbortOnClose、
TCPAbortOnMemory、TCPAbortOnTimeout、
TCPAbortOnLingerTCPAbortFailed

|reset相關 | |
|記憶體prune | PruneCalled、RcvPruned、OfoPruned、
TCPMemoryPressures |
|PAWS相關 | PAWSPassive、PAWSActive、PAWSEstab |
|Listen相關 | ListenOverflows、ListenDrops |
|undo相關 | TCPFullUndo、TCPPartialUndo、
TCPDSACKUndo、TCPLossUndo |
|快速路徑與慢速路徑 | TCPHPHits、TCPHPHitsToUser、
TCPPureAcks、TCPHPAcks |



常量

這些常量是Linux3.10中的預設值,僅在升級了核心版本時才需要關心一下這些值的變化。

RtoAlgorithm:
    預設為1,RTO演算法與RFC2698一致
RtoMin:
    預設值為HZ/5,即200ms
RtoMax:
    預設值為120HZ,即120s
MaxConn:
    協議棧本身並不會限制TCP連線總數,預設值為-1.

建連統計

這些統計值中,只有CurrEstab反應的是系統當前狀態,而其他值則是反應的歷史狀態
同時需要注意的是,這些計數器將ESTABLISHED和CLOSE-WAIT狀態都作為當前連線數。
可以這麼理解:這兩個狀態都以為這local=>peer方向的連線未被關閉

ActiveOpens:
    主動建連次數,CLOSE => SYN-SENT次數
PassiveOpens:
    被動建連次數,RFC原意是LISTEN => SYN-RECV次數,但Linux選擇在三次握手成功後才加1
AttemptFails:
    建連失敗次數
EstabResets:
    連線被reset次數,ESTABLISHED => CLOSE次數 + CLOSE-WAIT => CLOSE次數
CurrEstab:
    當前TCP連線數,ESTABLISHED個數 + CLOSE-WAIT個數

資料包統計

這些統計值也是歷史值,獨立的來看意義並不大。一般可統計一段時間內的變化,關注以下幾個指標
a. TCP層的重傳率: ΔRetransSegs / ΔOutSegs — 越小越好,如果超過20%(這個值根據實際情況而定)則應該引起注意
b. Reset傳送頻率: ΔOutRsts / ΔOutSegs — 越小越好,一般應該在1%以內
c. 錯誤包占比: ΔInErrs / ΔInSegs — 越小越好,一般應該在1%以內,同時由checksum導致的問題包應該更低

InSegs:
    收到的資料包個數,包括有錯誤的包個數
OutSegs:
    傳送的資料包個數
RetransSegs:
    重傳的包個數
InErrs:
    收到的有問題的包個數
OutRsts:
    傳送的帶reset標記的包個數
InCsumErrors:
    收到的checksum有問題的包個數,InErrs中應該只有*小部分*屬於該型別
EmbryonicRsts:
    在SYN-RECV狀態收到帶RST/SYN標記的包個數

syncookies功能

syncookies一般不會被觸發,只有在tcp_max_syn_backlog佇列被佔滿時才會被觸發
因此SyncookiesSent和SyncookiesRecv一般應該是0。
但是SyncookiesFailed值即使syncookies機制沒有被觸發,也很可能不為0。
這是因為一個處於LISTEN狀態的socket收到一個不帶SYN標記的資料包時,就會調
用cookie_v4_check()嘗試驗證cookie資訊。而如果驗證失敗,Failed次數就加1。

SyncookiesSent:
    使用syncookie技術傳送的syn/ack包個數
SyncookiesRecv
    收到攜帶有效syncookie資訊包個數
SyncookiesFailed
    收到攜帶無效syncookie資訊包個數

注: syncookies機制是為應對synflood攻擊而被提出來的。


TIME-WAIT回收

TIME-WAIT狀態是TCP協議狀態機中的重要一環,伺服器裝置一般都有非常多處於TIME-WAIT狀態的socket
如果是在主要提供HTTP服務的裝置上,TW值應該接近TcpPassiveOpens值。
一般情況下,sysctl_tcp_tw_reuse和sysctl_tcp_tw_recycle都是不推薦開啟的。這裡解釋了為什麼
所以TWKilled和TWRecycled都應該是0。
同時TCPTimeWaitOverflow也應該是0,否則就意味著記憶體使用方面出了大問題。

TW:
    經過正常的TCP_TIMEWAIT_LEN(60s)結束TW狀態的socket數量
TWKilled:
    經過更短的時間結束TW狀態的socket數量。
    只有在net.ipv4.tcp_tw_recycle開啟時,排程TW timer時才可能用更短的timeout值。
TWRecycled:
    Port從TIMEWAIT socket中複用的次數。
    只有在sysctl_tcp_tw_reuse開啟時,才可能加1
    鬱悶的是上面兩個counter的命名與sysctl的命名真是超級不一致啊。囧...
TCPTimeWaitOverflow:
    如果沒有記憶體分配TIME-WAIT結構體,則加1

RTO次數

RTO超時對TCP效能的影響是巨大的,因此關心RTO超時的次數也非常必要。
當然3.10中的TLP機制能夠減少一定量的TCPTimeouts數,將其轉換為快速重傳。
關於TLP的原理部分,可參考我的這篇wiki

TCPTimeouts:
    RTO timer第一次超時的次數,僅包含直接超時的情況
TCPSpuriousRTOs:
    透過F-RTO機制發現的虛假超時個數
TCPLossProbes:
    Probe Timeout(PTO)導致傳送Tail Loss Probe (TLP)包的次數
TCPLossProbeRecovery:
    丟失包剛好被TLP探測包修復的次數

/* 由以下計數器可以看出,進入RTO被觸發時,TCP是可能處於多種不同狀態的 */
TCPRenoRecoveryFail: (也放到了Recovery類別)
    先進入Recovery階段,然後又RTO的次數,對端不支援SACK選項
TCPSackRecoveryFail:(也放到了Recovery類別)
    先進入Recovery階段,然後又RTO的次數,對端支援SACK選項
TCPRenoFailures:
    先進TCP_CA_Disorder階段,然後又RTO超時的次數,對端不支援SACK選項
TCPSackFailures:
    先進TCP_CA_Disorder階段,然後又RTO超時的次數,對端支援SACK選項
TCPLossFailures:
    先進TCP_CA_Loss階段,然後又RTO超時的次數

Retrans數量

這些計數器統計的重傳包,都不是由於RTO超時導致進行的重傳
如果結合RetransSegs統計來看,如果這些非RTO導致的重傳佔比較大的話,也算是不幸中的萬幸。
另外LostRetransmit的數量應該偏低比較好,重傳包如果都大量被丟棄,則真的要注意了。

TCPLostRetransmit:
    丟失的重傳SBK數量,沒有TSO時,等於丟失的重傳包數量
TCPFastRetrans:
    成功快速重傳的SKB數量
TCPForwardRetrans:
    成功ForwardRetrans的SKB數量,Forward Retrans重傳的序號高於retransmit_high的資料
    TODO: retransmit_high目前的理解是被標記為lost的SKB中,最大的end_seq值
TCPSlowStartRetrans:
    成功在Loss狀態傳送的重傳SKB數量,而且這裡僅記錄非RTO超時進入Loss狀態下的重傳數量
    目前找到的一種非RTO進入Loss狀態的情況就是:tcp_check_sack_reneging()函式發現
    接收端違反(renege)了之前的SACK資訊時,會進入Loss狀態
TCPRetransFail:
    嘗試FastRetrans、ForwardRetrans、SlowStartRetrans重傳失敗的次數

FastOpen

TCP FastOpen(TFO)技術是Google提出來減少三次握手開銷的技術,
核心原理就是在第一次建連時server計算一個cookies發給client,之後client向
server再次發起建連請求時就可以攜帶cookies資訊驗明正身。如果cookies驗證透過,
server可以不等三次握手的最後一個ACK包就將client放在SYN包裡面的資料傳遞給application layer。

在3.10核心中,TFO由sysctl_tcp_fastopen開關控制,預設值為0(關閉)。
而且sysctl_tcp_fastopen目前也是推薦關閉的,因為網路中有些middlebox會丟棄那些帶有不認識的option的SYN包.
所以正常情況下這些值也應該都是0,當然如果收到過某些不懷好意帶TFO cookies資訊的SYN包,
TCPFastOpenPassive計數器就可能不為0。

TCPFastOpenActive:
    傳送的帶TFO cookie的SYN包個數
TCPFastOpenPassive:
    收到的帶TFO cookie的SYN包個數
TCPFastOpenPassiveFail:
    使用TFO技術建連失敗的次數
TCPFastOpenListenOverflow:
    TFO請求數超過listener queue設定的上限則加1
TCPFastOpenCookieReqd:
    收到一個請求TFO cookies的SYN包時加1

MD5

TCP MD5 Signature選項是為提高BGP Session的安全性而提出的,詳見RFC 2385
因此核心中是以編譯選項,而不是sysctl介面來配置是否使用該功能的。
如果核心編譯是的CONFIG_TCP_MD5SIG選項未配置,則不會支援TCPMD5Sig,下面兩個計數器也就只能是0

TCPMD5NotFound:
    希望收到帶MD5選項的包,但是包裡面沒有MD5選項
TCPMD5Unexpected:
    不希望收到帶MD5選項的包,但是包裡面有MD5選項

DelayedACK

DelayedACK是核心中預設支援的,但即使使用DelayedACKs,每收到兩個資料包也
必須傳送一個ACK。所以DelayedACKs可以估算為傳送出去的ACK數量的一半。
同時DelayedACKLocked反應的是應用與核心爭搶socket的次數,
如果佔DelayedACKs比例過大可能就需要看看應用程式是否有問題了。

DelayedACKs:
    嘗試傳送delayed ack的次數,包括未成功傳送的次數
DelayedACKLocked:
    由於usr鎖住了sock,而無法傳送delayed ack的次數
DelayedACKLost:
    TODO 暫時不理解準確含義
TCPSchedulerFailed:
    如果在delay ack處理函式中發現prequeue還有資料,就加1。
    資料放到prequeue,就是想user能儘快處理。如果任由資料,
    則可能user行為排程效果不好
    這個值應該非常接近於零才正常

DSACK

該型別計數器統計的是收/發DSACK資訊次數。
DSACKOldSent + DSACKOfoSent可以當做是傳送出的DSACK資訊的次數,而且機率上來講
OldSent應該佔比更大。
同理DSACKRecv的數量也應該遠多於DSACKOfoRecv的數量。
另外DSACK資訊的傳送是需要sysctl_tcp_dsack開啟的,如果發現sent兩個計數器為零,則要檢查一下了。
一般還是建議開啟dsack選項

TCPDSACKOldSent:
    如果收到的重複資料包序號比rcv_nxt(接收端想收到的下一個序號)小,則增加oldsent
TCPDSACKOfoSent:
    如果收到的重複資料包序號比rcv_nxt大,則是一個亂序的重複資料包,增加ofosent
TCPDSACKRecv:
    收到的old dsack資訊次數,判斷old的方法:dsack序號小於ACK號
TCPDSACKOfoRecv:
    收到的Ofo dsack資訊次數
TCPDSACKIgnoredOld:
    當一個dsack block被判定為無效,且設定過undo_marker,則加1
TCPDSACKIgnoredNoUndo:
    當一個dsack block被判定為無效,且未設定undo_marker,則加1

Reorder

當發現了需要更新某條TCP流的reordering值(亂序值)時,以下計數器可能被使用到。
不過下面四個計數器為互斥關係,最少見的應該是TCPRenoReorder,畢竟sack已經被
廣泛部署使用了。
TODO: 什麼情況下能準確的判斷出要更新reorder值呢?

TCPTSReorder:
    如果是被一個partial ack確認後需要更新reorder值,則加1
    這個地方取個TS的名字,還真是費解。不知道是什麼的縮寫表示了partial ack的含義。
TCPRenoReorder:
    如果被不支援SACK的dupack確認後,需要更新reorder值,則加1
TCPFACKReorder:
    如果在需要更新時判斷支援FACK,則加1
TCPSACKReorder:
    如果僅支援SACK,則該計數器加1

關於partial ack的完整內容可參考RFC6582,這裡摘要定義部分

In the case of multiple packets dropped from a single window of data,
the first new information available to the sender comes when the
sender receives an acknowledgment for the retransmitted packet (that
is, the packet retransmitted when fast retransmit was first entered).
If there is a single packet drop and no reordering, then the
acknowledgment for this packet will acknowledge all of the packets
transmitted before fast retransmit was entered.  However, if there
are multiple packet drops, then the acknowledgment for the
retransmitted packet will acknowledge some but not all of the packets
transmitted before the fast retransmit.  We call this acknowledgment
a partial acknowledgment.

Recovery

該型別計數器統計的進入快速重傳階段的總次數及失敗次數,失敗次數是指先進入了
recovery階段,然後有RTO超時了。Fast Recovery沒有成功。
首先由於SACK選項已經大面積使用,RenoRecovery的次數應該遠小於SackRecovery的次數
另外fail的次數應該比例較小才比較理想

TCPRenoRecovery:
    進入Recovery階段的次數,對端不支援SACK選項
TCPSackRecovery:
    進入Recovery階段的次數,對端支援SACK選項
TCPRenoRecoveryFail: (也放到了RTO次數類別)
    先進入Recovery階段,然後又RTO的次數,對端不支援SACK選項
TCPSackRecoveryFail:(也放到了RTO次數類別)
    先進入Recovery階段,然後又RTO的次數,對端支援SACK選項

Abort

abort本身是一種很嚴重的問題,因此是否有必要關心這些計數器
後三個計數器如果不為0,則往往意味著系統發生了較為嚴重的問題,需要格外注意

TCPAbortOnClose:
    如果呼叫tcp_close()關閉socket時,recv buffer中還有資料,則加1
    此時會主動傳送一個reset包給對端
TCPAbortOnData:
    如果在FIN_WAIT_1和FIN_WAIT_2狀態下收到後續資料,或TCP_LINGER2設定小於0,則計數器加1
TCPAbortOnTimeout:
    因各種計時器(RTO/PTO/keepalive)的重傳次數超過上限,而關閉連線時,計數器加1
TCPAbortOnMemory:
    如果orphan socket數量或者tcp_memory_allocated超過上限,則加1
    一般值為0
TCPAbortOnLinger:
    tcp_close()中,因tp->linger2被設定小於0,導致FIN_WAIT_2立即切換到CLOSE狀態的次數
    一般值為0
TCPAbortFailed:
    如果在準備傳送reset時,分配SKB或者傳送SKB失敗,則加1
    一般值為0

c. 當rcv_buf不足時可能需要prune ofo queue, 這種情況就會導致PruneCalled計數器增加;
   當一般都應該透過collapse節省記憶體就可以了,並不需要真正的prune掉被SACK的資料。
   所以OfoPruned和更嚴重的RcvPruned都應該計數為0。

參考資料

TCP SNMP counters一
TCP SNMP counters二
TCP SNMP counters三
RFC 2012: SNMPv2 Management Information Base for the Transmission Control Protocol using SMIv2
TCP Fast Open: expediting web services

相關文章