您好,登錄后才能下訂單哦!
這篇文章主要講解了“Linux高并發踩過的坑及性能實例分析”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Linux高并發踩過的坑及性能實例分析”吧!
Linux操作系統是現在服務器的首選操作系統,在Linux的默認系統參數下,Linux針對高并發的支持性并不是很好。小編從事Linux下應用程序開發多年,關于Linux系統下的高并發,小編自己踩過的坑,及如何解決踩過的坑下面列上幾條,供大家參考,避免再次掉坑。
出現這句提示的原因是程序打開的文件socket連接數量超過系統設定值。
查看每個用戶最大允許打開的文件數量
ulimit -a
其中 open files (-n) 1024 表示每個用戶最大允許打開的文件數量是1024
當前系統文件句柄的最大數目,只用于查看,不能設置修改
cat /proc/sys/fs/file-max
查看某個進程的打開文件限制數
cat /proc/10446(pid)/limits
設置open files 數值方法
ulimit -n 65535
這種設置方法在重啟后會還原為默認值。
永久設置方法:
vim /etc/security/limits.conf
在最后加入
* soft nofile 65535 * hard nofile 65535
生效需要重啟系統
這樣修改之后,問題得到有效解決。
現象是高并發場景下,服務器運行應用卡頓。
排查方法:查看服務器配置:
netstat -ant|awk '/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}'
發現處于 time_wait 的數量太多,有幾萬條,應該是大量socket處于TIME_WAIT狀態。如果客戶端的并發量持續很高,此時部分客戶端就會顯示連接不上。
TCP連接狀態描述:
CLOSED:無連接是活動的或正在進行 LISTEN:服務器在等待進入呼叫 SYN_RECV:一個連接請求已經到達,等待確認 SYN_SENT:應用已經開始,打開一個連接 ESTABLISHED:正常數據傳輸狀態 FIN_WAIT1:應用說它已經完成 FIN_WAIT2:另一邊已同意釋放 ITMED_WAIT:等待所有分組死掉 CLOSING:兩邊同時嘗試關閉 TIME_WAIT:另一邊已初始化一個釋放 LAST_ACK:等待所有分組死掉
TIME_WAIT過多危害
網絡情況不好時,如果主動方無TIME_WAIT等待,關閉前個連接后,主動方與被動方又建立起新的TCP連接,這時被動方重傳或延時過來的FIN包過來后會直接影響新的TCP連接;
同樣網絡情況不好并且無TIME_WAIT等待,關閉連接后無新連接,當接收到被動方重傳或延遲的FIN包后,會給被動方回一個RST包,可能會影響被動方其它的服務連接。
針對如何解決TIME_WAIT 過多這一問題,解答如下:
編輯內核文件/etc/sysctl.conf,加入以下內容:
net.ipv4.tcp_syncookies = 1 #表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉; net.ipv4.tcp_tw_reuse = 1 #表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0,表示關閉; net.ipv4.tcp_tw_recycle = 1 #表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。 net.ipv4.tcp_fin_timeout =30#修改系默認的 TIMEOUT 時間
然后執行 /sbin/sysctl -p 讓參數生效.
簡單來說,就是打開系統的TIMEWAIT重用和快速回收。
如果您的系統的連接數本身就很多,如果以上配置調優后性能還不理想,可以再優化一下TCP的可使用端口范圍,進一步提升服務器的并發能力。依然是/etc/sysctl.conf文件中,加入下面這些配置:
vi /etc/sysctl.conf #表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,改為20分鐘。 net.ipv4.tcp_keepalive_time = 1200 #表示用于向外連接的端口范圍。缺省情況下很小:32768到61000,改為1024到65000。 net.ipv4.ip_local_port_range = 1024 65000 #表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數。 net.ipv4.tcp_max_syn_backlog = 8192 #表示系統同時保持TIME_WAIT套接字的最大數量,如果超過這個數字,TIME_WAIT套接字將立刻被清除并打印警告信息。默認為180000,改為5000。對于Apache、Nginx等服務器,上幾行的參數可以很好地減少TIME_WAIT套接字數量,但是對于 Squid,效果卻不大。此項參數可以控制TIME_WAIT套接字的最大數量,避免Squid服務器被大量的TIME_WAIT套接字拖死。 net.ipv4.tcp_max_tw_buckets = 5000
Linux內核更多參數優化說明
vim /etc/sysctl.conf
1、net.ipv4.tcp_max_syn_backlog = 65536
記錄的那些尚未收到客戶端確認信息的連接請求的最大值。對于超過128M內存的系統而言,缺省值是1024,低于128M小內存的系統則是128。
SYN Flood攻擊利用TCP協議散布握手的缺陷,偽造虛假源IP地址發送大量TCP-SYN半打開連接到目標系統,最終導致目標系統Socket隊列資源耗盡而無法接受新的連接。為了應付這種攻擊,現代Unix系統中普遍采用多連接隊列處理的方式來緩沖(而不是解決)這種攻擊,是用一個基本隊列處理正常的完全連接應用(Connect()和Accept() ),是用另一個隊列單獨存放半打開連接。
這種雙隊列處理方式和其他一些系統內核措施(例如Syn-Cookies/Caches)聯合應用時,能夠比較有效的緩解小規模的SYN Flood攻擊(事實證明<1000p/s)加大SYN隊列長度可以容納更多等待連接的網絡連接數,一般遭受SYN Flood攻擊的網站,都存在大量SYN_RECV狀態,所以調大tcp_max_syn_backlog值能增加抵抗syn攻擊的能力。
2、net.core.netdev_max_backlog = 32768
每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目。
3、net.core.somaxconn = 32768
調整系統同時發起并發TCP連接數,可能需要提高連接儲備值,以應對大量突發入局連接請求的情況。如果同時接收到大量連接請求,使用較大的值會提高受支持的暫掛連接的數量,從而可減少連接失敗的數量。大的偵聽隊列對防止DDoS攻擊也會有所幫助。掛起請求的最大數量默認是128。
查看實時內核實時丟包命令: netstat-su
位置:/proc/sys/
4、net.core.wmem_default = 8388608
該參數指定了發送套接字緩沖區大小的缺省值(以字節為單位)
5、net.core.rmem_default = 8388608
該參數指定了接收套接字緩沖區大小的缺省值(以字節為單位)
6、net.core.rmem_max = 16777216
該參數指定了接收套接字緩沖區大小的最大值(以字節為單位)
7、net.core.wmem_max = 16777216
該參數指定了發送套接字緩沖區大小的最大值(以字節為單位)
8、net.ipv4.tcp_timestamps = 0
Timestamps可以防范那些偽造的sequence號碼。一條1G的寬帶線路或許會重遇到帶out-of-line數值的舊sequence號碼(假如它是由于上次產生的)。時間戳能夠讓內核接受這種“異常”的數據包。這里需要將其關掉,以提高性能。
9、net.ipv4.tcp_synack_retries = 2
對于遠端的連接請求SYN,內核會發送SYN+ACK數據報,以確認收到上一個SYN連接請求包。這是所謂的三次握手(threeway handshake)機制的第二個步驟。這里決定內核在放棄連接之前所送出的SYN+ACK數目。不應該大于255,默認值是5,對應于180秒左右時間。(可以根據tcp_syn_retries來決定這個值)
10、net.ipv4.tcp_syn_retries = 2
對于一個新建連接,內核要發送多少個SYN連接請求才決定放棄。不應該大于255,默認值是5,對應于180秒左右時間。(對于大負載而物理通信良好的網絡而言,這個值偏高,可修改為2.這個值僅僅是針對對外的連接,對進來的連接,是由tcp_retries1 決定的)
#net.ipv4.tcp_tw_len = 1
11、net.ipv4.tcp_tw_reuse = 1
表示開啟重用,允許將TIME-WAIT Sockets重新用于新的TCP連接,默認為0,表示關閉。這個對快速重啟動某些服務,而啟動后提示端口已經被使用的情形非常有幫助。
12、net.ipv4.tcp_mem = 94500000 915000000 927000000
tcp_mem有3個INTEGER變量:low, pressure, high
low:當TCP使用了低于該值的內存頁面數時,TCP沒有內存壓力,TCP不會考慮釋放內存。(理想情況下,這個值應與指定給tcp_wmem的第2個值相匹配。這第2個值表明,最大頁面大小乘以最大并發請求數除以頁大小 (131072*300/4096)
pressure:當TCP使用了超過該值的內存頁面數量時,TCP試圖穩定其內存使用,進入pressure模式,當內存消耗低于low值時則退出pressure狀態。(理想情況下這個值應該是TCP可以使用的總緩沖區大小的最大值(204800*300/4096)
high:允許所有TCP Sockets用于排隊緩沖數據報的頁面量。如果超過這個值,TCP連接將被拒絕,這就是為什么不要令其過于保守(512000*300/4096)的原因了。在這種情況下,提供的價值很大,它能處理很多連接,是所預期的2.5倍;或者使現有連接能夠傳輸2.5倍的數據。
一般情況下這些值是在系統啟動時根據系統內存數量計算得到的。
13、net.ipv4.tcp_max_orphans = 3276800
系統所能處理不屬于任何進程的TCP sockets最大數量。假如超過這個數量﹐那么不屬于任何進程的連接會被立即reset,并同時顯示警告信息。之所以要設定這個限制﹐純粹為了抵御那些簡單的DoS攻擊﹐千萬不要依賴這個或是人為的降低這個限制
14、net.ipv4.tcp_fin_timeout = 30
如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2狀態的時間。對端可以出錯并永遠不關閉連接,甚至意外當機。缺省值是60秒。2.2 內核的通常值是180秒,你可以按這個設置,但要記住的是,即使你的機器是一個輕載的WEB服務器,也有因為大量的死套接字而內存溢出的風險,FIN-WAIT-2的危險性比FIN-WAIT-1要小,因為它最多只能吃掉1.5K內存,但是它們的生存期長些。
15、net.ipv4.ip_conntrack_max = 10000
設置系統對最大跟蹤的TCP連接數的限制(CentOS 5.6無此參數)
同時還涉及到一個TCP 擁塞算法的問題,你可以用下面的命令查看本機提供的擁塞算法控制模塊:
sysctlnet.ipv4.tcp_available_congestion_control
對于幾種算法的分析,詳情可以參考下:TCP擁塞控制算法的優缺點、適用環境、性能分析,比如高延時可以試用hybla,中等延時可以試用htcp算法等。
如果想設置TCP 擁塞算法為hybla
#設置TCP 擁塞算法 net.ipv4.tcp_congestion_control=hybla
對于內核版高于于3.7.1的,我們可以開啟tcp_fastopen:
#開啟tcp_fastopen net.ipv4.tcp_fastopen= 3
Iptables相關
如非必須,關掉或卸載iptables防火墻,并阻止kernel加載iptables模塊。這些模塊會影響并發性能。
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的實現已經得到改進)。
感謝各位的閱讀,以上就是“Linux高并發踩過的坑及性能實例分析”的內容了,經過本文的學習后,相信大家對Linux高并發踩過的坑及性能實例分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。