高併發場景下優化伺服器的效能實戰

2021-10-18 07:56:14 字數 4512 閱讀 1339

tcp_nodelay引數並不是在作業系統級別進行配置的,而是在tcp套接字上新增tcp_nodelay引數來關閉粘包演算法,以便使資料報能夠立即投遞出去。

寫在前面

最近,有小夥伴在群裡提問:linux系統怎麼設定tcp_nodelay引數?也有小夥伴說問我。那今天,我們就來根據這個問題來聊聊在高併發場景下如何優化伺服器的效能這個話題。

其實,tcp_nodelay引數並不是在作業系統級別進行配置的,而是在tcp套接字上新增tcp_nodelay引數來關閉粘包演算法,以便使資料報能夠立即投遞出去。tcp_nodelay引數主要是對tcp套接字來說的,那對於伺服器硬體,如果要使其能夠支撐上百萬甚至上千萬的併發,我們該如何對其進行優化呢?

文章已收錄到:

作業系統

這裡,我使用的作業系統為centos 8,我們可以輸入如下命令來檢視作業系統的版本。

centos linux release 8.0.1905 (core)
對於高併發的場景,我們主要還是優化作業系統的網路效能,而作業系統中,有很多關於網路協議的引數,我們對於伺服器網路效能的優化,主要是對這些系統引數進行調優,以達到提公升我們應用訪問效能的目的。

系統引數

在centos 作業系統中,我們可以通過如下命令來檢視所有的系統引數。

/sbin/sysctl -a
部分輸出結果如下所示。

/sbin/sysctl -a|awk -f "." ''|sort -k1|uniq
執行命令輸出的結果資訊如下所示。

abi 

crypto

debug

dev

fs kernel

net

sunrpc

user

vm

其中的net型別就是我們要關注的與網路相關的作業系統引數。我們可以獲取net型別下的子型別,如下所示。

/sbin/sysctl -a|grep "^net."|awk -f "[.| ]" ''|sort -k1|uniq
輸出的結果資訊如下所示。

bridge 

core

ipv4

ipv6

netfilter

nf_conntrack_max

unix

在linux作業系統中,這些與網路相關的引數都可以在/etc/sysctl.conf 檔案裡修改,如果/etc/sysctl.conf 檔案中不存在這些引數,我們可以自行在/etc/sysctl.conf 檔案中新增這些引數。

在net型別的子型別中,我們需要重點關注的子型別有:core和ipv4。

優化套接字緩衝區

如果伺服器的網路套接字緩衝區太小,就會導致應用程式讀寫多次才能將資料處理完,這會大大影響我們程式的效能。如果網路套接字緩衝區設定的足夠大,從一定程度上能夠提公升我們程式的效能。

我們可以在伺服器的命令列輸入如下命令,來獲取有關伺服器套接字緩衝區的資訊。

/sbin/sysctl -a|grep "^net."|grep "[r|w|_]mem[_| ]"
輸出的結果資訊如下所示。

net.core.rmem_default = 212992 

net.core.rmem_max = 212992

net.core.wmem_default = 212992

net.core.wmem_max = 212992

net.ipv4.tcp_mem = 43545 58062 87090

net.ipv4.tcp_rmem = 4096 87380 6291456

net.ipv4.tcp_wmem = 4096 16384 4194304

net.ipv4.udp_mem = 87093 116125 174186

net.ipv4.udp_rmem_min = 4096

net.ipv4.udp_wmem_min = 4096

其中,帶有max、default、min關鍵字的為分別代表:最大值、預設值和最小值;帶有mem、rmem、wmem關鍵字的分別為:總記憶體、接收緩衝區記憶體、傳送緩衝區記憶體。

這裡需要注意的是:帶有rmem 和 wmem關鍵字的單位都是「位元組」,而帶有mem關鍵字的單位是「頁」。「頁」是作業系統管理記憶體的最小單位,在 linux 系統裡,預設一頁是 4kb 大小。

如何優化頻繁收發大檔案

如果在高併發場景下,需要頻繁的收發大檔案,我們該如何優化伺服器的效能呢?

這裡,我們可以修改的系統引數如下所示。

net.core.rmem_default 

net.core.rmem_max

net.core.wmem_default

net.core.wmem_max

net.ipv4.tcp_mem

net.ipv4.tcp_rmem

net.ipv4.tcp_wmem

這裡,我們做個假設,假設系統最大可以給tcp分配 2gb 記憶體,最小值為 256mb,壓力值為 1.5gb。按照一頁為 4kb 來計算, tcp_mem 的最小值、壓力值、最大值分別是 65536、393216、524288,單位是「頁」 。

假如平均每個檔案資料報為 512kb,每個套接字讀寫緩衝區最小可以各容納 2 個資料報,預設可以各容納 4 個資料報,最大可以各容納 10 個資料報,那我們可以算出 tcp_rmem 和 tcp_wmem 的最小值、預設值、最大值分別是 1048576、2097152、5242880,單位是「位元組」。而 rmem_default 和 wmem_default 是 2097152,rmem_max 和 wmem_max 是 5242880。

注:後面詳細介紹這些數值是如何計算的~~

這裡,還需要注意的是:緩衝區超過了 65535,還需要將 net.ipv4.tcp_window_scaling 引數設定為 1。

經過上面的分析後,我們最終得出的系統調優引數如下所示。

net.core.rmem_default = 2097152 

net.core.rmem_max = 5242880

net.core.wmem_default = 2097152

net.core.wmem_max = 5242880

net.ipv4.tcp_mem = 65536 393216 524288

net.ipv4.tcp_rmem = 1048576 2097152 5242880

net.ipv4.tcp_wmem = 1048576 2097152 5242880

優化tcp連線對計算機網路有一定了解的小夥伴都知道,tcp的連線需要經過「三次握手」和「四次揮手」的,還要經過慢啟動、滑動視窗、粘包演算法等支援可靠性傳輸的一系列技術支援。雖然,這些能夠保證tcp協議的可靠性,但有時這會影響我們程式的效能。

那麼,在高併發場景下,我們該如何優化tcp連線呢?

(1)關閉粘包演算法

如果使用者對於請求的耗時很敏感,我們就需要在tcp套接字上新增tcp_nodelay引數來關閉粘包演算法,以便資料報能夠立刻傳送出去。此時,我們也可以設定net.ipv4.tcp_syncookies的引數值為1。

(2)避免頻繁的建立和**連線資源

網路連線的建立和**是非常消耗效能的,我們可以通過關閉空閒的連線、重複利用已經分配的連線資源來優化伺服器的效能。重複利用已經分配的連線資源大家其實並不陌生,像:執行緒池、資料庫連線池就是復用了執行緒和資料庫連線。

我們可以通過如下引數來關閉伺服器的空閒連線和復用已分配的連線資源。

net.ipv4.tcp_tw_reuse = 1 

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_fin_timeout = 30

net.ipv4.tcp_keepalive_time=1800

(3)避免重**送資料報tcp支援超時重傳機制。如果傳送方將資料報已經傳送給接收方,但傳送方並未收到反饋,此時,如果達到設定的時間間隔,就會觸發tcp的超時重傳機制。為了避免傳送成功的資料報再次傳送,我們需要將伺服器的net.ipv4.tcp_sack引數設定為1。

(4)增大伺服器檔案描述符數量

在linux作業系統中,乙個網路連線也會占用乙個檔案描述符,連線越多,占用的檔案描述符也就越多。如果檔案描述符設定的比較小,也會影響我們伺服器的效能。此時,我們就需要增大伺服器檔案描述符的數量。

例如:fs.file-max = 10240000,表示伺服器最多可以開啟10240000個檔案。

Epoll實現伺服器高併發

最近在做乙個關於高併發伺服器相關的專案需要用到非同步 非阻塞io通訊,實現高tcp併發。以下用epoll技術實現乙個簡單的tcp高併發伺服器,驗證無業務處理的情況下,epoll處理併發連線的數的效果。include include include include include include in...

高併發計算伺服器數量

每秒查詢率qps 對乙個特定的查詢伺服器在規定時間內所處理流量多少的衡量標準,即每秒請求數,即最大談吐能力。併發數 併發數和qps是不同的概念,一般說qps會說多少併發使用者下qps,當qps相同時,併發使用者數越大,併發處理能力越好。當併發使用者數過大時,會造成程序 執行緒 頻繁切換,反正真正用於...

高併發伺服器(基於epoll)

本章節是用基本的linux unix基本函式編寫乙個完整的伺服器和客戶端例子,可在linux ubuntu 和unix freebsd 上執行,客戶端和服務端的功能如下 客戶端從標準輸入讀入一行,傳送到服務端 服務端從網路讀取一行,把小寫變為大寫,然後輸出到客戶端 客戶端收到服務端的響應,輸出這一行...