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