linux查看最大連接數,linux表示文件連接數,linux中連接數過多(TIME_WAIT/CLOSE_WAIT)讀這一篇就夠了
linux查看最大連接數,linux表示文件連接數,linux中連接數過多(TIME_WAIT/CLOSE_WAIT)讀這一篇就夠了
根據TCP/IP介紹,socket大概包含10個連接狀態。我們平常工作中遇到的,除了針對SYN的拒絕服務攻擊,如果有異常,大概率是TIME_WAIT和CLOSE_WAIT的問題。TIME_WAIT一般通過優化內核參數能夠解決;CLOSE_WAIT一般是由于程序編寫不合理造成的,更應該引起開發者注意。
TIME_WAIT
linux查看最大連接數?TIME_WAIT是主動關閉連接的一方保持的狀態,像nginx、爬蟲服務器,經常發生大量處于time_wait狀態的連接。TCP一般在主動關閉連接后,會等待2MS,然后徹底關閉連接。由于HTTP使用了TCP協議,所以在這些頻繁開關連接的服務器上,就積壓了非常多的TIME_WAIT狀態連接。
某些系統通過dmesg可以看到以下信息。
__ratelimit:?2170?callbacks?suppressedTCP:?time?wait?bucket?table?overflowTCP:?time?wait?bucket?table?overflowTCP:?time?wait?bucket?table?overflowTCP:?time?wait?bucket?table?overflow
ssh連接數限制?通過ss -s命令查看,可以看到timewait已經有2w個了。
ss?-sTotal:?174?(kernel?199)TCP:???20047?(estab?32,?closed?20000,?orphaned?4,?synrecv?0,?timewait?20000/0),?ports?10785
sysctl命令可以設置這些參數,如果想要重啟生效的話,加入/etc/sysctl.conf文件中。
linux文件屬性修改。#?修改閾值net.ipv4.tcp_max_tw_buckets?=?50000?#?表示開啟TCP連接中TIME-WAIT?sockets的快速回收net.ipv4.tcp_tw_reuse?=?1#啟用timewait?快速回收。這個一定要開啟,默認是關閉的。net.ipv4.tcp_tw_recycle=?1???#?修改系統默認的TIMEOUT時間,默認是60snet.ipv4.tcp_fin_timeout?=?10
測試參數的話,可以使用 sysctl -w net.ipv4.tcp_tw_reuse = 1 這樣的命令。如果是寫入進文件的,則使用sysctl -p生效。
CLOSE_WAIT
連接數和并發用戶數的關系、CLOSE_WAIT一般是由于對端主動關閉,而我方沒有正確處理的原因引起的。說白了,就是程序寫的有問題,屬于危害比較大的一種。
Socket中的11種狀態
1、客戶端獨有的:(1)SYN_SENT (2)FIN_WAIT1 (3)FIN_WAIT2 (4)CLOSING (5)TIME_WAIT 。2、服務器獨有的:(1)LISTEN (2)SYN_RCVD (3)CLOSE_WAIT (4)LAST_ACK 。3、共有的:(1)CLOSED (2)ESTABLISHED 。各個狀態的意義如下: LISTEN - 偵聽來自遠方TCP端口的連接請求; SYN-SENT -在發送連接請求后等待匹配的連接請求; SYN-RECEIVED- 在收到和發送一個連接請求后等待對連接請求的確認; ESTABLISHED- 代表一個打開的連接,數據可以傳送給用戶; FIN-WAIT-1 - 等待遠程TCP的連接中斷請求,或先前的連接中斷請求的確認;FIN-WAIT-2 - 從遠程TCP等待連接中斷請求; CLOSE-WAIT - 等待從本地用戶發來的連接中斷請求; CLOSING -等待遠程TCP對連接中斷的確認; LAST-ACK - 等待原來發向遠程TCP的連接中斷請求的確認; TIME-WAIT -等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認; CLOSED - 沒有任何連接狀態;
我們平常工作中遇到的,除了針對SYN的拒絕服務攻擊,大概率是TIME_WAIT和CLOSE_WAIT的問題。
TIME_WAIT一般通過優化內核參數能夠解決。
CLOSE_WAIT一般是由于程序編寫不合理造成的,更應該引起開發者注意。
1. time_wait狀態如何產生? 調用close()發起主動關閉的一方,在發送最后一個ACK之后會進入time_wait的狀態,也就說該發送方會保持2MSL時間之后才會回到初始狀態。MSL值得是數據包在網絡中的最大生存時間。產生這種結果使得這個TCP連接在2MSL連接等待期間,定義這個連接的四元組(客戶端IP地址和端口,服務端IP地址和端口號)不能被使用。
2.time_wait狀態產生的原因
1)為實現TCP全雙工連接的可靠釋放
假設發起主動關閉的一方(client)最后發送的ACK在網絡中丟失,由于TCP協議的重傳機制,執行被動關閉的一方(server)將會重發其FIN,在該FIN到達client之前,client必須維護這條連接狀態,也就說這條TCP連接所對應的資源(client方的local_ip,local_port)不能被立即釋放或重新分配,直到另一方重發的FIN達到之后,client重發ACK后,經過2MSL時間周期沒有再收到另一方的FIN之后,該TCP連接才能恢復初始的CLOSED狀態。如果主動關閉一方不維護這樣一個TIME_WAIT狀態,那么當被動關閉一方重發的FIN到達時,主動關閉一方的TCP傳輸層會用RST包響應對方,這會被對方認為是有錯誤發生,然而這事實上只是正常的關閉連接過程,并非異常。
2)為使舊的數據包在網絡因過期而消失
為說明這個問題,我們先假設TCP協議中不存在TIME_WAIT狀態的限制,再假設當前有一條TCP連接:(local_ip, local_port, remote_ip,remote_port),因某些原因,我們先關閉,接著很快以相同的四元組建立一條新連接。本文前面介紹過,TCP連接由四元組唯一標識,因此,在我們假設的情況中,TCP協議棧是無法區分前后兩條TCP連接的不同的,在它看來,這根本就是同一條連接,中間先釋放再建立的過程對其來說是“感知”不到的。這樣就可能發生這樣的情況:前一條TCP連接由local peer發送的數據到達remote peer后,會被該remot peer的TCP傳輸層當做當前TCP連接的正常數據接收并向上傳遞至應用層(而事實上,在我們假設的場景下,這些舊數據到達remote peer前,舊連接已斷開且一條由相同四元組構成的新TCP連接已建立,因此,這些舊數據是不應該被向上傳遞至應用層的),從而引起數據錯亂進而導致各種無法預知的詭異現象。作為一種可靠的傳輸協議,TCP必須在協議層面考慮并避免這種情況的發生,這正是TIME_WAIT狀態存在的第2個原因。
3)總結 具體而言,local peer主動調用close后,此時的TCP連接進入TIME_WAIT狀態,處于該狀態下的TCP連接不能立即以同樣的四元組建立新連接,即發起active close的那方占用的local port在TIME_WAIT期間不能再被重新分配。由于TIME_WAIT狀態持續時間為2MSL,這樣保證了舊TCP連接雙工鏈路中的舊數據包均因過期(超過MSL)而消失,此后,就可以用相同的四元組建立一條新連接而不會發生前后兩次連接數據錯亂的情況。
通過ss -s命令查看,可以看到timewait已經有2w個了。
如果想要重啟生效的話,加入/etc/sysctl.conf文件中。
net.ipv4.tcp_syncookies?=?1??#表示開啟SYN?Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉;net.ipv4.tcp_max_tw_buckets?=?50000?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?=?10??#?修改系統默認的TIMEOUT時間,默認是60s
使用sysctl -p生效
如果以上配置調優后性能還不理想,可繼續修改一下配置:
vi?/etc/sysctl.confnet.ipv4.tcp_keepalive_time?=?1200?#表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,改為20分鐘。net.ipv4.ip_local_port_range?=?1024?65000?#表示用于向外連接的端口范圍。缺省情況下很小:32768到61000,改為1024到65000。net.ipv4.tcp_max_syn_backlog?=?8192?#表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數。net.ipv4.tcp_max_tw_buckets?=?5000??#同時保持TIME_WAIT套接字的最大個數,超過這個數字那么該TIME_WAIT套接字將立刻被釋放#并在/var/log/message日志中打印警告信息(TCP:?time?wait?bucket?table?overflow)。#這個過多主要是消耗內存,單個TIME_WAIT占用內存非常小,但是多了就不好了,這個主要看內存以及你的服務器是否直接對外#默認為180000,改為5000。#對于Apache、Nginx等服務器,上幾行的參數可以很好地減少TIME_WAIT套接字數量#但是對于?Squid,效果卻不大。此項參數可以控制TIME_WAIT套接字的最大數量,避免Squid服務器被大量的TIME_WAIT套接字拖死。
CLOSE_WAIT
這種狀態的含義其實是表示在等待關閉。怎么理解呢?當對方close一個SOCKET后發送FIN報文給自己,你系統毫無疑問地會回應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是查看你是否還有數據發送給對方,如果沒有的話,那么你也就可以close這個SOCKET,發送FIN報文給對方,也即關閉連接。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連接。CLOSE_WAIT一般是由于對端主動關閉,而我方沒有正確處理的原因引起的。說白了,就是程序寫的有問題,屬于危害比較大的一種。代碼需要判斷socket,一旦讀到0,斷開連接,read返回負,檢查一下errno,如果不AGAIN,就斷開連接。