云服務器 Linux 內(nèi)核網(wǎng)絡參數(shù)介紹和常見問題處理
Linux系統(tǒng)內(nèi)核參數(shù)的查看和修改方法
通過/proc/sys/目錄
/proc/sys/目錄是Linux內(nèi)核在系統(tǒng)啟動后生成的“偽目錄”,在該目錄下會有一個名為net的文件夾,其中存放著當前系統(tǒng)中生效的所有內(nèi)核參數(shù),目錄樹結(jié)構(gòu)與參數(shù)的完整名稱相關(guān),如net.ipv4.tcp_tw_recycle,它對應的文件即是/proc/sys/net/ipv4/tcp_tw_recycle,文件的內(nèi)容就是參數(shù)值。
查看內(nèi)核參數(shù)
直接使用cat查看對應文件的內(nèi)容即可,比如要查看net.ipv4.tcp_tw_recycle的值,直接使用以下命令即可:cat /proc/sys/net/ipv4/tcp_tw_recycle
修改內(nèi)核參數(shù)
直接對內(nèi)核參數(shù)對應的文件進行修改,推薦使用echo進行修改,比如要修改net.ipv4.tcp_tw_recycle的值為“0”,直接使用以下命令即可:echo "0" > /proc/sys/net/ipv4/tcp_tw_recycle
注意:使用這種方法修改的參數(shù)值僅在本次運行中生效,系統(tǒng)重啟后就會恢復成原先的值,修改/proc/sys/net目錄的方法一般用于臨時性的驗證修改的效果,若需要永久性的修改,請使用sysctl命令或修改sysctl.conf文件的方法進行操作。
通過 sysctl.conf 文件
查看內(nèi)核參數(shù)
可以通過命令sysctl -a來查看當前系統(tǒng)中生效的所有參數(shù),命令的運行結(jié)果類似以下的輸出(部分內(nèi)容):
net.ipv4.tcp_app_win = 31
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_frto = 2
net.ipv4.tcp_frto_response = 0
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_no_metrics_save = 0
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_tso_win_divisor = 3
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_abc = 0
net.ipv4.tcp_mtu_probing = 0
net.ipv4.tcp_base_mss = 512
net.ipv4.tcp_workaround_signed_windows = 0
net.ipv4.tcp_challenge_ack_limit = 1000
net.ipv4.tcp_limit_output_bytes = 262144
net.ipv4.tcp_dma_copybreak = 4096
net.ipv4.tcp_slow_start_after_idle = 1
net.ipv4.cipso_cache_enable = 1
net.ipv4.cipso_cache_bucket_size = 10
net.ipv4.cipso_rbm_optfmt = 0
net.ipv4.cipso_rbm_strictvalid = 1
修改內(nèi)核參數(shù)
可以通過/sbin/sysctl -w kernel.domainname="example.com"來修改指定的參數(shù)值,如sysctl -w net.ipv4.tcp_tw_recycle="0"
可以直接修改/etc/sysctl.conf文件,修改將會在下次重啟時生效
NAT 哈希表滿導致服務器丟包
本節(jié)涉及到的內(nèi)核參數(shù)
net.netfilter.nf_conntrack_buckets
net.nf_conntrack_max
問題現(xiàn)象
發(fā)現(xiàn) Linux服務器出現(xiàn)間歇性丟包,連接無法建立,通過 tracert、mtr 等手段排查,外部網(wǎng)絡未見異常。
同時,如下圖所示,在系統(tǒng)日志中重復出現(xiàn)大量(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.
Feb 6 16:05:07 i-*** kernel: nf_conntrack: table full, dropping packet.
說明: ip_conntrack 是 Linux 系統(tǒng)內(nèi) NAT 的一個跟蹤連接條目的模塊。ip_conntrack 模塊會使用一個哈希表記錄 tcp 通訊協(xié)議的 established connection 記錄,當這個哈希表滿了的時候,便會導致 nf_conntrack: table full, dropping packet 錯誤。
解決思路
Linux系統(tǒng)會開辟一個空間用來維護每一個TCP鏈接,這個空間的大小與nf_conntrack_buckets、nf_conntrack_max相關(guān),后者的默認值是前者的4倍,而前者在系統(tǒng)啟動后無法修改,所以一般都是建議增大nf_conntrack_max。但系統(tǒng)維護連接是需要消耗內(nèi)存,所以請在確認系統(tǒng)空閑內(nèi)存充足的情況下調(diào)大該值,且調(diào)大的具體數(shù)值需要根據(jù)系統(tǒng)的情況而定。
time wait bucket table overflow 報錯
本節(jié)涉及到的內(nèi)核參數(shù)
net.ipv4.tcp_max_tw_buckets
問題現(xiàn)象
1、查詢服務器 /var/log/message日志,發(fā)現(xiàn)全部是類似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.
2、通過netstat -ant|grep TIME_WAIT|wc -l統(tǒng)計處于 TIME_WAIT 狀態(tài)的 TCP 連接數(shù),可以發(fā)現(xiàn)系統(tǒng)中處于TIME_WAIT狀態(tài)的TCP連接非常多(一般在上千的數(shù)量級)
解決思路
該問題和參數(shù)net.ipv4.tcp_max_tw_buckets相關(guān),該值可以調(diào)整內(nèi)核中管理TIME_WAIT狀態(tài)的數(shù)量,當實際處于TIME_WAIT及需要轉(zhuǎn)換為TIME_WAIT狀態(tài)連接數(shù)之和超過了net.ipv4.tcp_max_tw_buckets所規(guī)定的值的時候,內(nèi)核就會在message日志中打印這條錯誤信息,同時超出規(guī)定值的TCP連接會直接被關(guān)閉,而不會進入TIME_WAIT狀態(tài)。
解決該問題的方法同樣是調(diào)高這個內(nèi)核參數(shù)的值,但一味的調(diào)高可能會導致內(nèi)存額外的消耗,我們建議您可以根據(jù)實際情況適當調(diào)高,同時明確系統(tǒng)中為何會有如此多的TIME_WAIT,可以從業(yè)務層面去改進TCP連接的行為。
FIN_WAIT2 狀態(tài)的 TCP 鏈接過多
本節(jié)涉及到的內(nèi)核參數(shù)
net.ipv4.tcp_fin_timeout
問題現(xiàn)象
在TCP協(xié)議標準中,存在“半連接”的概念,F(xiàn)IN_WAIT2的狀態(tài)就是在本端主動關(guān)閉連接,但對端沒有主動關(guān)閉連接的情況下的狀態(tài),而 TCP/IP 協(xié)議棧對FIN_WAIT2狀態(tài)是沒有超時的,所以如果遠端不關(guān)閉,這個 FIN_WAIT_2 狀態(tài)將保持到系統(tǒng)重新啟動,越來越多的FIN_WAIT_2狀態(tài)會致使內(nèi)核 crash。
解決思路
因為現(xiàn)如今還使用“半連接”的應用非常少,那么長時間處于FIN_WAIT2狀態(tài)一般來說是一個非正常的現(xiàn)象,可以適當修改net.ipv4.tcp_fin_timeout參數(shù)來調(diào)整處于FIN_WAIT2狀態(tài)的TCP連接的超時時間,減少這個數(shù)值以便加快系統(tǒng)回收處于FIN_WAIT2狀態(tài)的TCP連接。
注意:由于FIN_WAIT2狀態(tài)的TCP連接會進入TIME_WAIT狀態(tài),該問題建議結(jié)合“time wait bucket table overflow 報錯”這一節(jié)一起閱讀。
出現(xiàn)大量 CLOSE_WAIT 的原因及解決方法
本節(jié)涉及到的內(nèi)核參數(shù)
暫無
問題現(xiàn)象
通過命令netstat -atn|grep CLOSE_WAIT|wc -l查看當前系統(tǒng)中處于CLOSE_WAIT狀態(tài)的TCP連接非常多。
問題原因
當遠端主動關(guān)閉連接時,TCP連接斷開時需要進行四次揮手,TCP連接的兩端都可以發(fā)起關(guān)閉連接的請求,若對端發(fā)起了關(guān)閉連接,但本地沒有進行后續(xù)的關(guān)閉連接操作,那么該鏈接就會處于CLOSE_WAIT狀態(tài)。雖然該鏈接已經(jīng)處于半開狀態(tài),但是已經(jīng)無法和對端通信,需要及時的釋放掉該鏈接。
解決思路
建議從業(yè)務層面及時判斷某個連接是否已經(jīng)被對端關(guān)閉,即在程序邏輯中對連接及時進行關(guān)閉檢查。
在編程語言中對應的讀、寫函數(shù)一般已經(jīng)包含了檢測 TCP 連接是否已經(jīng)斷開的功能,如 Java 中可以通過 read 方法來判斷,當 read 方法返回 -1 時則表示流已經(jīng)到達末尾,就可以使用 close 方法關(guān)閉該鏈接。C 語言中檢查 read 的返回值,若是 0 則可以關(guān)閉該連接,若小于 0 則查看一下 errno,若不是 AGAIN 則同樣可以關(guān)閉連接。
客戶端做了 NAT 的情況下無法訪問主機
本節(jié)涉及到的內(nèi)核參數(shù)
net.ipv4.tcp_tw_recycle
net.ipv4.tcp_timestamps
問題現(xiàn)象
本地客戶端做了NAT(包括VPC內(nèi)通過SNAT讓沒有公網(wǎng)的主機可以訪問外網(wǎng)),此時訪問其他的云產(chǎn)品會出現(xiàn)無法連接的情況,抓包的結(jié)果可以看到遠端對客戶端發(fā)送的 SYN 包沒有任何響應。
問題原因
若遠端服務器中net.ipv4.tcp_tw_recycle和net.ipv4.tcp_timestamps同時被開啟(即同時為1),那么服務器會檢查每一個報文中的時間戳(TCP協(xié)議中Timestamp這個option),若Timestamp不是遞增的關(guān)系,那么是不會響應這個報文的。而做了 NAT 后,服務器看到來自不同的客戶端的源IP都是一樣的,但 NAT 前每一臺客戶端的時間可能會有偏差,在服務器上就會看到 Timestamp 不是遞增的情況。
解決思路
分兩種情況:
1、遠端服務器為云主機
在這種情況下可以將服務器中的net.ipv4.tcp_tw_recycle置為0,只要net.ipv4.tcp_tw_recycle和net.ipv4.tcp_timestamps兩個參數(shù)不是同時置為1,那么服務器就不會去檢查 Timestamp 是否是遞增的情況了。
2、遠端服務器為虛擬主機等PaaS服務
由于虛擬主無法直接修改內(nèi)核參數(shù),那么就需要在客戶端上做修改,建議將net.ipv4.tcp_tw_recycle和net.ipv4.tcp_timestamps兩個參數(shù)都置為0,讓客戶端不要在 TCP 數(shù)據(jù)段中加入 Timestamp ,從而解決問題。
TCP 連接建立時常見的內(nèi)核參數(shù)
本節(jié)涉及到的內(nèi)核參數(shù)
net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_syncookies
net.ipv4.tcp_synack_retries
net.ipv4.tcp_abort_on_overflow
net.core.somaxconn
net.core.netdev_max_backlog
參數(shù)說明
前三個參數(shù)一般被用來抵御 SYN Flood 攻擊,建議您在充分了解參數(shù)的實際作用、業(yè)務的實際情況來調(diào)整這些參數(shù)。
net.ipv4.tcp_max_syn_backlog:這個參數(shù)決定了系統(tǒng)中處于SYN_RECV狀態(tài)的TCP連接數(shù)量,SYN_RECV狀態(tài)指的是當系統(tǒng)收到SYN后,作了SYN+ACK響應后等待對方回復三次握手階段最后一個ACK的階段。
net.ipv4.tcp_syncookies:當這個參數(shù)值被設置為1且SYN_RECV隊列滿了之后,內(nèi)核會對 SYN 包的回復做一定的修改:在響應的 SYN+ACK 包中,初始的序列號會由源IP和端口、目的IP和端口及當前時間這五個參數(shù)共同計算出一個值組成,惡意攻擊者對于linux內(nèi)核精心組裝的 TCP 包不會響應或作錯誤的響應(ACK包中確認的序列號并不是之前計算出的值),而正常的請求者會根據(jù)收到的 SYN+ACK 包做正確的響應,以便達到識別攻擊者的功能。注意:當tcp_syncookies啟用后,net.ipv4.tcp_max_syn_backlog值會被忽略。
net.ipv4.tcp_synack_retries:這個參數(shù)指明了處于SYN_RECV狀態(tài)時重傳 SYN+ACK 包的次數(shù)。
net.ipv4.tcp_abort_on_overflow:若設置為1,當系統(tǒng)在短時間內(nèi)收到了大量的請求,而相關(guān)的應用程序未能處理時,就會發(fā)送 Reset 包直接終止這些鏈接。默認值是0,在一般的情況下都建議先通過優(yōu)化應用程序的效率來提高處理能力,而不是簡單的讓內(nèi)核來 Reset 這些過多的連接。
net.core.somaxconn:這個值和net.ipv4.tcp_max_syn_backlog是有關(guān)聯(lián)的,后者指的是還在三次握手的半連接的上限,而這個值指的是處于ESTABLISHED的數(shù)量上限。若您的服務器是一個高負載的業(yè)務服務器,那么是有必要調(diào)高這個數(shù)值的。同時請注意在listen(2)函數(shù)中有一個參數(shù)backlog,這個參數(shù)同樣是指明這個監(jiān)聽的端口處于ESTABLISHED的數(shù)量上限,當backlog>net.core.somaxconn,系統(tǒng)會選擇內(nèi)核中的net.core.somaxconn參數(shù)值。
net.core.netdev_max_backlog:當內(nèi)核處理速度比網(wǎng)卡接收速度慢時,這部分多出來的包就會被保存在網(wǎng)卡的接收隊列上,而這個參數(shù)說明了這個隊列的數(shù)量上限。