來源:https://www.cnblogs.com/txlsz/p/13683892.htmlhtml
衆所周知在默認參數狀況下Linux對高併發支持並很差,主要受限於單進程最大打開文件數限制、內核TCP參數方面和IO事件分配機制等。下面就從幾方面來調整使Linux系統可以支持高併發環境。nginx
iptables相關
如非必須,關掉或卸載iptables防火牆,並阻止kernel加載iptables模塊。這些模塊會影響併發性能。web
單進程最大打開文件數限制
通常的發行版,限制單進程最大能夠打開1024個文件,這是遠遠不能知足高併發需求的,調整過程以下:算法
在#號提示符下敲入:vim
# 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文件,在文件中添加以下行:cookie
# 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分鐘。
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= 65535
記錄的那些還沒有收到客戶端確認信息的鏈接請求的最大值。對於有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併發處理能力會顯著提升。以上配置僅供參考,用於生產環境請根據本身的實際狀況調整觀察再調整。
- END -
本文分享自微信公衆號 - DevOps持續交付(devopscd)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。