2021-05-12 14:32:11
高並行情況下Linux系統及kernel引數優化
眾所周知在預設引數情況下Linux對高並行支援並不好,主要受限於單進程最大開啟檔案數限制、核心TCP引數方面和IO事件分配機制等。下面就從幾方面來調整使Linux系統能夠支援高並行環境。
Iptables相關
如非必須,關掉或解除安裝iptables防火牆,並阻止kernel載入iptables模組。這些模組會影響並行效能。
單進程最大開啟檔案數限制
一般的發行版,限制單進程最大可以開啟1024個檔案,這是遠遠不能滿足高並行需求的,調整過程如下:
在#號提示符下敲入:
# ulimit–n 65535
將root啟動的單一進程的最大可以開啟的檔案數設定為65535個。如果系統回顯類似於“Operationnotpermitted”之類的話,說明上述限制修改失敗,實際上是因為在中指定的數值超過了Linux系統對該使用者開啟檔案數的軟限制或硬限制。因此,就需要修改Linux系統對使用者的關於開啟檔案數的軟限制和硬限制。
第一步,修改limits.conf檔案,並新增:
# vim /etc/security/limits.conf
* softnofile 65536
* hard nofile65536
其中'*'號表示修改所有使用者的限制;soft或hard指定要修改軟限制還是硬限制;65536則指定了想要修改的新的限制值,即最大開啟檔案數(請注意軟限制值要小於或等於硬限制)。修改完後儲存檔案。
第二步,修改/etc/pam.d/login檔案,在檔案中新增如下行:
# vim /etc/pam.d/login
sessionrequired /lib/security/pam_limits.so
這是告訴Linux在使用者完成系統登入後,應該呼叫pam_limits.so模組來設定系統對該使用者可使用的各種資源數量的最大限制(包括使用者可開啟的最大檔案數限制),而pam_limits.so模組就會從/etc/security/limits.conf檔案中讀取設定來設定這些限制值。修改完後儲存此檔案。
第三步,檢視Linux系統級的最大開啟檔案數限制,使用如下命令:
# cat/proc/sys/fs/file-max
32568
這表明這台Linux系統最多允許同時開啟(即包含所有使用者開啟檔案數總和)32568個檔案,是Linux系統級硬限制,所有使用者級的開啟檔案數限制都不應超過這個數值。通常這個系統級硬限制是Linux系統在啟動時根據系統硬體資源狀況計算出來的最佳的最大同時開啟檔案數限制,如果沒有特殊需要,不應該修改此限制,除非想為使用者級開啟檔案數限制設定超過此限制的值。修改此硬限制的方法是修改/etc/sysctl.conf檔案內fs.file-max= 131072
這是讓Linux在啟動完成後強行將系統級開啟檔案數硬限制設定為131072。修改完後儲存此檔案。
完成上述步驟後重新啟動系統,一般情況下就可以將Linux系統對指定使用者的單一進程允許同時開啟的最大檔案數限制設為指定的數值。如果重新啟動後用ulimit-n命令檢視使用者可開啟檔案數限制仍然低於上述步驟中設定的最大值,這可能是因為在使用者登入指令碼/etc/profile中使用ulimit-n命令已經將使用者可同時開啟的檔案數做了限制。由於通過ulimit-n修改系統對使用者可同時開啟檔案的最大數限制時,新修改的值只能小於或等於上次ulimit-n設定的值,因此想用此命令增大這個限制值是不可能的。所以,如果有上述問題存在,就只能去開啟/etc/profile指令碼檔案,在檔案中查詢是否使用了ulimit-n限制了使用者可同時開啟的最大檔案數量,如果找到,則刪除這行命令,或者將其設定的值改為合適的值,然後儲存檔案,使用者退出並重新登入系統即可。
通過上述步驟,就為支援高並行TCP連線處理的通訊處理程式解除關於開啟檔案數量方面的系統限制。
核心TCP引數方面
Linux系統下,TCP連線斷開後,會以TIME_WAIT狀態保留一定的時間,然後才會釋放埠。當並行請求過多的時候,就會產生大量的TIME_WAIT狀態的連線,無法及時斷開的話,會佔用大量的埠資源和伺服器資源。這個時候我們可以優化TCP的核心引數,來及時將TIME_WAIT狀態的埠清理掉。
下面介紹的方法只對擁有大量TIME_WAIT狀態的連線導致系統資源消耗有效,如果不是這種情況下,效果可能不明顯。可以使用netstat命令去查TIME_WAIT狀態的連線狀態,輸入下面的組合命令,檢視當前TCP連線的狀態和對應的連線數量:
# netstat-n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
這個命令會輸出類似下面的結果:
LAST_ACK16
SYN_RECV348
ESTABLISHED70
FIN_WAIT1229
FIN_WAIT230
CLOSING33
TIME_WAIT18098
我們只用關心TIME_WAIT的個數,在這裡可以看到,有18000多個TIME_WAIT,這樣就佔用了18000多個埠。要知道埠的數量只有65535個,佔用一個少一個,會嚴重的影響到後繼的新連線。這種情況下,我們就有必要調整下Linux的TCP核心引數,讓系統更快的釋放TIME_WAIT連線。
編輯組態檔:/etc/sysctl.conf
# vim /etc/sysctl.conf
在這個檔案中,加入下面的幾行內容:
net.ipv4.tcp_syncookies= 1
net.ipv4.tcp_tw_reuse= 1
net.ipv4.tcp_tw_recycle= 1
net.ipv4.tcp_fin_timeout= 30
輸入下面的命令,讓核心引數生效:
# sysctl-p
簡單的說明上面的引數的含義:
net.ipv4.tcp_syncookies= 1
#表示開啟SYNCookies。當出現SYN等待佇列溢位時,啟用cookies來處理,可防範少量SYN***,預設為0,表示關閉;
net.ipv4.tcp_tw_reuse= 1
#表示開啟重用。允許將TIME-WAITsockets重新用於新的TCP連線,預設為0,表示關閉;
net.ipv4.tcp_tw_recycle= 1
#表示開啟TCP連線中TIME-WAITsockets的快速回收,預設為0,表示關閉;
net.ipv4.tcp_fin_timeout
#修改系統預設的TIMEOUT 時間。
在經過這樣的調整之後,除了會進一步提升伺服器的負載能力之外,還能夠防禦小流量程度的DoS、CC和SYN***。
此外,如果你的連線數本身就很多,我們可以再優化一下TCP的可使用埠範圍,進一步提升伺服器的並行能力。依然是往上面的引數檔案中,加入下面這些設定:
net.ipv4.tcp_keepalive_time= 1200
net.ipv4.ip_local_port_range= 1024 65535
net.ipv4.tcp_max_syn_backlog= 8192
net.ipv4.tcp_max_tw_buckets= 5000
這幾個引數,建議只在流量非常大的伺服器上開啟,會有顯著的效果。一般的流量小的伺服器上,沒有必要去設定這幾個引數。
net.ipv4.tcp_keepalive_time= 1200
#表示當keepalive起用的時候,TCP傳送keepalive訊息的頻度。預設是2小時,改為20分鐘。
net.ipv4.ip_local_port_range= 1024 65535
#表示用於向外連線的埠範圍。預設情況下很小,改為1024到65535。
net.ipv4.tcp_max_syn_backlog= 8192
#表示SYN佇列的長度,預設為1024,加大佇列長度為8192,可以容納更多等待連線的網路連線數。
net.ipv4.tcp_max_tw_buckets= 5000
#表示系統同時保持TIME_WAIT的最大數量,如果超過這個數位,TIME_WAIT將立刻被清除並列印警告資訊。預設為180000,改為5000。此項引數可以控制TIME_WAIT的最大數量,只要超出了。
核心其他TCP引數說明:
net.ipv4.tcp_max_syn_backlog= 65536
#記錄的那些尚未收到用戶端確認資訊的連線請求的最大值。對於有128M記憶體的系統而言,預設值是1024,小記憶體的系統則是128。
net.core.netdev_max_backlog= 32768
#每個網路介面接收封包的速率比核心處理這些包的速率快時,允許送到佇列的封包的最大數目。
net.core.somaxconn= 32768
#例如web應用中listen函數的backlog預設會給我們核心引數的net.core.somaxconn限制到128,而nginx定義的NGX_LISTEN_BACKLOG預設為511,所以有必要調整這個值。
net.core.wmem_default= 8388608
net.core.rmem_default= 8388608
net.core.rmem_max= 16777216 #最大socket讀buffer,可參考的優化值:873200
net.core.wmem_max= 16777216 #最大socket寫buffer,可參考的優化值:873200
net.ipv4.tcp_timestsmps= 0
#時間戳可以避免序列號的捲繞。一個1Gbps的鏈路肯定會遇到以前用過的序列號。時間戳能夠讓核心接受這種“異常”的封包。這裡需要將其關掉。
net.ipv4.tcp_synack_retries= 2
#為了開啟對端的連線,核心需要傳送一個SYN並附帶一個回應前面一個SYN的ACK。也就是所謂三次握手中的第二次握手。這個設定決定了核心放棄連線之前傳送SYN+ACK包的數量。
net.ipv4.tcp_syn_retries= 2
#在核心放棄建立連線之前傳送SYN包的數量。
#net.ipv4.tcp_tw_len= 1
net.ipv4.tcp_tw_reuse= 1
# 開啟重用。允許將TIME-WAITsockets重新用於新的TCP連線。
net.ipv4.tcp_wmem= 8192 436600 873200
# TCP寫buffer,可參考的優化值:8192 436600 873200
net.ipv4.tcp_rmem = 32768 436600 873200
# TCP讀buffer,可參考的優化值:32768 436600 873200
net.ipv4.tcp_mem= 94500000 91500000 92700000
# 同樣有3個值,意思是:
net.ipv4.tcp_mem[0]:低於此值,TCP沒有記憶體壓力。
net.ipv4.tcp_mem[1]:在此值下,進入記憶體壓力階段。
net.ipv4.tcp_mem[2]:高於此值,TCP拒絕分配socket。
上述記憶體單位是頁,而不是位元組。可參考的優化值是:7864321048576 1572864
net.ipv4.tcp_max_orphans= 3276800
#系統中最多有多少個TCP通訊端不被關聯到任何一個使用者檔案控制代碼上。
如果超過這個數位,連線將即刻被復位並列印出警告資訊。
這個限制僅僅是為了防止簡單的DoS***,不能過分依靠它或者人為地減小這個值,
更應該增加這個值(如果增加了記憶體之後)。
net.ipv4.tcp_fin_timeout= 30
#如果通訊端由本端要求關閉,這個引數決定了它保持在FIN-WAIT-2狀態的時間。對端可以出錯並永遠不關閉連線,甚至意外當機。預設值是60秒。2.2 核心的通常值是180秒,你可以按這個設定,但要記住的是,即使你的機器是一個輕載的WEB伺服器,也有因為大量的死通訊端而記憶體溢位的風險,FIN-WAIT-2的危險性比FIN-WAIT-1要小,因為它最多只能吃掉1.5K記憶體,但是它們的生存期長些。
同時還涉及到一個TCP 擁塞演算法的問題,你可以用下面的命令檢視本機提供的擁塞演算法控制模組:
sysctlnet.ipv4.tcp_available_congestion_control
對於幾種演算法的分析,詳情可以參考下:TCP擁塞控制演算法的優缺點、適用環境、效能分析,比如高延時可以試用hybla,中等延時可以試用htcp演算法等。
??果想設定TCP 擁塞演算法為hybla
net.ipv4.tcp_congestion_control=hybla
額外的,對於核心版高於於3.7.1的,我們可以開啟tcp_fastopen:
net.ipv4.tcp_fastopen= 3
IO事件分配機制
在Linux啟用高並行TCP連線,必須確認應用程式是否使用了合適的網路I/O技術和I/O事件分派機制。可用的I/O技術有同步I/O,非阻塞式同步I/O,以及非同步I/O。在高TCP並行的情形下,如果使用同步I/O,這會嚴重阻塞程式的運轉,除非為每個TCP連線的I/O建立一個執行緒。但是,過多的執行緒又會因系統對執行緒的排程造成巨大開銷。因此,在高TCP並行的情形下使用同步I/O是不可取的,這時可以考慮使用非阻塞式同步I/O或非同步I/O。非阻塞式同步I/O的技術包括使用select(),poll(),epoll等機制。非同步I/O的技術就是使用AIO。
從I/O事件分派機制來看,使用select()是不合適的,因為它所支援的並行連線數有限(通常在1024個以內)。如果考慮效能,poll()也是不合適的,儘管它可以支援的較高的TCP並行數,但是由於其採用“輪詢”機制,當並行數較高時,其執行效率相當低,並可能存在I/O事件分派不均,導致部分TCP連線上的I/O出現“飢餓”現象。而如果使用epoll或AIO,則沒有上述問題(早期Linux核心的AIO技術實現是通過在核心中為每個I/O請求建立一個執行緒來實現的,這種實現機制在高並行TCP連線的情形下使用其實也有嚴重的效能問題。但在最新的Linux核心中,AIO的實現已經得到改進)。
綜上所述,在開發支援高並行TCP連線的Linux應用程式時,應儘量使用epoll或AIO技術來實現並行的TCP連線上的I/O控制,這將為提升程式對高並行TCP連線的支援提供有效的I/O保證。
經過這樣的優化設定之後,伺服器的TCP並行處理能力會顯著提高。以上設定僅供參考,用於生產環境請根據自己的實際情況調整觀察再調整。
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx
本文永久更新連結地址:https://www.linuxidc.com/Linux/2018-08/153369.htm
相關文章