1. 程式人生 > 其它 >Linux伺服器高併發調優實戰

Linux伺服器高併發調優實戰

眾所周知在預設引數情況下Linux對高併發支援並不好,主要受限於單程序最大開啟檔案數限制、核心TCP引數方面和IO事件分配機制等。下面就從幾方面來調整使Linux系統能夠支援高併發環境。

iptables相關

如非必須,關掉或解除安裝iptables防火牆,並阻止kernel載入iptables模組。這些模組會影響併發效能。

單程序最大開啟檔案數限制

一般的發行版,限制單程序最大可以開啟1024個檔案,這是遠遠不能滿足高併發需求的,調整過程如下:

#號提示符下敲入:

# ulimit -n 65535

root啟動的單一程序的最大可以開啟的檔案數設定為65535個。如果系統回顯類似於“Operationnotpermitted”之類的話,說明上述限制修改失敗,實際上是因為指定的數值超過了Linux系統對該使用者開啟檔案數的軟限制或硬限制。因此,就需要修改Linux系統對使用者的關於開啟檔案數的軟限制和硬限制。

第一步,修改limits.conf檔案,並新增:

# vim /etc/security/limits.conf

* soft nofile 65535

* hard nofile 65535

其中'*'號表示修改所有使用者的限制;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_ACK 16

SYN_RECV 348

ESTABLISHED 70

FIN_WAIT 1229

FIN_WAIT 230

CLOSING 33

TIME_WAIT 18098

我們只用關心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分鐘。

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的最大數量,只要超出了。

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保證。