高併發場景下,如何優化服務器的性能

語言: CN / TW / HK
摘要:tcp_nodelay參數主要是對TCP套接字來説的,那對於服務器硬件,如果要使其能夠支撐上百萬甚至上千萬的併發,我們該如何對其進行優化呢?

本文分享自華為雲社區《【高併發】高併發場景下如何優化服務器的性能?》,作者: 冰 河 。

寫在前面

最近,有小夥伴在羣裏提問: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 "." '{print $1}'|sort -k1|uniq

運行命令輸出的結果信息如下所示。

abi
crypto
debug
dev
fs
kernel
net
sunrpc
user
vm

其中的net類型就是我們要關注的與網絡相關的操作系統參數。我們可以獲取net類型下的子類型,如下所示。

/sbin/sysctl -a|grep "^net."|awk -F "[.| ]" '{print $2}'|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個文件。

 

點擊關注,第一時間瞭解華為雲新鮮技術~