最近,有小夥伴在羣裏提問:Linux系統怎麼設置tcp_nodelay參數?也有小夥伴說問我。那今天,咱們就來根據這個問題來聊聊在高併發場景下如何優化服務器的性能這個話題。node
其實,tcp_nodelay參數並非在操做系統級別進行配置的,而是在TCP套接字上添加tcp_nodelay參數來關閉粘包算法,以便使數據包可以當即投遞出去。tcp_nodelay參數主要是對TCP套接字來講的,那對於服務器硬件,若是要使其可以支撐上百萬甚至上千萬的併發,咱們該如何對其進行優化呢?git
文章已收錄到:github
https://github.com/sunshinelyz/technology-binghe算法
https://gitee.com/binghe001/technology-binghe數據庫
這裏,我使用的操做系統爲CentOS 8,咱們能夠輸入以下命令來查看操做系統的版本。bash
CentOS Linux release 8.0.1905 (Core)
對於高併發的場景,咱們主要仍是優化操做系統的網絡性能,而操做系統中,有不少關於網絡協議的參數,咱們對於服務器網絡性能的優化,主要是對這些系統參數進行調優,以達到提高咱們應用訪問性能的目的。服務器
在CentOS 操做系統中,咱們能夠經過以下命令來查看全部的系統參數。微信
/sbin/sysctl -a
部分輸出結果以下所示。cookie
這裏的參數太多了,大概有一千多個,在高併發場景下,咱們不可能對操做系統的全部參數進行調優。咱們更多的是關注與網絡相關的參數。若是想得到與網絡相關的參數,那麼,咱們首先須要獲取操做系統參數的類型,以下命令能夠獲取操做系統參數的類型。網絡
/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 的最小值、壓力值、最大值分別是 6553六、39321六、524288,單位是「頁」 。
假如平均每一個文件數據包爲 512KB,每一個套接字讀寫緩衝區最小能夠各容納 2 個數據包,默承認以各容納 4 個數據包,最大能夠各容納 10 個數據包,那咱們能夠算出 tcp_rmem 和 tcp_wmem 的最小值、默認值、最大值分別是 104857六、209715二、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鏈接呢?
(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個文件。
好了,本文結合羣內讀者的提問進行的一些總結,但願可以給小夥伴們帶來實質性的幫助。今天就到這兒吧,我是冰河,你們有啥問題能夠在下方留言,也能夠加我微信:sun_shine_lyz,一塊兒交流技術,一塊兒進階,一塊兒牛逼~~