1. 程式人生 > >Linux 實例常用內核網絡參數介紹與常見問題處理

Linux 實例常用內核網絡參數介紹與常見問題處理

win 其他 max 重要 linux 網絡 dev ica 編程語言 次數

本文總結了常見的 Linux 內核參數及相關問題。修改內核參數前,您需要:

  • 從實際需要出發,最好有相關數據的支撐,不建議隨意調整內核參數。
  • 了解參數的具體作用,且註意同類型或版本環境的內核參數可能有所不同。
  • 備份 ECS 實例中的重要數據。參閱文檔創建快照。

查看和修改 Linux 實例內核參數

方法一、通過 /proc/sys/ 目錄

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

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

net.ipv4.tcp_tw_recycle 的值修改為 0。

註意

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

方法二、通過 sysctl.conf 文件

查看內核參數:執行命令 sysctl -a

查看當前系統中生效的所有參數,如下所示:

  1. net.ipv4.tcp_app_win = 31
  2. net.ipv4.tcp_adv_win_scale = 2
  3. net.ipv4.tcp_tw_reuse = 0
  4. net.ipv4.tcp_frto = 2
  5. net.ipv4.tcp_frto_response = 0
  6. net.ipv4.tcp_low_latency = 0
  7. net.ipv4.tcp_no_metrics_save = 0
  8. net.ipv4.tcp_moderate_rcvbuf = 1
  9. net.ipv4.tcp_tso_win_divisor = 3
  10. net.ipv4.tcp_congestion_control = cubic
  11. net.ipv4.tcp_abc = 0
  12. net.ipv4.tcp_mtu_probing = 0
  13. net.ipv4.tcp_base_mss = 512
  14. net.ipv4.tcp_workaround_signed_windows = 0
  15. net.ipv4.tcp_challenge_ack_limit = 1000
  16. net.ipv4.tcp_limit_output_bytes = 262144
  17. net.ipv4.tcp_dma_copybreak = 4096
  18. net.ipv4.tcp_slow_start_after_idle = 1
  19. net.ipv4.cipso_cache_enable = 1
  20. net.ipv4.cipso_cache_bucket_size = 10
  21. net.ipv4.cipso_rbm_optfmt = 0
  22. net.ipv4.cipso_rbm_strictvalid = 1

修改內核參數

  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 使配置生效。

註意:調整內核參數後內核處於不穩定狀態,請務必重啟實例。

Linux 網絡相關內核參數引發的常見問題及處理

Linux 實例 NAT 哈希表滿導致 ECS 實例丟包

此處涉及的內核參數:

  • net.netfilter.nf_conntrack_buckets
  • net.nf_conntrack_max

問題現象

ECS Linux 實例出現間歇性丟包,無法連接實例,通過 tracert、mtr 等工具排查,外部網絡未見異常。同時,如下圖所示,在系統日誌中重復出現大量(table full, dropping packet.)錯誤信息。

  1. Feb 6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
  2. Feb 6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
  3. Feb 6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
  4. 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,且根據系統的情況而定。

解決思路

  1. 使用管理終端登錄實例。
  2. 執行命令 # vi /etc/sysctl.conf 編輯系統內核配置。
  3. 修改哈希表項最大值參數:net.netfilter.nf_conntrack_max = 655350
  4. 修改超時參數:net.netfilter.nf_conntrack_tcp_timeout_established = 1200,默認情況下 timeout 是 432000(秒)。
  5. 執行命令 # sysctl -p 使配置生效。

Time wait bucket table overflow 報錯

此處涉及的內核參數:

  • net.ipv4.tcp_max_tw_buckets

問題現象

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

  1. Feb 18 12:28:38 i-*** kernel: TCP: time wait bucket table overflow
  2. Feb 18 12:28:44 i-*** kernel: printk: 227 messages suppressed.
  3. Feb 18 12:28:44 i-*** kernel: TCP: time wait bucket table overflow
  4. Feb 18 12:28:52 i-*** kernel: printk: 121 messages suppressed.
  5. Feb 18 12:28:52 i-*** kernel: TCP: time wait bucket table overflow
  6. Feb 18 12:28:53 i-*** kernel: printk: 351 messages suppressed.
  7. Feb 18 12:28:53 i-*** kernel: TCP: time wait bucket table overflow
  8. Feb 18 12:28:59 i-*** kernel: printk: 319 messages suppressed.

執行命令 netstat -ant|grep TIME_WAIT|wc -l 統計處於 TIME_WAIT 狀態的 TCP 連接數,發現處於 TIME_WAIT 狀態的 TCP 連接非常多。

原因分析

參數 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. 執行命令 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 實例中 FIN_WAIT2 狀態的 TCP 鏈接過多

此處涉及的內核參數:

  • net.ipv4.tcp_fin_timeout

問題現象

FIN_WAIT2 狀態的 TCP 鏈接過多。

原因分析

  • 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 連接。

解決思路

  1. 執行命令 vi /etc/sysctl.conf,修改或加入以下內容:

    1. net.ipv4.tcp_syncookies = 1
    2. net.ipv4.tcp_fin_timeout = 30
    3. net.ipv4.tcp_max_syn_backlog = 8192
    4. net.ipv4.tcp_max_tw_buckets = 5000
  2. 執行命令 # sysctl -p 使配置生效。

    註意:由於 FIN_WAIT2 狀態的 TCP 連接會進入 TIME_WAIT 狀態,請同時參閱 time wait bucket table overflow 報錯。

Linux 實例中出現大量 CLOSE_WAIT 狀態的 TCP 連接

問題現象

執行命令 netstat -atn|grep CLOSE_WAIT|wc -l 發現當前系統中處於 CLOSE_WAIT 狀態的 TCP 連接非常多。

原因分析

關閉 TCP 連接時,TCP 連接的兩端都可以發起關閉連接的請求,若對端發起了關閉連接,但本地沒有關閉連接,那麽該連接就會處於 CLOSE_WAIT 狀態。雖然該連接已經處於半開狀態,但是已經無法和對端通信,需要及時的釋放掉該鏈接。建議從業務層面及時判斷某個連接是否已經被對端關閉,即在程序邏輯中對連接及時關閉檢查。

解決思路

編程語言中對應的讀、寫函數一般包含了檢測 CLOSE_WAIT TCP 連接功能,例如:

Java 語言

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

C 語言

  1. 檢查 read 的返回值。
    • 若等於 0 則可以關閉該連接。
    • 若小於 0 則查看 errno,若不是 AGAIN 則同樣可以關閉連接。

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

此處涉及的內核參數:

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

問題現象

客戶端配置 NAT 後無法訪問遠端 ECS、RDS,包括配置了 SNAT 的 VPC ECS 。同時無法訪問連接其他 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_recyclenet.ipv4.tcp_timestamps 為 0。

文檔涉及的 Linux 內核參數說明

參數說明
net.ipv4.tcp_max_syn_backlog 該參數決定了系統中處於 SYN_RECV 狀態的 TCP 連接數量。SYN_RECV 狀態指的是當系統收到 SYN 後,作了 SYN+ACK 響應後等待對方回復三次握手階段中的最後一個 ACK 的階段。
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_synack_retries 該參數指明了處於 SYN_RECV 狀態時重傳 SYN+ACK 包的次數。
net.ipv4.tcp_abort_on_overflow 設置該參數為 1 時,當系統在短時間內收到了大量的請求,而相關的應用程序未能處理時,就會發送 Reset 包直接終止這些鏈接。建議通過優化應用程序的效率來提高處理能力,而不是簡單地 Reset。
默認值: 0。
net.core.somaxconn 該參數定義了系統中每一個端口最大的監聽隊列的長度,是個全局參數。該參數和 net.ipv4.tcp_max_syn_backlog 有關聯,後者指的是還在三次握手的半連接的上限,該參數指的是處於 ESTABLISHED 的數量上限。若您的 ECS 實例業務負載很高,則有必要調高該參數。listen(2) 函數中的參數 backlog 同樣是指明監聽的端口處於 ESTABLISHED 的數量上限,當 backlog 大於 net.core.somaxconn時,以 net.core.somaxconn 參數為準。
net.core.netdev_max_backlog 當內核處理速度比網卡接收速度慢時,這部分多出來的包就會被保存在網卡的接收隊列上,而該參數說明了這個隊列的數量上限。

參考鏈接

  1. Linux man-pages
  2. kernel/git/torvalds/linux.git_proc
  3. kernel/git/torvalds/linux.git_proc_net_tcp
  4. kernel/git/torvalds/linux.git_ip-sysctl
  5. kernel/git/torvalds/linux.git_netfilter-sysctl
  6. kernel/git/torvalds/linux.git_nf_conntrack-sysctl

Linux 實例常用內核網絡參數介紹與常見問題處理