linux服務(wù)器性能調(diào)優(yōu)之tcp/ip性能調(diào)優(yōu)

TCP狀態(tài)轉(zhuǎn)移圖

一、TCP狀態(tài)介紹:

在TCP/IP協(xié)議中,TCP協(xié)議提供可靠的連接服務(wù),采用三次握手建立一個連接。

第一次握手:建立連接時,客戶端發(fā)送syn包(syn=x)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);

第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=x+1),同時自己也發(fā)送一個SYN包(syn=y),即SYN+ACK包,此時服務(wù)器進(jìn)入SYN_RECV狀態(tài);

第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=y+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。

完成三次握手,客戶端與服務(wù)器開始傳送數(shù)據(jù),在上述過程中,還有一些重要的概念:

未連接隊(duì)列:在三次握手協(xié)議中,服務(wù)器維護(hù)一個未連接隊(duì)列,該隊(duì)列為每個客戶端的SYN包(syn=j)開設(shè)一個條目,該條目表明服務(wù)器已收到 SYN包,并向客戶發(fā)出確認(rèn),正在等待客戶的確認(rèn)包。這些條目所標(biāo)識的連接在服務(wù)器處于Syn_RECV狀態(tài),當(dāng)服務(wù)器收到客戶的確認(rèn)包時,刪除該條目, 服務(wù)器進(jìn)入ESTABLISHED狀態(tài)。

Backlog參數(shù):表示未連接隊(duì)列的最大容納數(shù)目。

SYN-ACK 重傳次數(shù) 服務(wù)器發(fā)送完SYN-ACK包,如果未收到客戶確認(rèn)包,服務(wù)器進(jìn)行首次重傳,等待一段時間仍未收到客戶確認(rèn)包,進(jìn)行第二次重傳,如果重傳次數(shù)超 過系統(tǒng)規(guī)定的最大重傳次數(shù),系統(tǒng)將該連接信息從半連接隊(duì)列中刪除。注意,每次重傳等待的時間不一定相同。

半連接存活時間:是指半連接隊(duì)列的條目存活的最長時間,也即服務(wù)從收到SYN包到確認(rèn)這個報文無效的最長時間,該時間值是所有重傳請求包的最長等待時間總和。有時我們也稱半連接存活時間為Timeout時間、SYN_RECV存活時間。

狀態(tài)解釋

CLOSED: 表示初始狀態(tài)。

LISTEN:

表示服務(wù)器端的某個SOCKET處于監(jiān)聽狀態(tài),可以接受連接

SYN_RCVD:

表示接受到了SYN報文,在正常情況下,這個狀態(tài)是服務(wù)器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態(tài),很短暫,基本上用 netstat你是很難看到這種狀態(tài)的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最后一個ACK報文不予發(fā)送。因此這種狀態(tài)時,當(dāng) 收到客戶端的ACK報文后,它會進(jìn)入到ESTABLISHED狀態(tài)。

SYN_SENT:

這個狀態(tài)與SYN_RCVD遙想呼應(yīng),當(dāng)客戶端SOCKET執(zhí)行CONNECT連接時,它首先發(fā)送SYN報文,因此也隨即它會進(jìn)入到了SYN_SENT狀態(tài),并等待服務(wù)端的發(fā)送三次握手中的第2個報文。SYN_SENT狀態(tài)表示客戶端已發(fā)送SYN報文。

ESTABLISHED:表示連接已經(jīng)建立

FIN_WAIT_1:

FIN_WAIT_1和FIN_WAIT_2狀態(tài)的真正含義都是表示等待對方的FIN報文。而這兩種狀態(tài)的區(qū)別是:FIN_WAIT_1狀態(tài)實(shí)際上是當(dāng) SOCKET在ESTABLISHED狀態(tài)時,它想主動關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報文,此時該SOCKET即進(jìn)入到FIN_WAIT_1狀態(tài)。而當(dāng)對 方回應(yīng)ACK報文后,則進(jìn)入到FIN_WAIT_2狀態(tài),當(dāng)然在實(shí)際的正常情況下,無論對方何種情況下,都應(yīng)該馬上回應(yīng)ACK報文,所以 FIN_WAIT_1狀態(tài)一般是比較難見到的,而FIN_WAIT_2狀態(tài)還有時常??梢杂胣etstat看到。

FIN_WAIT_2:

FIN_WAIT_2狀態(tài)下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點(diǎn)數(shù)據(jù)需要傳送給你,稍后再關(guān)閉連接。

TIME_WAIT:

表示收到了對方的FIN報文,并發(fā)送出了ACK報文,就等2MSL后即可回到CLOSED可用狀態(tài)了。如果FIN_WAIT_1狀態(tài)下,收到了對方同時帶FIN標(biāo)志和ACK標(biāo)志的報文時,可以直接進(jìn)入到TIME_WAIT狀態(tài),而無須經(jīng)過FIN_WAIT_2狀態(tài)。

CLOSING:

正常情況下,發(fā)送FIN報文后,按理來說是應(yīng)該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態(tài)表示你發(fā)送FIN 報文后,并沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什么情況下會出現(xiàn)此種情況呢?其實(shí)細(xì)想一下,也不難得出結(jié)論:那就是如果雙方幾乎 在同時close一個SOCKET的話,那么就出現(xiàn)了雙方同時發(fā)送FIN報文的情況,也即會出現(xiàn)CLOSING狀態(tài),表示雙方都正在關(guān)閉SOCKET連 接。

CLOSE_WAIT:

表示在等待關(guān)閉。怎么理解呢?當(dāng)對方close一個SOCKET后發(fā)送FIN報文給自己,你系統(tǒng)毫無疑問地會回應(yīng)一個ACK報文給對方,此時則進(jìn)入到 CLOSE_WAIT狀態(tài)。接下來呢,實(shí)際上你真正需要考慮的事情是察看你是否還有數(shù)據(jù)發(fā)送給對方,如果沒有的話,那么你也就可以 close這個SOCKET,發(fā)送FIN報文給對方,也即關(guān)閉連接。所以你在CLOSE_WAIT狀態(tài)下,需要完成的事情是等待你去關(guān)閉連接。

LAST_ACK:

被動關(guān)閉一方在發(fā)送FIN報文后,最后等待對方的ACK報文。當(dāng)收到ACK報文后,也即可以進(jìn)入到CLOSED可用狀態(tài)了。

需要C/C++ Linux服務(wù)器架構(gòu)師學(xué)習(xí)資料加qun(563998835)獲?。ㄙY料包括C/C++,Linux,golang技術(shù),Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協(xié)程,DPDK,ffmpeg等),免費(fèi)分享

二、調(diào)優(yōu):

所有的TCP/IP調(diào)優(yōu)參數(shù)都位于/proc/sys/net/目錄. 例如, 下面是最重要的一些調(diào)優(yōu)參數(shù), 后面是它們的含義:

1. /proc/sys/net/core/rmem_max — 最大的TCP數(shù)據(jù)接收緩沖

2. /proc/sys/net/core/wmem_max — 最大的TCP數(shù)據(jù)發(fā)送緩沖

3. /proc/sys/net/ipv4/tcp_timestamps — 時間戳在(請參考RFC 1323)TCP的包頭增加12個字節(jié)

4. /proc/sys/net/ipv4/tcp_sack — 有選擇的應(yīng)答

5. /proc/sys/net/ipv4/tcp_window_scaling — 支持更大的TCP窗口. 如果TCP窗口最大超過65535(64K), 必須設(shè)置該數(shù)值為1

6. rmem_default — 默認(rèn)的接收窗口大小

7. rmem_max — 接收窗口的最大大小

8. wmem_default — 默認(rèn)的發(fā)送窗口大小

9. wmem_max — 發(fā)送窗口的最大大小

net.core.rmem_default = 256960

net.core.rmem_max = 256960

net.core.wmem_default = 256960

net.core.wmem_max = 256960

net.ipv4.tcp_timestamps = 0

net.ipv4.tcp_sack =1

net.ipv4.tcp_window_scaling = 1

其他調(diào)優(yōu):

開啟SYN Cookies。當(dāng)出現(xiàn)SYN等待隊(duì)列溢出時,啟用cookies來處理,可防范少量SYN***,默認(rèn)為0,表示關(guān)閉;

net.ipv4.tcp_syncookies = 1

開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認(rèn)為0,表示關(guān)閉;

net.ipv4.tcp_tw_reuse = 1

開啟TCP連接中TIME-WAIT sockets的快速回收,默認(rèn)為0,表示關(guān)閉;

net.ipv4.tcp_tw_recycle = 1

系統(tǒng)默認(rèn)的TIMEOUT時間。

net.ipv4.tcp_fin_timeout = 5

當(dāng)keepalive起用的時候,TCP發(fā)送keepalive消息的頻度。缺省是2小時,改為20分鐘(20*60s)

net.ipv4.tcp_keepalive_time = 1200

表示用于向外連接的端口范圍。缺省情況下很?。?2768到61000,改為10000到65000

net.ipv4.ip_local_port_range = 10000 65000

SYN隊(duì)列的長度,默認(rèn)為1024,加大隊(duì)列長度為8192,可以容納更多等待連接的網(wǎng)絡(luò)連接數(shù)

net.ipv4.tcp_max_syn_backlog = 8192

系統(tǒng)同時保持TIME_WAIT的最大數(shù)量,如果超過這個數(shù)字,TIME_WAIT將立刻被清除并打印警告信息。默認(rèn)為180000,改為5000

net.ipv4.tcp_max_tw_buckets = 5000

其他調(diào)優(yōu)參數(shù)

tcp_syn_retries :INTEGER

默認(rèn)值是5

對于一個新建連接,內(nèi)核要發(fā)送多少個 SYN 連接請求才決定放棄。不應(yīng)該大于255,默認(rèn)值是5,對應(yīng)于180秒左右時間。(對于大負(fù)載而物理通信良好的網(wǎng)絡(luò)而言,這個值偏高,可修改為2.這個值僅 僅是針對對外的連接,對進(jìn)來的連接,是由tcp_retries1 決定的)

tcp_synack_retries :INTEGER

默認(rèn)值是5

對于遠(yuǎn)端的連接請求SYN,內(nèi)核會發(fā)送SYN + ACK數(shù)據(jù)報,以確認(rèn)收到上一個 SYN連接請求包。這是所謂的三次握手( threeway handshake)機(jī)制的第二個步驟。這里決定內(nèi)核在放棄連接之前所送出的 SYN+ACK 數(shù)目。不應(yīng)該大于255,默認(rèn)值是5,對應(yīng)于180秒左右時間。(可以根據(jù)上面的 tcp_syn_retries 來決定這個值)

tcp_keepalive_time :INTEGER

默認(rèn)值是7200(2小時)

當(dāng)keepalive打開的情況下,TCP發(fā)送keepalive消息的頻率。(由于目前網(wǎng)絡(luò)***等因素,造成了利用這個進(jìn)行的***很頻繁,曾經(jīng)也有cu 的朋友提到過,說如果2邊建立了連接,然后不發(fā)送任何數(shù)據(jù)或者rst/fin消息,那么持續(xù)的時間是不是就是2小時,空連接***? tcp_keepalive_time就是預(yù)防此情形的.我個人在做nat服務(wù)的時候的修改值為1800秒)

tcp_keepalive_probes:INTEGER

默認(rèn)值是9

TCP發(fā)送keepalive探測以確定該連接已經(jīng)斷開的次數(shù)。(注意:保持連接僅在SO_KEEPALIVE套接字選項(xiàng)被打開是才發(fā)送.次數(shù)默認(rèn)不需要修改,當(dāng)然根據(jù)情形也可以適當(dāng)?shù)乜s短此值.設(shè)置為5比較合適)

tcp_keepalive_intvl:INTEGER

默認(rèn)值為75

探測消息發(fā)送的頻率,乘以tcp_keepalive_probes就得到對于從開始探測以來沒有響應(yīng)的連接殺除的時間。默認(rèn)值為75秒,也就是沒有活動 的連接將在大約11分鐘以后將被丟棄。(對于普通應(yīng)用來說,這個值有一些偏大,可以根據(jù)需要改小.特別是web類服務(wù)器需要改小該值,15是個比較合適的 值)

tcp_retries1 :INTEGER

默認(rèn)值是3

放棄回應(yīng)一個TCP連接請求前﹐需要進(jìn)行多少次重試。RFC 規(guī)定最低的數(shù)值是3﹐這也是默認(rèn)值﹐根據(jù)RTO的值大約在3秒 – 8分鐘之間。(注意:這個值同時還決定進(jìn)入的syn連接)

tcp_retries2 :INTEGER

默認(rèn)值為15

在丟棄激活(已建立通訊狀況)的TCP連接之前﹐需要進(jìn)行多少次重試。默認(rèn)值為15,根據(jù)RTO的值來決定,相當(dāng)于13-30分鐘(RFC1122規(guī)定,必須大于100秒).(這個值根據(jù)目前的網(wǎng)絡(luò)設(shè)置,可以適當(dāng)?shù)馗男?我的網(wǎng)絡(luò)內(nèi)修改為了5)

tcp_orphan_retries :INTEGER

默認(rèn)值是7

在近端丟棄TCP連接之前﹐要進(jìn)行多少次重試。默認(rèn)值是7個﹐相當(dāng)于 50秒 – 16分鐘﹐視 RTO 而定。如果您的系統(tǒng)是負(fù)載很大的web服務(wù)器﹐那么也許需要降低該值﹐這類 sockets 可能會耗費(fèi)大量的資源。另外參的考 tcp_max_orphans 。(事實(shí)上做NAT的時候,降低該值也是好處顯著的,我本人的網(wǎng)絡(luò)環(huán)境中降低該值為3)

tcp_fin_timeout :INTEGER

默認(rèn)值是 60

對于本端斷開的socket連接,TCP保持在FIN-WAIT-2狀態(tài)的時間。對方可能會斷開連接或一直不結(jié)束連接或不可預(yù)料的進(jìn)程死亡。默認(rèn)值為 60 秒。過去在2.2版本的內(nèi)核中是 180 秒。您可以設(shè)置該值﹐但需要注意﹐如果您的機(jī)器為負(fù)載很重的web服務(wù)器﹐您可能要冒內(nèi)存被大量無效數(shù)據(jù)報填滿的風(fēng)險﹐FIN-WAIT-2 sockets 的危險性低于 FIN-WAIT-1 ﹐因?yàn)樗鼈冏疃嘀怀?1.5K 的內(nèi)存﹐但是它們存在時間更長。另外參考 tcp_max_orphans。(事實(shí)上做NAT的時候,降低該值也是好處顯著的,我本人的網(wǎng)絡(luò)環(huán)境中降低該值為30)

tcp_max_tw_buckets :INTEGER

默認(rèn)值是180000

系 統(tǒng)在同時所處理的最大 timewait sockets 數(shù)目。如果超過此數(shù)的話﹐time-wait socket 會被立即砍除并且顯示警告信息。之所以要設(shè)定這個限制﹐純粹為了抵御那些簡單的 DoS ***﹐千萬不要人為的降低這個限制﹐不過﹐如果網(wǎng)絡(luò)條件需要比默認(rèn)值更多﹐則可以提高它(或許還要增加內(nèi)存)。(事實(shí)上做NAT的時候最好可以適當(dāng)?shù)卦黾?該值)

tcp_tw_recycle :BOOLEAN

默認(rèn)值是0

打開快速 TIME-WAIT sockets 回收。除非得到技術(shù)專家的建議或要求﹐請不要隨意修改這個值。(做NAT的時候,建議打開它)

tcp_tw_reuse:BOOLEAN

默認(rèn)值是0

該文件表示是否允許重新應(yīng)用處于TIME-WAIT狀態(tài)的socket用于新的TCP連接(這個對快速重啟動某些服務(wù),而啟動后提示端口已經(jīng)被使用的情形非常有幫助)

tcp_max_orphans :INTEGER

缺省值是8192

系統(tǒng)所能處理不屬于任何進(jìn)程的TCP sockets最大數(shù)量。假如超過這個數(shù)量﹐那么不屬于任何進(jìn)程的連接會被立即reset,并同時顯示警告信息。之所以要設(shè)定這個限制﹐純粹為了抵御那些 簡單的 DoS ***﹐千萬不要依賴這個或是人為的降低這個限制(這個值Redhat AS版本中設(shè)置為32768,但是很多防火墻修改的時候,建議該值修改為2000)

tcp_abort_on_overflow :BOOLEAN

缺省值是0

當(dāng)守護(hù)進(jìn)程太忙而不能接受新的連接,就象對方發(fā)送reset消息,默認(rèn)值是false。這意味著當(dāng)溢出的原因是因?yàn)橐粋€偶然的猝發(fā),那么連接將恢復(fù)狀態(tài)。 只有在你確信守護(hù)進(jìn)程真的不能完成連接請求時才打開該選項(xiàng),該選項(xiàng)會影響客戶的使用。(對待已經(jīng)滿載的sendmail,apache這類服務(wù)的時候,這 個可以很快讓客戶端終止連接,可以給予服務(wù)程序處理已有連接的緩沖機(jī)會,所以很多防火墻上推薦打開它)

tcp_syncookies :BOOLEAN

默認(rèn)值是0

只有在內(nèi)核編譯時選擇了CONFIG_SYNCOOKIES時才會發(fā)生作用。當(dāng)出現(xiàn)syn等候隊(duì)列出現(xiàn)溢出時象對方發(fā)送syncookies。目的是為了防止syn flood***。

注意:該選項(xiàng)千萬不能用于那些沒有收到***的高負(fù)載服務(wù)器,如果在日志中出現(xiàn)synflood消息,但是調(diào)查發(fā)現(xiàn)沒有收到synflood***,而是合法用戶的連接負(fù)載過高的原因,你應(yīng)該調(diào)整其它參數(shù)來提高服務(wù)器性能。參考:

tcp_max_syn_backlog

tcp_synack_retries

tcp_abort_on_overflow

syncookie嚴(yán)重的違背TCP協(xié)議,不允許使用TCP擴(kuò)展,可能對某些服務(wù)導(dǎo)致嚴(yán)重的性能影響(如SMTP轉(zhuǎn)發(fā))。(注意,該實(shí)現(xiàn)與BSD上面使用 的tcp proxy一樣,是違反了RFC中關(guān)于tcp連接的三次握手實(shí)現(xiàn)的,但是對于防御syn-flood的確很有用.)

tcp_stdurg :BOOLEAN

默認(rèn)值為0

使用 TCP urg pointer 字段中的主機(jī)請求解釋功能。大部份的主機(jī)都使用老舊的 BSD解釋,因此如果您在 Linux 打開它﹐或會導(dǎo)致不能和它們正確溝通。

tcp_max_syn_backlog :INTEGER

對于那些依然還未獲得客戶端確認(rèn)的連接請求﹐需要保存在隊(duì)列中最大數(shù)目。對于超過 128Mb 內(nèi)存的系統(tǒng)﹐默認(rèn)值是 1024 ﹐低于 128Mb 的則為 128。如果服務(wù)器經(jīng)常出現(xiàn)過載﹐可以嘗試增加這個數(shù)字。警告﹗假如您將此值設(shè)為大于 1024﹐最好修改 include/net/tcp.h 里面的 TCP_SYNQ_HSIZE ﹐以保持 TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog ﹐并且編進(jìn)核心之內(nèi)。(SYN Flood***利用TCP協(xié)議散布握手的缺陷,偽造虛假源IP地址發(fā)送大量TCP-SYN半打開連接到目標(biāo)系統(tǒng),最終導(dǎo)致目標(biāo)系統(tǒng)Socket隊(duì)列資源耗 盡而無法接受新的連接。為了應(yīng)付這種***,現(xiàn)代Unix系統(tǒng)中普遍采用多連接隊(duì)列處理的方式來緩沖(而不是解決)這種***,是用一個基本隊(duì)列處理正常的完 全連接應(yīng)用(Connect()和Accept() ),是用另一個隊(duì)列單獨(dú)存放半打開連接。這種雙隊(duì)列處理方式和其他一些系統(tǒng)內(nèi)核措施(例如Syn-Cookies/Caches)聯(lián)合應(yīng)用時,能夠比較有 效的緩解小規(guī)模的SYN Flood***(事實(shí)證明<1000p/s)加大SYN隊(duì)列長度可以容納更多等待連接的網(wǎng)絡(luò)連接數(shù),所以對Server來說可以考慮增大該值.)

tcp_window_scaling :INTEGER

缺省值為1

該 文件表示設(shè)置tcp/ip會話的滑動窗口大小是否可變。參數(shù)值為布爾值,為1時表示可變,為0時表示不可變。tcp/ip通常使用的窗口最大可達(dá)到 65535 字節(jié),對于高速網(wǎng)絡(luò),該值可能太小,這時候如果啟用了該功能,可以使tcp/ip滑動窗口大小增大數(shù)個數(shù)量級,從而提高數(shù)據(jù)傳輸?shù)哪芰?RFC 1323)。(對普通地百M(fèi)網(wǎng)絡(luò)而言,關(guān)閉會降低開銷,所以如果不是高速網(wǎng)絡(luò),可以考慮設(shè)置為0)

tcp_timestamps :BOOLEAN

缺省值為1

Timestamps 用在其它一些東西中﹐可以防范那些偽造的 sequence 號碼。一條1G的寬帶線路或許會重遇到帶 out-of-line數(shù)值的舊sequence 號碼(假如它是由于上次產(chǎn)生的)。Timestamp 會讓它知道這是個 ‘舊封包’。(該文件表示是否啟用以一種比超時重發(fā)更精確的方法(RFC 1323)來啟用對 RTT 的計(jì)算;為了實(shí)現(xiàn)更好的性能應(yīng)該啟用這個選項(xiàng)。)

tcp_sack :BOOLEAN

缺省值為1

使 用 Selective ACK﹐它可以用來查找特定的遺失的數(shù)據(jù)報— 因此有助于快速恢復(fù)狀態(tài)。該文件表示是否啟用有選擇的應(yīng)答(Selective Acknowledgment),這可以通過有選擇地應(yīng)答亂序接收到的報文來提高性能(這樣可以讓發(fā)送者只發(fā)送丟失的報文段)。(對于廣域網(wǎng)通信來說這個 選項(xiàng)應(yīng)該啟用,但是這會增加對 CPU 的占用。)

tcp_fack :BOOLEAN

缺省值為1

打開FACK擁塞避免和快速重傳功能。(注意,當(dāng)tcp_sack設(shè)置為0的時候,這個值即使設(shè)置為1也無效)

tcp_dsack :BOOLEAN

缺省值為1

允許TCP發(fā)送”兩個完全相同”的SACK。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容