虛擬網絡運維------ Linux 內核配置相關問題記錄

虛擬網絡運維------ Linux 內核配置相關問題記錄

前言

雲計算網絡方向運維時,經常會遇到各類網絡場景問題,其中受到Linux內核配置的影響是存在一定的比例的, 此類問題相對比較複雜,不易排查,這裏長期更新,將遇到的涉及Linux內核配置影響的運維問題記錄;

另外,涉及調整內核配置時,需要從實際需要出發,最好有相關數據的支撐,不建議隨意調整內核參數。需要了解參數的具體作用,且注意同類型或版本環境的內核參數可能有所不同。並做好備份,方便回滾;

Linux 內核相關官方文檔:https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

ip-sysctl.txt

內核配置的查看和修改

查看內核參數:使用 cat 查看對應文件的內容,例如執行命令 cat /proc/sys/net/ipv4/tcp_tw_recycle 查看 net.ipv4.tcp_tw_recycle 的值。

修改內核參數:使用 echo 修改內核參數對應的文件,例如執行命令 echo "0" > /proc/sys/net/ipv4/tcp_tw_recyclenet.ipv4.tcp_tw_recycle 的值修改爲 0。

  • /proc/sys/ 目錄是 Linux 內核在啓動後生成的僞目錄,其目錄下的 net 文件夾中存放了當前系統中開啓的所有內核參數、目錄樹結構與參數的完整名稱相關,如 net.ipv4.tcp_tw_recycle,它對應的文件是 /proc/sys/net/ipv4/tcp_tw_recycle,文件的內容就是參數值。
  • 修改的參數值僅在當次運行中生效,系統重啓後會回滾歷史值,一般用於臨時性的驗證修改的效果。若需要永久性修改,需要修改sysctl.conf 文件;可以使用sysctl 命令管理;

查看內核參數:執行命令 sysctl -a 查看當前系統中生效的所有參數;

修改內核參數

  1. 執行命令 /sbin/sysctl -w kernel.parameter="example" 修改參數,如sysctl -w net.ipv4.tcp_tw_recycle="0"
  2. 執行命令 vi /etc/sysctl.conf 修改 /etc/sysctl.conf 文件中的參數。
  3. 執行命令 /sbin/sysctl -p 使配置生效。

注意:調整內核參數後內核處於不穩定狀態,請酌情重啓實例。

重點內核參數配置詳述

nf_conntrack

  • net.netfilter.nf_conntrack_buckets
  • net.nf_conntrack_max

nf_conntrack(在老版本的 Linux 內核中叫 ip_conntrack)是一個內核模塊,用於跟蹤一個連接的狀態的。連接狀態跟蹤可以供其他模塊使用,最常見的兩個使用場景是 iptables 的 nat 的 state 模塊。 iptables 的 nat 通過規則來修改目的/源地址,但光修改地址不行,我們還需要能讓回來的包能路由到最初的來源主機。這就需要藉助 nf_conntrack 來找到原來那個連接的記錄纔行。而 state 模塊則是直接使用 nf_conntrack 裏記錄的連接的狀態來匹配用戶定義的相關規則。

nf_conntrack 模塊會使用一個哈希表記錄 TCP 協議 established connection 記錄,當這個哈希表滿了的時候,便會導致 nf_conntrack: table full, dropping packet 錯誤。Linux 系統會開闢一個空間用來維護每一個 TCP 鏈接,這個空間的大小與 nf_conntrack_bucketsnf_conntrack_max 相關,後者的默認值是前者的 4 倍,而前者在系統啓動後無法修改,所以一般都是建議調大 nf_conntrack_max

注意:系統維護連接比較消耗內存,請在系統空閒和內存充足的情況下調大 nf_conntrack_max,且根據系統的情況而定。

運維過程中,如果tcp連接數滿後,就會導致Linux OS 出現丟包、高時延或斷連等問題;具體表現是在/var/log/message

會打印類似:kernel: nf_conntrack: table full, dropping packet.

規避修改方案:

修改內核配置net.nf_conntrack_max將配置參數調大;或 停止iptables(或 firewalld)服務,或添加iptables 規則禁止連接跟蹤;

lsmod | grep nf
sysctl -a | grep nf_conntrack
systemctl status firewalld
# iptables 規則類似這樣
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --sport 80 -j NOTRACK

下列截圖配置項都是依賴於模塊 nf_conntrack,以及 如果iptables服務(或firewalld) 服務狀態 active (running) ,iptables 會自動拉起nf_conntrack 模塊;當stop 服務後,模塊即會停用;

tcp_max_tw_buckets

net.ipv4.tcp_max_tw_buckets

該字段的的官方說明

tcp_max_tw_buckets - INTEGER
Maximal number of timewait sockets held by system simultaneously.
If this number is exceeded time-wait socket is immediately destroyed
and warning is printed. This limit exists only to prevent
simple DoS attacks, you must not lower the limit artificially,
but rather increase it (probably, after increasing installed memory),
if network conditions require more than default value.

系統同時持有的最大timewait套接字數。如果超過此數量,則等待時間插座將立即銷燬並打印警告。此限制的存在只是爲了防止簡單的DoS攻擊,不建議人爲地降低了極限,而是增加它(可能,增加安裝的內存後),如果網絡條件需要超過默認值。

sysctl -a | grep tcp_max_tw_buckets

TIME_WAIT狀態原理
通信雙方建立TCP連接後,主動關閉連接(即在tcp四次斷開時,先發送fin報文的一方)的一方就會進入TIME_WAIT狀態。
客戶端主動關閉連接時,會發送最後一個ack後,然後會進入TIME_WAIT狀態,再停留2個MSL時間(maximum segment lifetime 最大分節生命期),進入CLOSED狀態。

如果環境中time_wait連接數超過了內核配置tcp_max_tw_buckets 配置數據數量,則不會有新的time_wait 狀態連接出現,

可能會出現兩種異常情況:
① 對端服務器發完最後一個 Fin 包,沒有收到當前服務器返回最後一個 Ack,又重發了 Fin 包,因爲新的 TimeWait 沒有辦法創建 ,這個連接在當前服務器上就消失了,對端服務器將會收到一個 Reset 包。因爲這個連接是明確要關閉的,所以收到一個 Reset 也不會有什麼大問題。(但是違反了 TCP/IP 協議)
② 因爲這個連接在當前服務器上消失,那麼剛剛釋放的端口可能被立刻使用,如果這時對端服務器沒有釋放連接,當前服務器就會收到對端服務器發來的 Reset 包。如果當前服務器是代理服務器,就可能會給用戶返回 502 錯誤。(這種異常對服務或者用戶是有影響的)

當Linux實例的time_wait 連接數大於或等於配置參數時,Linux 實例 /var/log/message 日誌全是類似 kernel: TCP: time wait bucket table overflow 的報錯信息,提示 time wait bucket table 溢出,如下:

Feb 18 12:28:38 i-*** kernel: TCP: time wait bucket table overflow
Feb 18 12:28:44 i-*** kernel: printk: 227 messages suppressed.
Feb 18 12:28:44 i-*** kernel: TCP: time wait bucket table overflow
Feb 18 12:28:52 i-*** kernel: printk: 121 messages suppressed.

通過netstat -anptu 會查看到大量的處於TIME_WAIT 狀態的鏈接,未關閉的連接;

實際運維時,遇到過TIME_WAIT狀態的連接數量過多,導致耗盡請求port數,進而無法發起新鏈接請求,出現訪問失敗的情況;(下面有案例);

原因分析

參數 net.ipv4.tcp_max_tw_buckets 可以調整內核中管理 TIME_WAIT 狀態的數量,當實例中處於 TIME_WAIT 及需要轉換爲 TIME_WAIT 狀態連接數之和超過了 net.ipv4.tcp_max_tw_buckets 參數值時,message 日誌中將報錯 time wait bucket table,同時內核關閉超出參數值的部分 TCP 連接。需要根據實際情況適當調高 net.ipv4.tcp_max_tw_buckets,同時從業務層面去改進 TCP 連接。

在 TIME_WAIT 數量等於 tcp_max_tw_buckets 時,不會有新的 TIME_WAIT 產生。

解決思路

  1. 執行命令 netstat -anp |grep tcp |wc -l 統計 TCP 連接數。
  2. 執行命令 vi /etc/sysctl.conf,查詢 net.ipv4.tcp_max_tw_buckets 參數。如果確認連接使用很高,容易超出限制。
  3. 根據實際情況調整配置參數 net.ipv4.tcp_max_tw_buckets
  4. 執行命令 sysctl -p 使配置生效。

另Linux內核中,還有兩個配置 net.ipv4.tcp_tw_recyclenet.ipv4.tcp_tw_reuse;這兩個配置項的調整需要慎重,可能會導致數據面的問題,影響轉發;

tcp_fin_timeout

net.ipv4.tcp_fin_timeout

tcp_fin_timeout - INTEGER
The length of time an orphaned (no longer referenced by any
application) connection will remain in the FIN_WAIT_2 state
before it is aborted at the local end. While a perfectly
valid “receive only” state for an un-orphaned connection, an
orphaned connection in FIN_WAIT_2 state could otherwise wait
forever for the remote to close its end of the connection.
Cf. tcp_max_orphans
Default: 60 seconds

  • HTTP 服務中,Server 由於某種原因會主動關閉連接,例如 KEEPALIVE 超時的情況下。作爲主動關閉連接的 Server 就會進入 FIN_WAIT2 狀態。
  • TCP/IP 協議棧中,存在半連接的概念,FIN_WAIT2 狀態不算做超時,如果 Client 不關閉,FIN_WAIT_2 狀態將保持到系統重啓,越來越多的 FIN_WAIT_2 狀態會致使內核 Crash。

網絡上資料有兩種說法 :

一種是:調小 net.ipv4.tcp_fin_timeout 參數,減少這個數值以便加快系統關閉處於 FIN_WAIT2 狀態的 TCP 連接;

另一種是:net.ipv4.tcp_fin_timeout這個數值其實是輸出用的,修改之後並沒有真正的讀回內核中進行使用,而內核中真正管用的是一個宏定義,在 $KERNEL/include/net/tcp.h裏面,有下面的行:#define TCP_TIMEWAIT_LEN (60*HZ)

目前這部分暫時沒有條件驗證確認;

其他內核參數配置概述

這裏將其他的配置參數簡單描述如下:

參數 描述
net.core.rmem_default 默認的TCP數據接收窗口大小(字節)。
net.core.rmem_max 最大的TCP數據接收窗口(字節)。
net.core.wmem_default 默認的TCP數據發送窗口大小(字節)。
net.core.wmem_max 最大的TCP數據發送窗口(字節)。
net.core.netdev_max_backlog 當內核處理速度比網卡接收速度慢時,這部分多出來的包就會被保存在網卡的接收隊列上,而該參數說明了這個隊列的數量上限。在每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目。
net.core.somaxconn 該參數定義了系統中每一個端口最大的監聽隊列的長度,是個全局參數。該參數和net.ipv4.tcp_max_syn_backlog有關聯,後者指的是還在三次握手的半連接的上限,該參數指的是處於ESTABLISHED的數量上限。若您的ECS實例業務負載很高,則有必要調高該參數。listen(2)函數中的參數backlog 同樣是指明監聽的端口處於ESTABLISHED的數量上限,當backlog大於net.core.somaxconn時,以net.core.somaxconn參數爲準。
net.core.optmem_max 表示每個套接字所允許的最大緩衝區的大小。
net.ipv4.tcp_mem 確定TCP棧應該如何反映內存使用,每個值的單位都是內存頁(通常是4KB)。 第一個值是內存使用的下限。 第二個值是內存壓力模式開始對緩衝區使用應用壓力的上限。 第三個值是內存使用的上限。在這個層次上可以將報文丟棄,從而減少對內存的使用。對於較大的BDP可以增大這些值(注:其單位是內存頁而不是字節)。
net.ipv4.tcp_rmem 爲自動調優定義Socket使用的內存。 第一個值是爲Socket接收緩衝區分配的最少字節數。 第二個值是默認值(該值會被rmem_default覆蓋),緩衝區在系統負載不重的情況下可以增長到這個值。 第三個值是接收緩衝區空間的最大字節數(該值會被rmem_max覆蓋)。
net.ipv4.tcp_wmem 爲自動調優定義Socket使用的內存。 第一個值是爲Socket發送緩衝區分配的最少字節數。 第二個值是默認值(該值會被wmem_default覆蓋),緩衝區在系統負載不重的情況下可以增長到這個值。 第三個值是發送緩衝區空間的最大字節數(該值會被wmem_max覆蓋)。
net.ipv4.tcp_keepalive_time TCP發送keepalive探測消息的間隔時間(秒),用於確認TCP連接是否有效。
net.ipv4.tcp_keepalive_intvl 探測消息未獲得響應時,重發該消息的間隔時間(秒)。
net.ipv4.tcp_keepalive_probes 在認定TCP連接失效之前,最多發送多少個keepalive探測消息。
net.ipv4.tcp_sack 啓用有選擇的應答(1表示啓用),通過有選擇地應答亂序接收到的報文來提高性能,讓發送者只發送丟失的報文段,(對於廣域網通信來說)這個選項應該啓用,但是會增加對CPU的佔用。
net.ipv4.tcp_fack 啓用轉發應答,可以進行有選擇應答(SACK)從而減少擁塞情況的發生,這個選項也應該啓用。
net.ipv4.tcp_timestamps TCP時間戳(會在TCP包頭增加12B),以一種比重發超時更精確的方法(參考RFC 1323)來啓用對RTT的計算,爲實現更好的性能應該啓用這個選項。
net.ipv4.tcp_window_scaling 啓用RFC 1323定義的window scaling,要支持超過64KB的TCP窗口,必須啓用該值(1表示啓用),TCP窗口最大至1GB,TCP連接雙方都啓用時才生效。
net.ipv4.tcp_syncookies 該參數表示是否打開TCP同步標籤(SYN_COOKIES),內核必須開啓並編譯CONFIG_SYN_COOKIES,SYN_COOKIES可以防止一個套接字在有過多試圖連接到達時,引起過載。默認值0表示關閉。 當該參數被設置爲1,且SYN_RECV隊列滿了之後,內核會對SYN包的回覆做一定的修改,即在響應的SYN+ACK包中,初始的序列號是由源IP+Port、目的IP+Port及時間這五個參數共同計算出一個值組成精心組裝的TCP包。由於ACK包中確認的序列號並不是之前計算出的值,惡意攻擊者無法響應或誤判,而請求者會根據收到的SYN+ACK包做正確的響應。啓用net.ipv4.tcp_syncookies後,會忽略net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_tw_reuse 表示是否允許將處於TIME-WAIT狀態的Socket(TIME-WAIT的端口)用於新的TCP連接。
net.ipv4.tcp_tw_recycle 能夠更快地回收TIME-WAIT套接字。
net.ipv4.tcp_fin_timeout 對於本端斷開的Socket連接,TCP保持在FIN-WAIT-2狀態的時間(秒)。對方可能會斷開連接或一直不結束連接或不可預料的進程死亡。
net.ipv4.ip_local_port_range 表示TCP/UDP協議允許使用的本地端口號。
net.ipv4.tcp_max_syn_backlog 該參數決定了系統中處於SYN_RECV狀態的TCP連接數量。SYN_RECV狀態指的是當系統收到SYN後,作爲SYN+ACK響應後等待對方回覆三次握手階段中的最後一個ACK的階段。對於還未獲得對方確認的連接請求,可保存在隊列中的最大數目。如果服務器經常出現過載,可以嘗試增加這個數字。默認爲1024。
net.ipv4.tcp_low_latency 允許TCP/IP棧適應在高吞吐量情況下低延時的情況,這個選項應該禁用。
net.ipv4.tcp_westwood 啓用發送者端的擁塞控制算法,它可以維護對吞吐量的評估,並試圖對帶寬的整體利用情況進行優化,對於WAN通信來說應該啓用這個選項。
net.ipv4.tcp_bic 爲快速長距離網絡啓用Binary Increase Congestion,這樣可以更好地利用以GB速度進行操作的鏈接,對於WAN通信應該啓用這個選項。
net.ipv4.tcp_max_tw_buckets 該參數設置系統的TIME_WAIT的數量,如果超過默認值則會被立即清除。默認爲180000。
net.ipv4.tcp_synack_retries 指明瞭處於SYN_RECV狀態時重傳SYN+ACK包的次數。
net.ipv4.tcp_abort_on_overflow 設置該參數爲1時,當系統在短時間內收到了大量的請求,而相關的應用程序未能處理時,就會發送Reset包直接終止這些鏈接。建議通過優化應用程序的效率來提高處理能力,而不是簡單地Reset。默認值爲0。
net.ipv4.route.max_size 內核所允許的最大路由數目。
net.ipv4.ip_forward 接口間轉發報文。
net.ipv4.ip_default_ttl 報文可以經過的最大跳數。
net.netfilter.nf_conntrack_tcp_timeout_established 在指定之間內,已經建立的連接如果沒有活動,則通過iptables進行清除。
net.netfilter.nf_conntrack_max 哈希表項最大值。

運維問題記錄

問題1:client port 耗盡無法發起請求,概率性連接失敗

問題現象

client 概率性連接db實例失敗,報錯:ERROR 2003(HY000):Can't connect to Mysql server on '192.168.192.28' (99)


報錯回顯 google 後,發現是php相關回顯,報錯代碼 99;

根據google 回顯,判斷是client 存在限制,另複測其他client 未出現該問題,server 端監控也未見異常;

原因分析

檢查client 連接數端口 netstat -anptu | wc -l

查看發現有大量time_wait狀態連接,進一步檢查client 端內核相關配置;

所以客戶端 就是在 這個 範圍 內,60999 - 32768 = 28231 滿了之後就可能會導致無法分配新的客戶端端口發起請求;

sysctl -a | grep port_range

由於大量time_wait 狀態連接佔用連接數,修改內核參數中對 time_wait 狀態連接的最大數量,釋放連接;

[root@c9c5b5d95-z7jlj /]# sysctl -a | grep tw
net.ipv4.tcp_max_tw_buckets = 524288

解決方案


規避修改後,問題規避;

後續發現是由於db中缺少一張表,程序持續發起連接重試,導致有大量短連接請求,耗盡port,觸發問題;

另此次問題client 是kubernetes pod,內核配置是pod內配置,pod跨node節點訪問db實例:

數據鏈路是pod -----> svc ----> LB ---- DB

另 kubernetes中,不能修改pod sysctl 內核配置中的tw參數,k8s 不能開 tw 參數,不能開tcp_tw_reuse 和tcp_tw_recycle,這兩個參數開了後會影響nat轉發;

另外之前也遇到過,產品轉發特性,會特定使用一些特定的端口,如果請求分配到這些端口時,就會出現請求報錯或os 丟包;

問題2:Linux OS NAT哈希表滿導致丟包(nf_conntrack)

問題現象

Linux 實例出現丟包、斷連等網絡異常現象;根據抓包等網絡排查方案,定界丟包爲該實例時;在系統日誌中重複出現大量類似以下錯誤信息。

Feb  6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
Feb  6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
Feb  6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
Feb  6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.

原因分析

ip_conntrack是Linux系統內NAT的一個跟蹤連接條目的模塊。ip_conntrack模塊會使用一個哈希表記錄TCP協議“established connection”記錄,當這個哈希表滿之後,便會導致“nf_conntrack: table full, dropping packet”錯誤。Linux系統會開闢一個空間,用於維護每一個TCP鏈接,這個空間的大小與nf_conntrack_bucketsnf_conntrack_max參數相關,後者的默認值是前者的4倍,所以一般建議調大nf_conntrack_max參數值。

說明:系統維護連接比較消耗內存,請在系統空閒和內存充足的情況下調大nf_conntrack_max參數,且根據系統的情況而定。

解決方法

修改內核配置net.nf_conntrack對應配置參數;

或 停止iptables(或 firewalld)服務,或添加iptables 規則禁止連接跟蹤;

如果選擇修改內核配置net.nf_conntrack對應配置參數,可參考如下操作:

  1. 執行以下命令,編輯系統內核配置。

    vi /etc/sysctl.conf
    
  2. 修改哈希表項最大值參數net.netfilter.nf_conntrack_max655350

  3. 修改超時參數net.netfilter.nf_conntrack_tcp_timeout_established1200,默認情況下超時時間是432000秒。

  4. 執行sysctl -p命令,使配置生效。

問題3:報“Time wait bucket table overflow”錯誤(tcp_max_tw_buckets)

此處涉及的內核參數爲net.ipv4.tcp_max_tw_buckets

問題現象

  • Linux實例的/var/log/message日誌信息全是類似kernel: TCP: time wait bucket table overflow的報錯信息,提示time wait bucket table”溢出,系統顯示類似如下。

Feb 18 12:28:38 i-*** kernel: TCP: time wait bucket table overflow
Feb 18 12:28:44 i-*** kernel: printk: 227 messages suppressed.
Feb 18 12:28:44 i-*** kernel: TCP: time wait bucket table overflow
Feb 18 12:28:52 i-*** kernel: printk: 121 messages suppressed.
Feb 18 12:28:52 i-*** kernel: TCP: time wait bucket table overflow
Feb 18 12:28:53 i-*** kernel: printk: 351 messages suppressed.
Feb 18 12:28:53 i-*** kernel: TCP: time wait bucket table overflow
Feb 18 12:28:59 i-*** kernel: printk: 319 messages suppressed.
```

  • 執行以下命令,統計處於TIME_WAIT狀態的TCP連接數,發現處於TIME_WAIT狀態的TCP連接非常多。

    netstat -ant|grep TIME_WAIT|wc -l
    

原因分析

參數net.ipv4.tcp_max_tw_buckets可以調整內核中管理TIME_WAIT狀態的數量。當實例中處於TIME_WAIT狀態,及需要轉換爲TIME_WAIT狀態的連接數之和超過net.ipv4.tcp_max_tw_buckets參數值時,message日誌中將報“time wait bucket table” 錯誤,同時內核關閉超出參數值的部分TCP連接。您需要根據實際情況適當調高net.ipv4.tcp_max_tw_buckets參數,同時從業務層面去改進TCP連接。

解決方法

  1. 執行以下命令,統計TCP連接數。

    netstat -anp |grep tcp |wc -l
    
  2. 執行以下命令,查詢net.ipv4.tcp_max_tw_buckets參數。如果確認連接使用很高,則容易超出限制。

    vi /etc/sysctl.conf
    
  3. 根據現場情況,增加net.ipv4.tcp_max_tw_buckets參數值的大小。

  4. 執行sysctl -p命令,使配置生效。

問題4:Linux實例中FIN_WAIT2狀態的TCP鏈接過多

注意:此處涉及的內核參數爲net.ipv4.tcp_fin_timeout

問題現象

FIN_WAIT2狀態的TCP鏈接過多。

原因分析

  • 在HTTP服務中,Server由於某種原因會主動關閉連接,例如KEEPALIVE超時的情況下。作爲主動關閉連接的Server就會進入FIN_WAIT2狀態。
  • 在TCP/IP協議棧中,存在半連接的概念,FIN_WAIT2狀態不算超時,如果Client不關閉,FIN_WAIT2狀態將保持到系統重啓,越來越多的FIN_WAIT2狀態會致使內核Crash。
  • 建議調小net.ipv4.tcp_fin_timeout參數的值,以便加快系統關閉處於FIN_WAIT2狀態的TCP連接。

解決方法

  1. 執行

    vi /etc/sysctl.conf
    

    命令,修改或增加以下內容。

    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_fin_timeout = 30
    net.ipv4.tcp_max_syn_backlog = 8192
    net.ipv4.tcp_max_tw_buckets = 5000
    
  2. 執行

    sysctl -p
    

    命令,使配置生效。

    注意:由於FIN_WAIT2狀態的TCP連接會進入TIME_WAIT狀態,請同時參見報“Time wait bucket table overflow”錯誤這個問題。

問題5:Linux實例中出現大量CLOSE_WAIT狀態的TCP連接

問題現象

執行以下命令,發現當前系統中處於CLOSE_WAIT狀態的TCP連接非常多。

netstat -atn|grep CLOSE_WAIT|wc -l

原因分析

根據實例上的業務量判斷CLOSE_WAIT數量是否超出了正常的範圍。TCP連接斷開時需要進行四次揮手,TCP連接的兩端都可以發起關閉連接的請求,若對端發起了關閉連接,但本地沒有關閉連接,那麼該連接就會處於CLOSE_WAIT狀態。雖然該連接已經處於半開狀態,但是已經無法和對端通信,需要及時的釋放該連接。建議從業務層面及時判斷某個連接是否已經被對端關閉,即在程序邏輯中對連接及時關閉,並進行檢查。

解決方法

編程語言中對應的讀、寫函數一般包含了檢測CLOSE_WAIT狀態的TCP連接功能,可通過執行以下命令,查看當前實例上處於CLOSE_WAIT狀態的連接數。Java語言和C語言中關閉連接的方法如下。

netstat -an|grep CLOSE_WAIT|wc -l

Java語言

  1. 通過read方法來判斷I/O 。當read方法返回-1時,則表示已經到達末尾。
  2. 通過close方法關閉該鏈接。

C語言

檢查read的返回值。

  • 若等於0,則可以關閉該連接。
  • 若小於0,則查看error,若不是AGAIN,則同樣可以關閉連接。

問題6:客戶端配置NAT後仍無法訪問ECS或RDS遠端服務器

說明:此處涉及的內核參數如下。

  • net.ipv4.tcp_tw_recycle
  • net.ipv4.tcp_timestamps

問題現象

客戶端配置NAT後無法訪問遠端ECS、RDS,包括配置了SNAT的VPC中的ECS實例。同時無法訪問其他ECS或RDS等雲產品,抓包檢測發現遠端ECS和RDS對客戶端發送的SYN包沒有響應。

原因分析

若遠端服務器的內核參數net.ipv4.tcp_tw_recyclenet.ipv4.tcp_timestamps的值都爲1,則遠端服務器會檢查每一個報文中的時間戳(Timestamp),若Timestamp不是遞增的關係,不會響應這個報文。配置NAT後,遠端服務器看到來自不同客戶端的源IP相同,但NAT前每一臺客戶端的時間可能會有偏差,報文中的Timestamp就不是遞增的情況。

解決方法

  • 遠端服務器爲ECS時,修改net.ipv4.tcp_tw_recycle參數爲0。
  • 遠端服務器爲RDS等PaaS服務時。RDS無法直接修改內核參數,需要在客戶端上修改net.ipv4.tcp_tw_recycle參數和net.ipv4.tcp_timestamps參數爲0。

問題7:存在大量處於TIME_WAIT狀態的連接

說明:此處涉及的內核參數如下。

  • net.ipv4.tcp_syncookies
  • net.ipv4.tcp_tw_reuse
  • net.ipv4.tcp_tw_recycle
  • net.ipv4.tcp_fin_timeout

問題現象

雲服務器中存在大量處於TIME_WAIT狀態的連接。

原因分析

首先通過調用close()發起主動關閉,在發送最後一個ACK之後會進入time_wait的狀態,該發送方會保持2MSL時間之後纔會回到初始狀態。MSL值是數據包在網絡中的最大生存時間。產生這種結果使得這個TCP連接在2MSL連接等待期間,定義這個連接的四元組(客戶端IP地址和端口,服務端IP地址和端口號)不能被使用。

解決方法

通過netstatss命令,可以看到大量處於TIME_WAIT狀態的連接。

  1. 執行以下命令,查看TIME_WAIT狀態的連接數量。

    netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'
    
  2. 執行以下命令,編輯系統內核配置。

    vi /etc/sysctl.conf
    

    修改或加入以下內容。

    net.ipv4.tcp_syncookies = 1 
    net.ipv4.tcp_tw_reuse = 1 
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_fin_timeout = 30
    
  3. 執行命令以下命令,使配置生效。

    /sbin/sysctl -p 
    

問題8:服務端斷開連接後客戶端仍然可以看到是建立連接的

注意:此處涉及的內核參數爲net.ipv4.tcp_fin_timeout

問題現象

服務端A與客戶端B建立了TCP連接,之後服務端A主動斷開了連接,但是在客戶端B上仍然看到連接是建立的。

原因分析

通常是由於修改了服務端默認的net.ipv4.tcp_fin_timeout內核參數所致。

解決方法

  1. 執行以下命令,修改配置,設置

    net.ipv4.tcp_fin_timeout=30
    

     vi /etc/sysctl.conf
    
  2. 執行以下命令,使配置生效。

    sysctl -p
    

問題9:無法在本地網絡環境通過SSH連接Linux實例

說明:此處涉及的內核參數如下。

  • net.ipv4.tcp_tw_recycle
  • net.ipv4.tcp_timestamps

問題現象

無法在本地網絡環境通過SSH連接Linux實例,或者訪問該Linux實例上的HTTP業務出現異常。Telnet測試會被reset。

原因分析

如果您的本地網絡是NAT共享方式上網,該問題可能是由於本地NAT環境和目標Linux相關內核參數配置不匹配導致。嘗試通過修改目標Linux實例內核參數來解決問題。

  1. 遠程連接目標Linux實例。

  2. 執行如下命令,查看當前配置。

    cat /proc/sys/net/ipv4/tcp_tw_recycle
    cat /proc/sys/net/ipv4/tcp_timestamps
    
  3. 查看上述兩個配置的值是否爲0,如果爲1,NAT環境下的請求可能會導致上述問題。

解決方法

通過如下方式將上述參數值修改爲0。

  1. 執行如下命令,修改配置文件。

    vi /etc/sysctl.conf
    
  2. 添加如下內容。

    net.ipv4.tcp_tw_recycle=0
    net.ipv4.tcp_timestamps=0
    
  3. 執行如下命令,使配置生效。

    sysctl -p 
    
  4. 重新SSH登錄實例,或者進行業務訪問測試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章