0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

開發(fā)或者運(yùn)維中的性能優(yōu)化建議

Linux閱碼場 ? 來源:Linux閱碼場 ? 作者:Linux閱碼場 ? 2022-06-13 11:37 ? 次閱讀

寫到這里,本書已經(jīng)快接近尾聲了。在本書前面幾章的內(nèi)容里,我們深入地討論了很多內(nèi)核網(wǎng)絡(luò)模塊相關(guān)的問題。正和庖丁一樣,從今日往后我們看到的也不再是整個(gè)的 Linux (整頭牛)了,而是內(nèi)核的內(nèi)部各個(gè)模塊(筋?肌理)。我們也理解了內(nèi)核各個(gè)模塊是如何有機(jī)協(xié)作來幫我們完成任務(wù)的。

那么具備了這些深刻的理解之后,我們?cè)谛阅芊矫嬗心男﹥?yōu)化手段可用呢?我在本章中給出一些開發(fā)或者運(yùn)維中的性能優(yōu)化建議。注意,我用的字眼是建議,而不是原則之類的。每一種性能優(yōu)化方法都有它適用或者不適用的應(yīng)用場景。你應(yīng)當(dāng)根據(jù)你當(dāng)前的項(xiàng)目現(xiàn)狀靈活來選擇用或者不用。

1 網(wǎng)絡(luò)請(qǐng)求優(yōu)化

建議1:盡量減少不必要的網(wǎng)絡(luò) IO

我要給出的第一個(gè)建議就是不必要用網(wǎng)絡(luò) IO 的盡量不用。

是的,網(wǎng)絡(luò)在現(xiàn)代的互聯(lián)網(wǎng)世界里承載了很重要的角色。用戶通過網(wǎng)絡(luò)請(qǐng)求線上服務(wù)、服務(wù)器通過網(wǎng)絡(luò)讀取數(shù)據(jù)庫中數(shù)據(jù),通過網(wǎng)絡(luò)構(gòu)建能力無比強(qiáng)大分布式系統(tǒng)。網(wǎng)絡(luò)很好,能降低模塊的開發(fā)難度,也能用它搭建出更強(qiáng)大的系統(tǒng)。但是這不是你濫用它的理由!

我曾經(jīng)見過有的同學(xué)在自己開發(fā)的接口里要請(qǐng)求幾個(gè)第三方的服務(wù)。這些服務(wù)提供了一個(gè) C 或者 Java 語言的SDK,說是 SDK 其實(shí)就是簡單的一次 UPD 或者 TCP 請(qǐng)求的封裝而已。這個(gè)同學(xué)呢,不熟悉 C 和 Java 語言的代碼,為了省事就直接在本機(jī)上把這些 SDK 部署上來,然后自己再通過本機(jī)網(wǎng)絡(luò) IO 調(diào)用這些 SDK。我們接手這個(gè)項(xiàng)目以后,分析了一下這幾個(gè) SDK 的實(shí)現(xiàn),其實(shí)調(diào)用和協(xié)議解析都很簡單。我們?cè)谧约旱姆?wù)進(jìn)程里實(shí)現(xiàn)了一遍,干掉了這些本機(jī)網(wǎng)絡(luò) IO 。效果是該項(xiàng)目 CPU 整體核數(shù)削減了 20 % +。另外除了性能以外,項(xiàng)目的部署難度,可維護(hù)性也都得到了極大的提升。

原因我們?cè)诒緯?5 章的內(nèi)容里說過,即使是本機(jī)網(wǎng)絡(luò) IO 開銷仍然是很大的。先說發(fā)送一個(gè)網(wǎng)絡(luò)包,首先得從用戶態(tài)切換到內(nèi)核態(tài),花費(fèi)一次系統(tǒng)調(diào)用的開銷。進(jìn)入到內(nèi)核以后,又得經(jīng)過冗長的協(xié)議棧,這會(huì)花費(fèi)不少的 CPU周期,最后進(jìn)入環(huán)回設(shè)備的“驅(qū)動(dòng)程序”。接收端呢,軟中斷花費(fèi)不少的 CPU 周期又得經(jīng)過接收協(xié)議棧的處理,最后喚醒或者通知用戶進(jìn)程來處理。當(dāng)服務(wù)端處理完以后,還得把結(jié)果再發(fā)過來。又得來這么一遍,最后你的進(jìn)程才能收到結(jié)果。你說麻煩不麻煩。另外還有個(gè)問題就是多個(gè)進(jìn)程協(xié)作來完成一項(xiàng)工作就必然會(huì)引入更多的進(jìn)程上下文切

換開銷,這些開銷從開發(fā)視角來看,做的其實(shí)都是無用功。

上面我們還分析的只是本機(jī)網(wǎng)絡(luò) IO,如果是跨機(jī)器的還得會(huì)有雙方網(wǎng)卡的 DMA 拷貝過程,以及兩端之間的網(wǎng)絡(luò)RTT 耗時(shí)延遲。所以,網(wǎng)絡(luò)雖好,但也不能隨意濫用!

建議2:盡量合并網(wǎng)絡(luò)請(qǐng)求

在可能的情況下,盡可能地把多次的網(wǎng)絡(luò)請(qǐng)求合并到一次,這樣既節(jié)約了雙端的 CPU 開銷,也能降低多次 RTT 導(dǎo)致的耗時(shí)。

我們舉個(gè)實(shí)踐中的例子可能更好理解。假如有一個(gè) redis,里面存了每一個(gè) App 的信息(應(yīng)用名、包名、版本、截圖等等)。你現(xiàn)在需要根據(jù)用戶安裝應(yīng)用列表來查詢數(shù)據(jù)庫中有哪些應(yīng)用比用戶的版本更新,如果有則提醒用戶更新。

那么最好不要寫出如下的代碼:

get(包名)...}

上面這段代碼功能上實(shí)現(xiàn)上沒問題,問題在于性能。據(jù)我們統(tǒng)計(jì)現(xiàn)代用戶平均安裝 App 的數(shù)量在 60 個(gè)左右。那這段代碼在運(yùn)行的時(shí)候,每當(dāng)用戶來請(qǐng)求一次,你的服務(wù)器就需要和 redis 進(jìn)行 60 次網(wǎng)絡(luò)請(qǐng)求??偤臅r(shí)最少是 60個(gè) RTT 起。更好的方法是應(yīng)該使用 redis 中提供的批量獲取命令,如 hmget、pipeline等,經(jīng)過一次網(wǎng)絡(luò) IO 就獲取到所有想要的數(shù)據(jù),如圖 1.1。

b642359c-e633-11ec-ba43-dac502259ad0.png

圖1.1 網(wǎng)絡(luò)請(qǐng)求合并

建議3:調(diào)用者與被調(diào)用機(jī)器盡可能部署的近一些

在前面的章節(jié)中我們看到在握手一切正常的情況下, TCP 握手的時(shí)間基本取決于兩臺(tái)機(jī)器之間的 RTT 耗時(shí)。雖然我們沒辦法徹底去掉這個(gè)耗時(shí),但是我們卻有辦法把 RTT 降低,那就是把客戶端和服務(wù)器放的足夠地近一些。盡量把每個(gè)機(jī)房內(nèi)部的數(shù)據(jù)請(qǐng)求都在本地機(jī)房解決,減少跨地網(wǎng)絡(luò)傳輸。

舉例,假如你的服務(wù)是部署在北京機(jī)房的,你調(diào)用的 mysql、redis最好都位于北京機(jī)房內(nèi)部。盡量不要跨過千里萬里跑到廣東機(jī)房去請(qǐng)求數(shù)據(jù),即使你有專線,耗時(shí)也會(huì)大大增加!在機(jī)房內(nèi)部的服務(wù)器之間的 RTT 延遲大概只有零點(diǎn)幾毫秒,同地區(qū)的不同機(jī)房之間大約是 1 ms 多一些。但如果從北京跨到廣東的話,延遲將是 30 - 40 ms 左右,幾十倍的上漲!

建議4:內(nèi)網(wǎng)調(diào)用不要用外網(wǎng)域名

假如說你所在負(fù)責(zé)的服務(wù)需要調(diào)用兄弟部門的一個(gè)搜索接口,假設(shè)接口是:"http://www.sogou.com/wq?key=開發(fā)內(nèi)功修煉"。

那既然是兄弟部門,那很可能這個(gè)接口和你的服務(wù)是部署在一個(gè)機(jī)房的。即使沒有部署在一個(gè)機(jī)房,一般也是有專線可達(dá)的。所以不要直接請(qǐng)求 www.sogou.com, 而是應(yīng)該使用該服務(wù)在公司對(duì)應(yīng)的內(nèi)網(wǎng)域名。在我們公司內(nèi)部,每一個(gè)外網(wǎng)服務(wù)都會(huì)配置一個(gè)對(duì)應(yīng)的內(nèi)網(wǎng)域名,我相信你們公司也有。

為什么要這么做,原因有以下幾點(diǎn)

1)外網(wǎng)接口慢。本來內(nèi)網(wǎng)可能過個(gè)交換機(jī)就能達(dá)到兄弟部門的機(jī)器,非得上外網(wǎng)兜一圈再回來,時(shí)間上肯定會(huì)慢。

2)帶寬成本高。在互聯(lián)網(wǎng)服務(wù)里,除了機(jī)器以外,另外一塊很大的成本就是 IDC 機(jī)房的出入口帶寬成本。兩臺(tái)機(jī)器在內(nèi)網(wǎng)不管如何通信都不涉及到帶寬的計(jì)算。但是一旦你去外網(wǎng)兜了一圈回來,行了,一進(jìn)一出全部要繳帶寬費(fèi),你說虧不虧??!

3)NAT 單點(diǎn)瓶頸。一般的服務(wù)器都沒有外網(wǎng) IP,所以要想請(qǐng)求外網(wǎng)的資源,必須要經(jīng)過 NAT 服務(wù)器。但是一個(gè)公司的機(jī)房里幾千臺(tái)服務(wù)器中,承擔(dān) NAT 角色的可能就那么幾臺(tái)。它很容易成為瓶頸。我們的業(yè)務(wù)就遇到過好幾次 NAT 故障導(dǎo)致外網(wǎng)請(qǐng)求失敗的情形。NAT 機(jī)器掛了,你的服務(wù)可能也就掛了,故障率大大增加。

2 接收過程優(yōu)化

建議1:調(diào)整網(wǎng)卡 RingBuffer 大小

當(dāng)網(wǎng)線中的數(shù)據(jù)幀到達(dá)網(wǎng)卡后,第一站就是 RingBu??er。網(wǎng)卡在 RingBuffer 中尋找可用的內(nèi)存位置,找到后 DMA引擎會(huì)把數(shù)據(jù) DMA 到 RingBuffer 內(nèi)存里。因此我們第一個(gè)要監(jiān)控和調(diào)優(yōu)的就是網(wǎng)卡的 RingBuffer,我們使用ethtool 來來查看一下 Ringbuffer 的大小。

#ethtool-geth0Ringparametersforeth0:Pre-setmaximums:RX:4096RXMini:0RXJumbo:0TX:4096Currenthardwaresettings:RX:512RXMini:0RXJumbo:0TX: 512

這里看到我手頭的網(wǎng)卡設(shè)置 RingBuffer 最大允許設(shè)置到 4096 ,目前的實(shí)際設(shè)置是 512。

這里有一個(gè)小細(xì)節(jié),ethtool查看到的是實(shí)際是Rx bd的大小。Rx bd位于網(wǎng)卡中,相當(dāng)于一個(gè)指針。

RingBu??er在內(nèi)存中,Rx bd指向RingBuffer。Rx bd和RingBuffer中的元素是一一對(duì)應(yīng)的關(guān)系。在網(wǎng)卡啟

動(dòng)的時(shí)候,內(nèi)核會(huì)為網(wǎng)卡的Rx bd在內(nèi)存中分配RingBu??er,并設(shè)置好對(duì)應(yīng)關(guān)系。

在 Linux 的整個(gè)網(wǎng)絡(luò)棧中,RingBuffer 起到一個(gè)任務(wù)的收發(fā)中轉(zhuǎn)站的角色。對(duì)于接收過程來講,網(wǎng)卡負(fù)責(zé)往RingBuffer 中寫入收到的數(shù)據(jù)幀,ksoftirqd 內(nèi)核線程負(fù)責(zé)從中取走處理。只要 ksoftirqd 線程工作的足夠快,RingBuffer 這個(gè)中轉(zhuǎn)站就不會(huì)出現(xiàn)問題。但是我們?cè)O(shè)想一下,假如某一時(shí)刻,瞬間來了特別多的包,而 ksoftirqd處理不過來了,會(huì)發(fā)生什么?這時(shí) RingBuffer 可能瞬間就被填滿了,后面再來的包網(wǎng)卡直接就會(huì)丟棄,不做任何處理!

b66a7ef8-e633-11ec-ba43-dac502259ad0.png

圖2.1RingBuffer 溢出

那我們?cè)趺礃幽芸匆幌?,我們的服?wù)器上是否有因?yàn)檫@個(gè)原因?qū)е碌膩G包呢?前面我們介紹的四個(gè)工具都可以查看

這個(gè)丟包統(tǒng)計(jì),拿 ethtool 來舉例:

#ethtool-Seth0......rx_fifo_errors:0tx_fifo_errors: 0

rx_fifo_errors 如果不為 0 的話(在 ifconfig 中體現(xiàn)為 overruns 指標(biāo)增長),就表示有包因?yàn)?RingBuffer 裝不下而被丟棄了。那么怎么解決這個(gè)問題呢?很自然首先我們想到的是,加大 RingBuffer 這個(gè)“中轉(zhuǎn)倉庫”的大小,如圖2.2通過 ethtool 就可以修改。

# ethtool -G eth1 rx 4096 tx 4096

b68fced8-e633-11ec-ba43-dac502259ad0.png

圖2.2RingBuffer 擴(kuò)容

這樣網(wǎng)卡會(huì)被分配更大一點(diǎn)的”中轉(zhuǎn)站“,可以解決偶發(fā)的瞬時(shí)的丟包。不過這種方法有個(gè)小副作用,那就是排隊(duì)的包過多會(huì)增加處理網(wǎng)絡(luò)包的延時(shí)。所以應(yīng)該讓內(nèi)核處理網(wǎng)絡(luò)包的速度更快一些更好,而不是讓網(wǎng)絡(luò)包傻傻地在RingBuffer 中排隊(duì)。我們后面會(huì)再介紹到 RSS ,它可以讓更多的核來參與網(wǎng)絡(luò)包接收。

建議2:多隊(duì)列網(wǎng)卡 RSS 調(diào)優(yōu)

硬中斷的情況可以通過內(nèi)核提供的偽文件 /proc/interrupts 來進(jìn)行查看。拿飛哥手頭的一臺(tái)虛機(jī)來舉例:

b6a5632e-e633-11ec-ba43-dac502259ad0.png

上述結(jié)果是我手頭的一臺(tái)虛機(jī)的輸出結(jié)果。上面包含了非常豐富的信息。網(wǎng)卡的輸入隊(duì)列 virtio1-input.0 的中斷號(hào)是 27,總的中斷次數(shù)是 1109986815,并且 27 號(hào)中斷都是由 CPU3 來處理的。

那么為什么這個(gè)輸入隊(duì)列的中斷都在 CPU3 上呢?這是因?yàn)閮?nèi)核的一個(gè)中斷親和性配置,在我機(jī)器的偽文件系統(tǒng)中可以查看到。

#cat/proc/irq/27/smp_affinity8

smp_affinity 里是CPU的親和性的綁定,8 是二進(jìn)制的 1000, 第4位為 1。代表的就是當(dāng)前的第 27 號(hào)中斷的都由第 4 個(gè) CPU 核心 - CPU3 來處理。

現(xiàn)在的主流網(wǎng)卡基本上都是支持多隊(duì)列的。通過 ethtool 工具可以查看網(wǎng)卡的隊(duì)列情況。

#ethtool-leth0Channelparametersforeth0:Pre-setmaximums:RX:0TX:0Other:1Combined:63Currenthardwaresettings:RX:0TX:0Other:1Combined: 8

上述結(jié)果表示當(dāng)前網(wǎng)卡支持的最大隊(duì)列數(shù)是 63 ,當(dāng)前開啟的隊(duì)列數(shù)是 8 。這樣當(dāng)有數(shù)據(jù)到達(dá)的時(shí)候,可以將接收進(jìn)來的包分散到多個(gè)隊(duì)列里。另外每一個(gè)隊(duì)列都有自己的中斷號(hào)。比如我手頭另外一臺(tái)多隊(duì)列的機(jī)器上看到結(jié)果(為了方便展示我刪除了部分不相關(guān)內(nèi)容):

b6eba168-e633-11ec-ba43-dac502259ad0.png

這臺(tái)機(jī)器上 virtio 這塊虛擬網(wǎng)卡上有四個(gè)輸入隊(duì)列,其硬中斷號(hào)分別是 27、29、31 和 33。有獨(dú)立的中斷號(hào)就可以獨(dú)立向某個(gè) CPU 核心發(fā)起硬中斷請(qǐng)求,讓對(duì)應(yīng) CPU 來 poll 包。中斷和 CPU 的對(duì)應(yīng)關(guān)系還是通過 cat/proc/irq/{中斷號(hào)}/smp_affinity 來查看。通過將不同隊(duì)列的 CPU 親和性打散到多個(gè) CPU 核上,就可以讓多核同時(shí)并行處理接收到的包了。這個(gè)特性叫做 RSS(Receive Side Scaling,接收端擴(kuò)展),如圖 2.3。這是加快 Linux內(nèi)核處理網(wǎng)絡(luò)包的速度非常有用的一個(gè)優(yōu)化手段。

b712dba2-e633-11ec-ba43-dac502259ad0.png

圖2.3多隊(duì)列網(wǎng)卡

在網(wǎng)卡支持多隊(duì)列的服務(wù)器上,想提高內(nèi)核收包的能力,直接簡單加大隊(duì)列數(shù)就可以了,這比加大 RingBuffer 更為有用。因?yàn)榧哟?RingBuffer 只是給個(gè)更大的空間讓網(wǎng)絡(luò)幀能繼續(xù)排隊(duì),而加大隊(duì)列數(shù)則能讓包更早地被內(nèi)核處理。ethtool 修改隊(duì)列數(shù)量方法如下:

#ethtool -L eth0 combined 32

不過在一般情況下,由一個(gè)叫隊(duì)列中斷號(hào)和 CPU 之間的親和性并不需要手工維護(hù),有一個(gè) irqbalance的服務(wù)來自動(dòng)管理。通過 ps 命令可以查看到這個(gè)進(jìn)程。

#ps-ef|grepirqbroot 29805 1 0 18:57 ? 0000 /usr/sbin/irqbalance --foreground

Irqbalance 會(huì)根據(jù)系統(tǒng)中斷負(fù)載的情況,自動(dòng)維護(hù)和遷移各個(gè)中斷的 CPU 親和性,以保持各個(gè) CPU 之間的中斷開銷均衡。如果有必要,irqbalance 也會(huì)自動(dòng)把中斷從一個(gè) CPU 遷移到另一個(gè) CPU 上。如果確實(shí)想自己維護(hù)親和性,那得先關(guān)掉 irqbalance,然后再修改中斷號(hào)對(duì)應(yīng)的 smp_affinity。

#serviceirqbalancestop# echo 2 > /proc/irq/30/smp_affinity

建議3:硬中斷合并

在第 1 章中我們看到,當(dāng)網(wǎng)絡(luò)包接收到 RingBuffer 后,接下來通過硬中斷通知 CPU。那么你覺得從整體效率上來講,是有包到達(dá)就發(fā)起中斷好呢,還是攢一些數(shù)據(jù)包再通知 CPU 更好。

先允許我來引用一個(gè)實(shí)際工作中的例子,假如你是一位開發(fā)同學(xué),和你對(duì)口的產(chǎn)品經(jīng)理一天有10 個(gè)小需求需要讓你幫忙來處理。她對(duì)你有兩種中斷方式:

第一種:產(chǎn)品經(jīng)理想到一個(gè)需求,就過來找你,和你描述需求細(xì)節(jié),然后讓你幫你來改。

第二種:產(chǎn)品經(jīng)理想到需求后,不來打擾你,等攢夠 5 個(gè)來找你一次,你集中處理。

我們現(xiàn)在不考慮及時(shí)性,只考慮你的工作整體效率,你覺得那種方案下你的工作效率會(huì)高呢?或者換句話說,你更喜歡哪一種工作狀態(tài)呢?只要你真的有過工作經(jīng)驗(yàn),一定都會(huì)覺得第二種方案更好。對(duì)人腦來講,頻繁的中斷會(huì)打亂你的計(jì)劃,你腦子里剛才剛想到一半技術(shù)方案可能也就廢了。當(dāng)產(chǎn)品經(jīng)理走了以后,你再想撿起來剛被中斷之的工作的時(shí)候,很可能得花點(diǎn)時(shí)間回憶一會(huì)兒才能繼續(xù)工作。

對(duì)于CPU來講也是一樣,CPU要做一件新的事情之前,要加載該進(jìn)程的地址空間,load進(jìn)程代碼,讀取進(jìn)程數(shù)據(jù),各級(jí)別 cache 要慢慢熱身。因此如果能適當(dāng)降低中斷的頻率,多攢幾個(gè)包一起發(fā)出中斷,對(duì)提升 CPU 的整體工作效率是有幫助的。所以,網(wǎng)卡允許我們對(duì)硬中斷進(jìn)行合并。

現(xiàn)在我們來看一下網(wǎng)卡的硬中斷合并配置。

#ethtool-ceth0Coalesceparametersforeth0:AdaptiveRX:offTX:off......rx-usecs:1rx-frames:0rx-usecs-irq:0rx-frames-irq:0......

我們來說一下上述結(jié)果的大致含義

Adaptive RX::自適應(yīng)中斷合并,網(wǎng)卡驅(qū)動(dòng)自己判斷啥時(shí)候該合并啥時(shí)候不合并

rx-usecs:當(dāng)過這么長時(shí)間過后,一個(gè) RX interrupt 就會(huì)被產(chǎn)生

rx-frames:當(dāng)累計(jì)接收到這么多個(gè)幀后,一個(gè) RX interrupt 就會(huì)被產(chǎn)生

如果你想好了修改其中的某一個(gè)參數(shù)了的話,直接使用 ethtool -C 就可以,例如:

# ethtool -C eth0 adaptive-rx on

不過需要注意的是,減少中斷數(shù)量雖然能使得 Linux 整體網(wǎng)絡(luò)包吞吐更高,不過一些包的延遲也會(huì)增大,所以用的時(shí)候得適當(dāng)注意。

建議4:軟中斷 budget 調(diào)整

再舉個(gè)日常工作相關(guān)的例子,不知道你有沒有聽說過番茄工作法這種高效工作方法。它的大致意思就是你在工作的時(shí)候,要有一整段的不被打擾的時(shí)間,集中精力處理某一項(xiàng)工作。這一整段時(shí)間時(shí)長被建議是 25 分鐘。對(duì)于我們的Linux的處理軟中斷的 ksoftirqd 來說,它也和番茄工作法思路類似。一旦它被硬中斷觸發(fā)開始了工作,它會(huì)集中精力處理一波兒網(wǎng)絡(luò)包(絕不只是1個(gè)),然后再去做別的事情。

我們說的處理一波兒是多少呢,策略略復(fù)雜。我們只說其中一個(gè)比較容易理解的,那就是net.core.netdev_budget 內(nèi)核參數(shù)。

#sysctl-a|grepnet.core.netdev_budget = 300

這個(gè)的意思說的是,ksoftirqd 一次最多處理300個(gè)包,處理夠了就會(huì)把 CPU 主動(dòng)讓出來,以便 Linux 上其它的任務(wù)可以得到處理。那么假如說,我們現(xiàn)在就是想提高內(nèi)核處理網(wǎng)絡(luò)包的效率。那就可以讓 ksoftirqd 進(jìn)程多干一會(huì)兒網(wǎng)絡(luò)包的接收,再讓出 CPU。至于怎么提高,直接修改這個(gè)參數(shù)的值就好了。

#sysctl -w net.core.netdev_budget=600

如果要保證重啟仍然生效,需要將這個(gè)配置寫到/etc/sysctl.conf

建議5:接收處理合并

硬中斷合并是指的攢一堆數(shù)據(jù)包后再通知一次 CPU,不過數(shù)據(jù)包仍然是分開的。Lro(Large Receive Offload) /Gro(Generic Receive Offload) 還能把數(shù)據(jù)包合并起來后再往上層傳遞。

如果應(yīng)用中是大文件的傳輸,大部分包都是一段數(shù)據(jù),不用 LRO / GRO 的話,會(huì)每次都將一個(gè)小包傳送到協(xié)議棧(IP接收函數(shù)、TCP接收)函數(shù)中進(jìn)行處理。開啟了的話,內(nèi)核或者網(wǎng)卡會(huì)進(jìn)行包的合并,之后將一個(gè)大包傳給協(xié)議處理函數(shù),如圖 2.4。這樣 CPU 的效率也就提高了。

b767b24e-e633-11ec-ba43-dac502259ad0.png

圖2.4 接收處理合并

Lro 和 Gro 的區(qū)別是合并包的位置不同。Lro 是在網(wǎng)卡上就把合并的事情給做了,因此要求網(wǎng)卡硬件必須支持才行。而 Gso 是在內(nèi)核源碼中用軟件的方式實(shí)現(xiàn)的,更加通用,不依賴硬件。

那么如何查看你的系統(tǒng)內(nèi)是否打開了 LRO / GRO 呢?

#ethtool-keth0generic-receive-offload:onlarge-receive-offload:on...

如果你的網(wǎng)卡驅(qū)動(dòng)沒有打開 GRO 的話,可以通過如下方式打開。

#ethtool-Keth0groon# ethtool -K eth0 lro on

3 發(fā)送過程優(yōu)化

建議1:控制數(shù)據(jù)包大小

在第四章中我們看到,在發(fā)送協(xié)議棧執(zhí)行的過程中到了 IP 層如果要發(fā)送的數(shù)據(jù)大于 MTU 的話,會(huì)被分片。這個(gè)分片會(huì)有哪些影響呢?首先就是在分片的過程中我們看到多了一次的內(nèi)存拷貝。其次就是分片越多,在網(wǎng)絡(luò)傳輸?shù)倪^程中出現(xiàn)丟包的風(fēng)險(xiǎn)也越大。當(dāng)丟包重傳出現(xiàn)的時(shí)候,重傳定時(shí)器的工作時(shí)間單位是秒,也就是說最快 1 秒以后才能開始重傳。所以,如果在你的應(yīng)用程序里可能的話,可以嘗試將數(shù)據(jù)大小控制在一個(gè) MTU 內(nèi)部來極致地提高性能。我所知道的是在早期的 QQ 后臺(tái)服務(wù)中應(yīng)用過這個(gè)技巧,不知道現(xiàn)在還有沒有在用。

建議2:減少內(nèi)存拷貝

假如你要發(fā)送一個(gè)文件給另外一臺(tái)機(jī)器上,那么比較基礎(chǔ)的做法是先調(diào)用 read 把文件讀出來,再調(diào)用 send 把數(shù)據(jù)把數(shù)據(jù)發(fā)出去。這樣數(shù)據(jù)需要頻繁地在內(nèi)核態(tài)內(nèi)存和用戶態(tài)內(nèi)存之間拷貝,如圖 3.1。

b7979e00-e633-11ec-ba43-dac502259ad0.png

圖3.1 read + write 發(fā)送文件

目前減少內(nèi)存拷貝主要有兩種方法,分別是使用 mmap 和 sendfile 兩個(gè)系統(tǒng)調(diào)用。使用 mmap 系統(tǒng)調(diào)用的話,映射進(jìn)來的這段地址空間的內(nèi)存在用戶態(tài)和內(nèi)核態(tài)都是可以使用的。如果你發(fā)送數(shù)據(jù)是發(fā)的是 mmap 映射進(jìn)來的數(shù)據(jù),則內(nèi)核直接就可以從地址空間中讀取,如圖 3.2,這樣就節(jié)約了一次從內(nèi)核態(tài)到用戶態(tài)的拷貝過程。

b7df96ba-e633-11ec-ba43-dac502259ad0.png

圖3.2 mmap + write 發(fā)送文件

不過在 mmap 發(fā)送文件的方式里,系統(tǒng)調(diào)用的開銷并沒有減少,還是發(fā)生兩次內(nèi)核態(tài)和用戶態(tài)的上下文切換。如果你只是想把一個(gè)文件發(fā)送出去,而不關(guān)心它的內(nèi)容,則可以調(diào)用另外一個(gè)做的更極致的系統(tǒng)調(diào)用 - sendfile。在這個(gè)系統(tǒng)調(diào)用里,徹底把讀文件和發(fā)送文件給合并起來了,系統(tǒng)調(diào)用的開銷又省了一次。再配合絕大多數(shù)網(wǎng)卡都支持的"分散-收集"(Scatter-gather)DMA 功能。可以直接從 PageCache 緩存區(qū)中 DMA 拷貝到網(wǎng)卡中,如圖3.3。這樣絕大部分的 CPU 拷貝操作就都省去了。

b814e6da-e633-11ec-ba43-dac502259ad0.png

圖3.3 sendfile 發(fā)送文件

建議3:發(fā)送處理合并

在建議 1 中我們說到過發(fā)送過程在 IP 層如果要發(fā)送的數(shù)據(jù)大于 MTU 的話,會(huì)被分片。但其實(shí)是有一個(gè)例外情況,那就是開啟了 TSO(TCP Segmentation Offload)/ GSO(Generic Segmentation Offload)。我們來回顧和跟進(jìn)

一下發(fā)送過程中的相關(guān)源碼:

//file:net/ipv4/ip_output.cstaticintip_finish_output(structsk_buff*skb){......//大于mtu的話就要進(jìn)行分片了if(skb->len>ip_skb_dst_mtu(skb)&&!skb_is_gso(skb))returnip_fragment(skb,ip_finish_output2)?elsereturnip_finish_output2(skb)?}

ip_finish_output 是協(xié)議層中的函數(shù)。skb_is_gso 判斷是否使用 gso,如果使用了的話,就可以把分片過程推遲到更下面的設(shè)備層去做。

//file:net/core/dev.cintdev_hard_start_xmit(structsk_buff*skb,structnet_device*dev,structnetdev_queue*txq){......if(netif_needs_gso(skb,features)){if(unlikely(dev_gso_segment(skb,features)))gotoout_kfree_skb?if(skb->next)gotogso?}}

dev_hard_start_xmit 位于設(shè)備層,和物理網(wǎng)卡離得更近了。netif_needs_gso 來判斷是否需要進(jìn)行 GSO 切分。在這個(gè)函數(shù)里會(huì)判斷網(wǎng)卡硬件是不是支持 TSO,如果支持則不進(jìn)行 GSO 切分,將大包直接傳給網(wǎng)卡驅(qū)動(dòng),切分工作推遲到網(wǎng)卡硬件中去做。如果硬件不支持,則調(diào)用 dev_gso_segment 開始切分。

推遲分片的好處是可以省去大量包的協(xié)議頭的計(jì)算工作量,減輕 CPU 的負(fù)擔(dān)。

b844fcf8-e633-11ec-ba43-dac502259ad0.png

圖3.4 發(fā)送處理合并

使用 ethtool 工具可以查看當(dāng)前 tso 和 gso 的開啟狀況。

#ethtool-keth0tcp-segmentation-offload:ontx-tcp-segmentation:ontx-tcp-ecn-segmentation:off[fixed]tx-tcp6-segmentation:onudp-fragmentation-offload:off[fixed]generic-segmentation-offload: off

如果沒有開啟,可以使用 ethtool 打開。

#ethtool-Keth0tsoon# ethtool -K eth0 gso on

建議4:多隊(duì)列網(wǎng)卡 XPS 調(diào)優(yōu)

在第四章的發(fā)送過程中 4.4.5 小節(jié),我們看到在 __netdev_pick_tx 函數(shù)中,要選擇一個(gè)發(fā)送隊(duì)列出來。如果存在XPS (Transmit Packet Steering)配置,就以 XPS 配置為準(zhǔn)。過程是根據(jù)當(dāng)前 CPU 的 id 號(hào)去到 XPS 中查看是要用哪個(gè)發(fā)送隊(duì)列,來看下源碼。

//file:net/core/flow_dissector.cstatic inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb){//獲取xps配置dev_maps=rcu_dereference(dev->xps_maps)?if(dev_maps){map=rcu_dereference(map=rcu_dereference(//raw_smp_processor_id()是獲取當(dāng)前cpuiddev_maps->cpu_map[raw_smp_processor_id()])?if(map){if(map->len==1)queue_index=map->queues[0]?...}

源碼中 raw_smp_processor_id 是在獲取當(dāng)前執(zhí)行的 CPU id。用該 CPU 號(hào)查看對(duì)應(yīng)的 CPU 核是否有配置。XPS配置在 /sys/class/net//queues/tx-/xps_cpus 這個(gè)偽文件里。例如對(duì)于我手頭的一臺(tái)服務(wù)器來說,配置是這樣的。

#cat/sys/class/net/eth0/queues/tx-0/xps_cpus00000001#cat/sys/class/net/eth0/queues/tx-1/xps_cpus00000002#cat/sys/class/net/eth0/queues/tx-2/xps_cpus00000004#cat/sys/class/net/eth0/queues/tx-3/xps_cpus00000008......

上述結(jié)果中 xps_cpus 是一個(gè) CPU 掩碼,表示當(dāng)前隊(duì)列對(duì)應(yīng)的 CPU 號(hào)。從上面輸出看對(duì)于 eth0 網(wǎng)卡 下的 tx-0 隊(duì)列來說,是和 CPU0 綁定的。00000001 表示 CPU0,00000002 表示 CPU1,...,以此類推。假如當(dāng)前 CPU 核是CPU0,那么找到的隊(duì)列就是 eth0 網(wǎng)卡 下的 tx-0。

b86396d6-e633-11ec-ba43-dac502259ad0.png

圖3.5多隊(duì)列網(wǎng)卡發(fā)送

那么通過 XPS 指定了當(dāng)前 CPU 要使用的發(fā)送隊(duì)列有什么好處呢。好處大致是有兩個(gè):

第一,因?yàn)楦俚?CPU 爭用同一個(gè)隊(duì)列,所以設(shè)備隊(duì)列鎖上的沖突大大減少。如果進(jìn)一步配置成每個(gè) CPU都有自己獨(dú)立的隊(duì)列用,則會(huì)完全消除隊(duì)列鎖的開銷。

第二,CPU 和發(fā)送隊(duì)列一對(duì)一綁定以后能提高傳輸結(jié)構(gòu)的局部性,從而進(jìn)一步提升效率。

關(guān)于RSS、RPS、RFS、aRFS、XPS等網(wǎng)絡(luò)包收發(fā)過程中的優(yōu)化手段可用參考源碼中

Documentation/networking/scaling.txt這個(gè)文檔。里面有關(guān)于這些技術(shù)的詳細(xì)官方說明。

建議5:使用 eBPF 繞開協(xié)議棧的本機(jī) IO

如果你的業(yè)務(wù)中涉及到大量的本機(jī)網(wǎng)絡(luò) IO 可以考慮這個(gè)優(yōu)化方案。

在第 5 章中我們看到,本機(jī)網(wǎng)絡(luò) IO 和跨機(jī) IO 比較起來,確實(shí)是節(jié)約了驅(qū)動(dòng)上的一些開銷。發(fā)送數(shù)據(jù)不需要進(jìn)RingBuffer 的驅(qū)動(dòng)隊(duì)列,直接把 skb 傳給接收協(xié)議棧(經(jīng)過軟中斷)。但是在內(nèi)核其它組件上,可是一點(diǎn)都沒少,系統(tǒng)調(diào)用、協(xié)議棧(傳輸層、網(wǎng)絡(luò)層等)、設(shè)備子系統(tǒng)整個(gè)走 了一個(gè)遍。連“驅(qū)動(dòng)”程序都走了(雖然對(duì)于回環(huán)設(shè)備來說這個(gè)驅(qū)動(dòng)只是一個(gè)純軟件的虛擬出來的東東)。

如果想用本機(jī)網(wǎng)絡(luò) IO,但是又不想頻繁地在協(xié)議棧中繞來繞去。那么你可以試試 eBPF。使用 eBPF 的 sockmap和 sk redirect 可以繞過 TCP/IP 協(xié)議棧,而被直接發(fā)送給接收端的 socket,業(yè)界已經(jīng)有公司在這么做了。

4 內(nèi)核與進(jìn)程協(xié)作優(yōu)化

建議1:盡量少用 recvfrom 等進(jìn)程阻塞的方式

在 3.3 節(jié)我們看到,在使用了 recvfrom 阻塞方式來接收 socket 上數(shù)據(jù)的時(shí)候。每次一個(gè)進(jìn)程專?為了等一個(gè)socket 上的數(shù)據(jù)就得被從 CPU 上拿下來。然后再換上另一個(gè) 進(jìn)程。等到數(shù)據(jù) ready 了,睡眠的進(jìn)程又會(huì)被喚醒。總共兩次進(jìn)程上下文切換開銷。如果我們服務(wù)器上需要有大量的用戶請(qǐng)求需要處理,那就需要有很多的進(jìn)程存在,而且不停地切換來切換去。這樣的缺點(diǎn)有如下這么幾個(gè):

因?yàn)槊總€(gè)進(jìn)程只能同時(shí)等待一條連接,所以需要大量的進(jìn)程。

進(jìn)程之間互相切換的時(shí)候需要消耗很多 CPU 周期,一次切換大約是 3 - 5 us 左右。

頻繁的切換導(dǎo)致 L1、L2、L3 等高速緩存的效果大打折扣

大家可能以為這種網(wǎng)絡(luò) IO 模型很少見了。但其實(shí)在很多傳統(tǒng)的客戶端 SDK 中,比如 mysql、redis 和 kafka 仍然是沿用了這種方式。

建議2:使用成熟的網(wǎng)絡(luò)庫

使用 epoll 可以高效地管理海量的 socket。在服務(wù)器端。我們有各種成熟的網(wǎng)絡(luò)庫進(jìn)行使用。這些網(wǎng)絡(luò)庫都對(duì)epoll 使用了不同程度的封裝。

首先第一個(gè)要給大家參考的是 Redis。老版本的 Redis 里單進(jìn)程高效地使用 epoll 就能支持每秒數(shù)萬 QPS 的高性能。如果你的服務(wù)是單進(jìn)程的,可以參考 Redis 在網(wǎng)絡(luò) IO 這塊的源碼。

如果是多線程的,線程之間的分工有很多種模式。那么哪個(gè)線程負(fù)責(zé)等待讀 IO 事件,那個(gè)線程負(fù)責(zé)處理用戶請(qǐng)求,哪個(gè)線程又負(fù)責(zé)給用戶寫返回。根據(jù)分工的不同,又衍生出單 Reactor、多 Reactor、以及 Proactor 等多種模式。大家也不必頭疼,只要理解了這些原理之后選擇一個(gè)性能不錯(cuò)的網(wǎng)絡(luò)庫就可以了。比如 PHP 中的 Swoole、Golang 的 net 包、Java 中的 netty 、C++ 中的 Sogou Workflow 都封裝的非常的不錯(cuò)。

建議3:使用 Kernel-ByPass 新技術(shù)

如果你的服務(wù)對(duì)網(wǎng)絡(luò)要求確實(shí)特別特特別的高,而且各種優(yōu)化措施也都用過了,那么現(xiàn)在還有終極優(yōu)化大招 --Kernel-ByPass 技術(shù)。在本書我們看到了內(nèi)核在接收網(wǎng)絡(luò)包的時(shí)候要經(jīng)過很?的收發(fā)路徑。在這期間牽涉到很多內(nèi)核組件之間的協(xié)同、協(xié)議棧的處理、以及內(nèi)核態(tài)和用戶態(tài)的拷貝和切換。Kernel-ByPass 這類的技術(shù)方案就是繞開內(nèi)核協(xié)議棧,自己在用戶態(tài)來實(shí)現(xiàn)網(wǎng)絡(luò)包的收發(fā)。這樣不但避開了繁雜的內(nèi)核協(xié)議棧處理,也減少了頻繁了內(nèi)核態(tài)用戶態(tài)之間的拷貝和切換,性能將發(fā)揮到極致!

目前我所知道的方案有 SOLARFLARE 的軟硬件方案、DPDK 等等。如果大家感興趣,可以多去了解一下!

5 握手揮手過程優(yōu)化

建議1:配置充足的端口范圍

客戶端在調(diào)用 connect 系統(tǒng)調(diào)用發(fā)起連接的時(shí)候,需要先選擇一個(gè)可用的端口。內(nèi)核在選用端口的時(shí)候,是采用從可用端口范圍中某一個(gè)隨機(jī)位置開始遍歷的方式。如果端口不充足的話,內(nèi)核可能需要循環(huán)撞很多次才能選上一個(gè)可用的。這也會(huì)導(dǎo)致花費(fèi)更多的 CPU 周期在內(nèi)部的哈希表查找以及可能的自旋鎖等待上。因此不要等到端口用盡報(bào)錯(cuò)了才開始加大端口范圍,而且應(yīng)該一開始的時(shí)候就保持一個(gè)比較充足的值。

#vi/etc/sysctl.confnet.ipv4.ip_local_port_range=500065000# sysctl -p //使配置生效

如果端口加大了仍然不夠用,那么可以考慮開啟端口 reuse 和 recycle。這樣端口在連接斷開的時(shí)候就不需要等待2MSL 的時(shí)間了,可以快速回收。開啟這個(gè)參數(shù)之前需要保證 tcp_timestamps 是開啟的。

#vi/etc/sysctl.confnet.ipv4.tcp_timestamps=1net.ipv4.tcp_tw_reuse=1net.ipv4.tw_recycle=1# sysctl -p

建議2:客戶端最好不要使用 bind

如果不是業(yè)務(wù)有要求,建議客戶端不要使用 bind。因?yàn)槲覀冊(cè)?6.3 節(jié)看到過,connect 系統(tǒng)調(diào)用在選擇端口的時(shí)候,即使一個(gè)端口已經(jīng)被用過了,只要和已經(jīng)有的連接四元組不完全一致,那這個(gè)端口仍然可以被用于建立新連接。但是 bind 函數(shù)會(huì)破壞 connect 的這段端口選擇邏輯,直接綁定一個(gè)端口,而且一個(gè)端口只能被綁定一次。如果使用了 bind,則一個(gè)端口只能用于發(fā)起一條連接上。總體上來看,你的機(jī)器的最大并發(fā)連接數(shù)就真的受限于65535 了。

建議3:小心連接隊(duì)列溢出

服務(wù)器端使用了兩個(gè)連接隊(duì)列來響應(yīng)來自客戶端的握手請(qǐng)求。這兩個(gè)隊(duì)列的長度是在服務(wù)器 listen 的時(shí)候就確定好了的。如果發(fā)生溢出,很可能會(huì)丟包。所以如果你的業(yè)務(wù)使用的是短連接且流量比較大,那么一定得學(xué)會(huì)觀察這兩個(gè)隊(duì)列是否存在溢出的情況。因?yàn)橐坏┏霈F(xiàn)因?yàn)檫B接隊(duì)列導(dǎo)致的握手問題,那么 TCP 連接耗時(shí)都是秒級(jí)以上了。

對(duì)于半連接隊(duì)列, 有個(gè)簡單的辦法。那就是只要保證 tcp_syncookies 這個(gè)內(nèi)核參數(shù)是 1 就能保證不會(huì)有因?yàn)榘脒B接隊(duì)列滿而發(fā)生的丟包。對(duì)于全連接隊(duì)列來說,可以通過 netstat -s 來觀察。netstat -s 可查看到當(dāng)前系統(tǒng)全連接隊(duì)列滿導(dǎo)致的丟包統(tǒng)計(jì)。但該數(shù)字記錄的是總丟包數(shù),所以你需要再借助 watch 命令動(dòng)態(tài)監(jiān)控。

#watch'netstat--s|grepoverflowed'160 times the listen queue of a socket overflowed //全連接隊(duì)列滿導(dǎo)致的丟包

如果輸出的數(shù)字在你監(jiān)控的過程中變了,那說明當(dāng)前服務(wù)器有因?yàn)槿B接隊(duì)列滿而產(chǎn)生的丟包。你就需要加大你的全連接隊(duì)列的?度了。全連接隊(duì)列是應(yīng)用程序調(diào)用 listen時(shí)傳入的 backlog 以及內(nèi)核參數(shù) net.core.somaxconn 二者之中較小的那個(gè)。如果需要加大,可能兩個(gè)參數(shù)都需要改。如果你手頭并沒有服務(wù)器的權(quán)限,只是發(fā)現(xiàn)自己的客戶端機(jī)連接某個(gè) server 出現(xiàn)耗時(shí)長,想定位一下是否是因?yàn)槲帐株?duì)列的問題。那也有間接的辦法,可以 tcpdump 抓包查看是否有 SYN 的 TCP Retransmission。如果有偶發(fā)的 TCP Retransmission, 那就說明對(duì)應(yīng)的服務(wù)端連接隊(duì)列可能有問題了。

建議4:減少握手重試

在 6.5 節(jié)我們看到如果握手發(fā)生異常,客戶端或者服務(wù)端就會(huì)啟動(dòng)超時(shí)重傳機(jī)制。這個(gè)超時(shí)重試的時(shí)間間隔是翻倍地增長的,1 秒、3 秒、7 秒、15 秒、31 秒、63 秒 ......。對(duì)于我們提供給用戶直接訪問的接口來說,重試第一次耗時(shí) 1 秒多已經(jīng)是嚴(yán)重影響用戶體驗(yàn)了。如果重試到第三次以后,很有可能某一個(gè)環(huán)節(jié)已經(jīng)報(bào)錯(cuò)返回 504 了。所以在這種應(yīng)用場景下,維護(hù)這么多的超時(shí)次數(shù)其實(shí)沒有任何意義。倒不如把他們?cè)O(shè)置的小一些,盡早放棄。其中客戶端的 syn 重傳次數(shù)由 tcp_syn_retries 控制,服務(wù)器半連接隊(duì)列中的超時(shí)次數(shù)是由 tcp_synack_retries 來控制。把它們兩個(gè)調(diào)成你想要的值。

建議5:打開 TFO( TCP Fast Open)

我們第 6 章的時(shí)候沒有介紹一個(gè)細(xì)節(jié),那就是 fastopen 功能。在客戶端和服務(wù)器端都支持該功能的前提下,客戶端的第三次握手 ack 包就可以攜帶要發(fā)送給服務(wù)器的數(shù)據(jù)。這樣就會(huì)節(jié)約一個(gè) RTT 的時(shí)間開銷。如果支持,可以嘗試啟用。

#vi/etc/sysctl.confnet.ipv4.tcp_fastopen=3//服務(wù)器和客戶端兩種角色都啟用#sysctl--p

建議6:保持充足的文件描述符上限

在 Linux 下一切皆是文件,包括我們網(wǎng)絡(luò)連接中的 socket。如果你的服務(wù)進(jìn)程需要支持海量的并發(fā)連接。那么調(diào)整和加大文件描述符上限是很關(guān)鍵的。否則你的線上服務(wù)將會(huì)收到 “Too many open files”這個(gè)錯(cuò)誤。

相關(guān)的限制機(jī)制請(qǐng)參考 8.2 節(jié),這里我們給出一套推薦的修改方法。例如你的服務(wù)需要在單進(jìn)程支持 100 W 條并發(fā),那么建議:

#vi/etc/sysctl.conffs.file-max=1100000//系統(tǒng)級(jí)別設(shè)置成110W,多留點(diǎn)buffer。fs.nr_open=1100000//進(jìn)程級(jí)別也設(shè)置成110W,因?yàn)橐WC比hardnofile大#sysctl--p#vi/etc/security/limits.conf//用戶進(jìn)程級(jí)別都設(shè)置成100W*softnofile1000000* hard nofile 1000000

建議7:如果請(qǐng)求頻繁,請(qǐng)棄用短連接改用長連接

如果你的服務(wù)器頻繁請(qǐng)求某個(gè) server,比如 redis 緩存。和建議 1 比起來,一個(gè)更好一點(diǎn)的方法是使用長連接。這樣的好處有

1)節(jié)約了握手開銷。短連接中每次請(qǐng)求都需要服務(wù)和緩存之間進(jìn)行握手,這樣每次都得讓用戶多等一個(gè)握手的時(shí)間開銷。

2)規(guī)避了隊(duì)列滿的問題。前面我們看到當(dāng)全連接或者半連接隊(duì)列溢出的時(shí)候,服務(wù)器直接丟包。而客戶端呢并不知情,所以傻傻地等 3 秒才會(huì)重試。要知道 tcp 本身并不是專門為互聯(lián)網(wǎng)服務(wù)設(shè)計(jì)的。這個(gè) 3 秒的超時(shí)對(duì)于互聯(lián)網(wǎng)用戶的體驗(yàn)影響是致命的。

3)端口數(shù)不容易出問題。端連接中,在釋放連接的時(shí)候,客戶端使用的端口需要進(jìn)入 TIME_WAIT 狀態(tài),等待 2MSL的時(shí)間才能釋放。所以如果連接頻繁,端口數(shù)量很容易不夠用。而長連接就固定使用那么幾十上百個(gè)端口就夠用了。

建議8:TIME_WAIT 的優(yōu)化

很多線上服務(wù)如果使用了短連接的情況下,就會(huì)出現(xiàn)大量的 TIME_WAIT。

首先,我想說的是沒有必要見到兩三萬個(gè) TIME_WAIT 就恐慌的不行。從內(nèi)存的?度來考慮,一條 TIME_WAIT 狀態(tài)的連接僅僅是 0.5 KB 的內(nèi)存而已。從端口占用的角度來說,確實(shí)是消耗掉了一個(gè)端口。但假如你下次再連接的是不同的 Server 的話,該端口仍然可以使用。只有在所有 TIME_WAIT 都聚集在和一個(gè) Server 的連接上的時(shí)候才會(huì)有問題。

那怎么解決呢? 其實(shí)辦法有很多。第一個(gè)辦法是按上面建議 1 中的開啟端口 reuse 和 recycle。第二個(gè)辦法是限制TIME_WAIT 狀態(tài)的連接的最大數(shù)量。

#vi/etc/sysctl.confnet.ipv4.tcp_max_tw_buckets=32768# sysctl --p

如果再徹底一些,也可以干脆采用建議 7 ,直接用?連接代替頻繁的短連接。連接頻率大大降低以后,自然也就沒有 TIME_WAIT 的問題了。

原文標(biāo)題:深入理解Linux網(wǎng)絡(luò)之網(wǎng)絡(luò)性能優(yōu)化建議

文章出處:【微信公眾號(hào):Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10699

    瀏覽量

    209353
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    3711

    瀏覽量

    64023

原文標(biāo)題:深入理解Linux網(wǎng)絡(luò)之網(wǎng)絡(luò)性能優(yōu)化建議

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【深圳】誠聘運(yùn)開發(fā)工程師

    獵頭推薦職位:運(yùn)開發(fā)工程師工作職責(zé):1. 負(fù)責(zé)運(yùn)平臺(tái)開發(fā)、自動(dòng)化平臺(tái)維護(hù)、研究
    發(fā)表于 07-04 14:34

    【上?!扛呒?jí)運(yùn)工程師

    獵頭職位:高級(jí)運(yùn)工程師工作職責(zé):1.各種運(yùn)項(xiàng)目實(shí)施;2.基礎(chǔ)服務(wù)日常維護(hù)工作,保障業(yè)務(wù)穩(wěn)定可靠;3.持續(xù)改進(jìn)運(yùn)
    發(fā)表于 07-13 15:38

    為何運(yùn)人員要學(xué)Python?

    運(yùn)必須懂開發(fā),不懂開發(fā)運(yùn)維道路會(huì)越走越窄。特別是要學(xué)會(huì)Python開發(fā),Python能滿足絕
    發(fā)表于 02-02 18:55

    學(xué)習(xí)Linux運(yùn)發(fā)展方向

    及丟失等)、對(duì)網(wǎng)站的故障進(jìn)行監(jiān)控、解決網(wǎng)站運(yùn)行的潛在安全問題、開發(fā)自動(dòng)化腳本程序提高工作效率、規(guī)劃網(wǎng)站架構(gòu)、程序發(fā)布流程和規(guī)范,制定運(yùn)工作制度和規(guī)范、配合開發(fā)人員部署并調(diào)試產(chǎn)品研發(fā)需
    發(fā)表于 07-25 17:15

    Linux運(yùn)都要會(huì)哪些shell技能

    。兩者之間,shell幾乎是IT企業(yè)必須使用的運(yùn)自動(dòng)化編程語言,特別是在運(yùn)工作的服務(wù)監(jiān)控、業(yè)務(wù)快速部署、服務(wù)啟動(dòng)停止、數(shù)據(jù)備份及處理、日制分析等環(huán)節(jié)里,shell是不可缺的。當(dāng)然
    發(fā)表于 11-30 17:38

    運(yùn)人員到底要不要學(xué)習(xí)開發(fā)

    ,封妻蔭子”如果僅僅懂編碼,那充其量就是碼農(nóng)而已,所以,開發(fā)人員懂運(yùn)也是趨勢(shì),或者說算是開發(fā)知識(shí)的一部分,因此,老男孩老師在和其他
    發(fā)表于 01-28 17:59

    虛擬化故障怎么辦?虛擬化運(yùn)怎么解決?

    團(tuán)隊(duì)能力和運(yùn)工具!在此特殊時(shí)期,很多運(yùn)人員面臨著運(yùn)工具的匱乏的難題,很多用戶反映明辰智航云安虛擬化業(yè)務(wù)
    發(fā)表于 02-21 21:32

    何為智能運(yùn)?

    一、何為智能運(yùn)?生產(chǎn)設(shè)備/裝備是工業(yè)的重要生產(chǎn)工具,其可靠性、性能對(duì)工業(yè)生產(chǎn)有重大影響。隨著工業(yè)大數(shù)據(jù)推進(jìn),設(shè)備的智能運(yùn)被定義為一個(gè)重要
    發(fā)表于 07-12 06:34

    開啟運(yùn)維新時(shí)代:WOT2016互聯(lián)網(wǎng)運(yùn)開發(fā)者峰會(huì)內(nèi)容回顧

      從互聯(lián)網(wǎng)時(shí)代到數(shù)據(jù)時(shí)代,IT運(yùn)迎來了翻天覆地的變化。從開發(fā)到部署,從測試到監(jiān)控,從性能優(yōu)化到安全保障,新的思維和方法已經(jīng)出現(xiàn),我們已經(jīng)
    發(fā)表于 04-21 15:06 ?699次閱讀

    常見的提權(quán)方法與運(yùn)建議

    常見的提權(quán)方法與運(yùn)建議
    發(fā)表于 09-07 11:23 ?4次下載
    常見的提權(quán)方法與<b class='flag-5'>運(yùn)</b><b class='flag-5'>維</b><b class='flag-5'>建議</b>

    邊緣運(yùn)架構(gòu)是怎樣的

    對(duì)于邊緣云節(jié)點(diǎn),其運(yùn)的總體要求與中心云運(yùn)要求相當(dāng),其中包括規(guī)劃設(shè)計(jì)、部署、維護(hù)、優(yōu)化運(yùn)營等。
    發(fā)表于 04-24 09:57 ?2407次閱讀

    云計(jì)算運(yùn)管理的優(yōu)化與改進(jìn)

    來源:CIO之家 本文經(jīng)授權(quán)轉(zhuǎn)載 為促進(jìn)當(dāng)前云計(jì)算運(yùn)管理的優(yōu)化與改進(jìn),應(yīng)從打造一體化的的運(yùn)管理模式開始,并將業(yè)務(wù)導(dǎo)向放在首位,從而有效實(shí)
    的頭像 發(fā)表于 11-03 14:41 ?2887次閱讀
    云計(jì)算<b class='flag-5'>運(yùn)</b><b class='flag-5'>維</b>管理的<b class='flag-5'>優(yōu)化</b>與改進(jìn)

    設(shè)備智能運(yùn):數(shù)字化時(shí)代的工廠維護(hù)與優(yōu)化策略

    設(shè)備智能運(yùn) 是一種基于數(shù)字化技術(shù)和數(shù)據(jù)分析的設(shè)備維護(hù)和優(yōu)化策略。它通過實(shí)時(shí)監(jiān)測設(shè)備的運(yùn)行狀態(tài)、使用情況和性能參數(shù),對(duì)設(shè)備進(jìn)行預(yù)防性維護(hù)和優(yōu)化
    的頭像 發(fā)表于 11-29 18:01 ?971次閱讀

    制氫機(jī)遠(yuǎn)程監(jiān)控運(yùn)方案

    健康發(fā)展至關(guān)重要。在此背景下,藍(lán)蜂物聯(lián)網(wǎng)提出制氫機(jī)遠(yuǎn)程監(jiān)控運(yùn)方案,旨在通過先進(jìn)的信息技術(shù)手段實(shí)現(xiàn)對(duì)制氫設(shè)備的實(shí)時(shí)監(jiān)測、故障預(yù)警、遠(yuǎn)程診斷及優(yōu)化控制,全面提升運(yùn)
    的頭像 發(fā)表于 04-23 17:44 ?358次閱讀
    制氫機(jī)遠(yuǎn)程監(jiān)控<b class='flag-5'>運(yùn)</b><b class='flag-5'>維</b>方案

    光伏電站智能運(yùn)管理系統(tǒng)三大核心功能

    帶來了更高效、更智能的管理方式。 光伏電站智能運(yùn)管理系統(tǒng)的三大核心功能 1、智能優(yōu)化與管理 光伏電站智能運(yùn)管理平臺(tái)還可以通過對(duì)電站數(shù)據(jù)的
    的頭像 發(fā)表于 08-23 15:55 ?179次閱讀
    光伏電站智能<b class='flag-5'>運(yùn)</b><b class='flag-5'>維</b>管理系統(tǒng)三大核心功能