問題背景 有同事聯繫我說,在生產環境上,訪問不了我負責的common服務,然後我去檢查common服務的health endpoint, 沒問題,然後我問了下異常,timeout導致的System.OperationCanceledException。那大概率是客戶端的問題,會不會是埠耗盡,用ne ...
問題背景
有同事聯繫我說,在生產環境上,訪問不了我負責的common服務,然後我去檢查common服務的health endpoint, 沒問題,然後我問了下異常,timeout導致的System.OperationCanceledException。那大概率是客戶端的問題,會不會是埠耗盡,用netstat看下是不是有大量的埠占用,果然如此,大概如圖:
什麼是埠耗盡
埠耗盡(Port Exhaustion)是指當系統中可用的TCP/IP埠號被全部占用,而無法建立新的網路連接時產生的一種情況。例如,在進行大量的網路連接,如客戶端與伺服器之間頻繁地建立和斷開連接時,可能會發生埠耗盡。如果客戶端在短時間內打開了大量的短暫連接,並且由於TCP協議的TIME_WAIT狀態,這些埠不能立即被重用,就可能出現埠耗盡的現象。此時,新的出站連接可能會失敗,因為找不到可用的源埠號。
埠是有限的
每個TCP或UDP連接由一個四元組唯一標識:源IP地址、源埠號、目的IP地址以及目的埠號。在一個給定的源IP地址中,埠號是有限的,通常是從1024到65535(0到1023保留給系統和知名埠)。
拓展閱讀,如何查看Linux中的可用埠範圍
cat /proc/sys/net/ipv4/ip_local_port_range
什麼是TIME_WAIT狀態
在TCP/IP網路中,TIME_WAIT狀態是TCP連接結束過程的一部分。這是一個正常的狀態,發生在一個連接關閉的準備階段,此時通常是客戶端已經發送了一個FIN(結束)數據包來表示它沒有更多數據要發送,並且也已經收到了另一側(通常是伺服器)的確認。
下麵是TIME_WAIT狀態在TCP連接終止過程中的作用:
- 主動關閉:客戶端向伺服器發送一個FIN數據包,表示它已經完成數據發送。
- 伺服器接收到FIN,發送一個ACK(確認),併進入CLOSE_WAIT狀態,表示它已經確認了客戶端結束連接的請求。
- 伺服器在發送完所有剩餘的數據後,發送自己的FIN數據包。
- 客戶端接收到伺服器的FIN,發送回一個ACK,併進入TIME_WAIT狀態。
TIME_WAIT狀態會持續一個時間段,這個時間是最大報文生命周期(MSL)的兩倍,這是一個確保連接相關的所有數據包不再存在於網路中的定義期間。這個時間通常被設置為2分鐘,因此TIME_WAIT狀態的持續時間通常是4分鐘。
TIME_WAIT狀態的主要原因有:
- 確保網路上延遲的數據包被丟棄,避免可能幹擾後續新的連接。
- 允許TCP連接可靠地結束,確保FIN-ACK握手過程正確結束。
- 確保如果客戶端到伺服器的最後一個ACK丟失,客戶端仍處於TIME_WAIT狀態,這樣如果伺服器因為沒有收到ACK而重新發送FIN,客戶端可以重新發送ACK。
在高流量的伺服器中,TCP連接經常地開啟和關閉,TIME_WAIT狀態以及它的持續時間可能導致大量的套接字處於這個狀態,從而可能耗盡可用的埠。
如何解決
- 改變TIME_WAIT時間,即減少埠被占用的時間;不推薦,儘量使用預設設置
- 啟用埠重用,例如TCP埠復用(SO_REUSEADDR)選項;
- 增加可用的埠範圍。
- 保證埠儘早儘快的釋放