'「系統編程」你所不知道的TIME_WAIT(下)'

"
作者:大房
鏈接:https://mp.weixin.qq.com/s/mO-I7P2y9ERW7xp_l_85wQ


如果你沒有閱讀過上篇文章,可以點擊你所不知道的TIME_WAIT和CLOSE_WAIT(上)這裡閱讀,先閱讀上篇,搞清楚概念,再繼續今天的下篇吧。

「系統編程」你所不知道的TIME_WAIT和CLOSE_WAIT(上)

幾個問題

1. 請問我們所說連接池可以複用連接,是不是意味著,需要等到上個連接time wait結束後才能再次使用?

所謂連接池複用,複用的一定是活躍的連接,所謂活躍,第一表明連接池裡的連接都是ESTABLISHED的,第二,連接池做為上層應用,會有定時的心跳去保持連接的活躍性。既然連接都是活躍的,那就不存在有TIME_WAIT的概念了,在上篇裡也有提到,TIME_WAIT是在主動關閉連接的一方,在關閉連接後才進入的狀態。既然已經關閉了,那麼這條連接肯定已經不在連接池裡面了,即被連接池釋放了。

2. 想請問下,作為負載均衡的機器隨機端口使用完的情況下大量time_wait,不調整你文字裡說的那三個參數,有其他的更好的方案嗎?

第一,隨機端口使用完,你可以通過調整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成 net.ipv4.ip_local_port_range=1024 65535,保證你的負載均衡服務器至少可以使用6萬個隨機端口,也即可以有6萬的反向代理到後端的連接,可以支持每秒1000的併發(想一想,因為TIME_WAIT狀態會持續1分鐘後消失,所以一分鐘最多有6萬,每秒1000);如果這麼多端口都使用完了,也證明你應該加服務器了,或者,你的負載均衡服務器需要配置多個IP地址,或者,你的後端服務器需要監聽更多的端口和配置更多的IP(想一下socket的五元組)

第二,大量的TIME_WAIT,多大量?如果是幾千個,其實不用擔心,因為這個內存和CPU的消耗有一些,但是是可以忽略的。

第三,如果真的量很大,上萬上萬的那種,可以考慮,讓後端的服務器主動關閉連接,如果後端服務器沒有外網的連接只有負載均衡服務器的連接(主要是沒有NAT網絡的連接),可以在後端服務器上配置tw_recycle,然後同時,在負載均衡服務器上,配置tw_reuse。參見本文後面的解釋。

3. 如果想深入的學習一下網絡方面的知識,有什麼推薦的?

學習網絡比學一門編程語言“難”很多。所謂難,其實,是因為需要花很多的時間投入。我自己不算精通,只能說入門和理解。基本書可以推薦:《TCP/IP 協議詳解》,必讀;《TCP/IP高效編程:改善網絡程序的44個技巧》,必讀;《Unix環境高級編程》,必讀;《Unix網絡編程:卷一》,我只讀過卷一;另外,還需要熟悉一下網絡工具,tcpdump以及wireshark,我的notes裡有一個一站式學習Wireshark:https://github.com/dafang/notebook/issues/114,也值得一讀。有了這些積累,可能就是一些實踐以及碎片化的學習和積累了。


TIME_WAIT很多,可怕嗎

回到正題,如果你通過 ss -tan state time-wait | wc -l 發現,系統中有很多TIME_WAIT,很多人都會緊張。多少算多呢?幾百幾千?如果是這個量級,其實真的沒必要緊張。第一,這個量級,因為TIME_WAIT所佔用的內存很少很少;因為記錄和尋找可用的local port所消耗的CPU也基本可以忽略。

會佔用內存嗎?當然!任何你可以看到的數據,內核裡都需要有相關的數據結構來保存這個數據啊。一條Socket處於TIME_WAIT狀態,它也是一條“存在”的socket,內核裡也需要有保持它的數據,由於內核需要保存這些數據,必然,會佔用一定的內存:

1:內核裡有保存所有連接的一個hash table,這個hash table裡面既包含TIME_WAIT狀態的連接,也包含其他狀態的連接。主要用於有新的數據到來的時候,從這個hash table裡快速找到這條連接。不同的內核對這個hash table的大小設置不同,你可以通過dmesg命令去找到你的內核設置的大小:

"
作者:大房
鏈接:https://mp.weixin.qq.com/s/mO-I7P2y9ERW7xp_l_85wQ


如果你沒有閱讀過上篇文章,可以點擊你所不知道的TIME_WAIT和CLOSE_WAIT(上)這裡閱讀,先閱讀上篇,搞清楚概念,再繼續今天的下篇吧。

「系統編程」你所不知道的TIME_WAIT和CLOSE_WAIT(上)

幾個問題

1. 請問我們所說連接池可以複用連接,是不是意味著,需要等到上個連接time wait結束後才能再次使用?

所謂連接池複用,複用的一定是活躍的連接,所謂活躍,第一表明連接池裡的連接都是ESTABLISHED的,第二,連接池做為上層應用,會有定時的心跳去保持連接的活躍性。既然連接都是活躍的,那就不存在有TIME_WAIT的概念了,在上篇裡也有提到,TIME_WAIT是在主動關閉連接的一方,在關閉連接後才進入的狀態。既然已經關閉了,那麼這條連接肯定已經不在連接池裡面了,即被連接池釋放了。

2. 想請問下,作為負載均衡的機器隨機端口使用完的情況下大量time_wait,不調整你文字裡說的那三個參數,有其他的更好的方案嗎?

第一,隨機端口使用完,你可以通過調整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成 net.ipv4.ip_local_port_range=1024 65535,保證你的負載均衡服務器至少可以使用6萬個隨機端口,也即可以有6萬的反向代理到後端的連接,可以支持每秒1000的併發(想一想,因為TIME_WAIT狀態會持續1分鐘後消失,所以一分鐘最多有6萬,每秒1000);如果這麼多端口都使用完了,也證明你應該加服務器了,或者,你的負載均衡服務器需要配置多個IP地址,或者,你的後端服務器需要監聽更多的端口和配置更多的IP(想一下socket的五元組)

第二,大量的TIME_WAIT,多大量?如果是幾千個,其實不用擔心,因為這個內存和CPU的消耗有一些,但是是可以忽略的。

第三,如果真的量很大,上萬上萬的那種,可以考慮,讓後端的服務器主動關閉連接,如果後端服務器沒有外網的連接只有負載均衡服務器的連接(主要是沒有NAT網絡的連接),可以在後端服務器上配置tw_recycle,然後同時,在負載均衡服務器上,配置tw_reuse。參見本文後面的解釋。

3. 如果想深入的學習一下網絡方面的知識,有什麼推薦的?

學習網絡比學一門編程語言“難”很多。所謂難,其實,是因為需要花很多的時間投入。我自己不算精通,只能說入門和理解。基本書可以推薦:《TCP/IP 協議詳解》,必讀;《TCP/IP高效編程:改善網絡程序的44個技巧》,必讀;《Unix環境高級編程》,必讀;《Unix網絡編程:卷一》,我只讀過卷一;另外,還需要熟悉一下網絡工具,tcpdump以及wireshark,我的notes裡有一個一站式學習Wireshark:https://github.com/dafang/notebook/issues/114,也值得一讀。有了這些積累,可能就是一些實踐以及碎片化的學習和積累了。


TIME_WAIT很多,可怕嗎

回到正題,如果你通過 ss -tan state time-wait | wc -l 發現,系統中有很多TIME_WAIT,很多人都會緊張。多少算多呢?幾百幾千?如果是這個量級,其實真的沒必要緊張。第一,這個量級,因為TIME_WAIT所佔用的內存很少很少;因為記錄和尋找可用的local port所消耗的CPU也基本可以忽略。

會佔用內存嗎?當然!任何你可以看到的數據,內核裡都需要有相關的數據結構來保存這個數據啊。一條Socket處於TIME_WAIT狀態,它也是一條“存在”的socket,內核裡也需要有保持它的數據,由於內核需要保存這些數據,必然,會佔用一定的內存:

1:內核裡有保存所有連接的一個hash table,這個hash table裡面既包含TIME_WAIT狀態的連接,也包含其他狀態的連接。主要用於有新的數據到來的時候,從這個hash table裡快速找到這條連接。不同的內核對這個hash table的大小設置不同,你可以通過dmesg命令去找到你的內核設置的大小:

「系統編程」你所不知道的TIME_WAIT(下)

2:還有一個hash table用來保存所有的bound ports,主要用於可以快速的找到一個可用的端口或者隨機端口:

"
作者:大房
鏈接:https://mp.weixin.qq.com/s/mO-I7P2y9ERW7xp_l_85wQ


如果你沒有閱讀過上篇文章,可以點擊你所不知道的TIME_WAIT和CLOSE_WAIT(上)這裡閱讀,先閱讀上篇,搞清楚概念,再繼續今天的下篇吧。

「系統編程」你所不知道的TIME_WAIT和CLOSE_WAIT(上)

幾個問題

1. 請問我們所說連接池可以複用連接,是不是意味著,需要等到上個連接time wait結束後才能再次使用?

所謂連接池複用,複用的一定是活躍的連接,所謂活躍,第一表明連接池裡的連接都是ESTABLISHED的,第二,連接池做為上層應用,會有定時的心跳去保持連接的活躍性。既然連接都是活躍的,那就不存在有TIME_WAIT的概念了,在上篇裡也有提到,TIME_WAIT是在主動關閉連接的一方,在關閉連接後才進入的狀態。既然已經關閉了,那麼這條連接肯定已經不在連接池裡面了,即被連接池釋放了。

2. 想請問下,作為負載均衡的機器隨機端口使用完的情況下大量time_wait,不調整你文字裡說的那三個參數,有其他的更好的方案嗎?

第一,隨機端口使用完,你可以通過調整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成 net.ipv4.ip_local_port_range=1024 65535,保證你的負載均衡服務器至少可以使用6萬個隨機端口,也即可以有6萬的反向代理到後端的連接,可以支持每秒1000的併發(想一想,因為TIME_WAIT狀態會持續1分鐘後消失,所以一分鐘最多有6萬,每秒1000);如果這麼多端口都使用完了,也證明你應該加服務器了,或者,你的負載均衡服務器需要配置多個IP地址,或者,你的後端服務器需要監聽更多的端口和配置更多的IP(想一下socket的五元組)

第二,大量的TIME_WAIT,多大量?如果是幾千個,其實不用擔心,因為這個內存和CPU的消耗有一些,但是是可以忽略的。

第三,如果真的量很大,上萬上萬的那種,可以考慮,讓後端的服務器主動關閉連接,如果後端服務器沒有外網的連接只有負載均衡服務器的連接(主要是沒有NAT網絡的連接),可以在後端服務器上配置tw_recycle,然後同時,在負載均衡服務器上,配置tw_reuse。參見本文後面的解釋。

3. 如果想深入的學習一下網絡方面的知識,有什麼推薦的?

學習網絡比學一門編程語言“難”很多。所謂難,其實,是因為需要花很多的時間投入。我自己不算精通,只能說入門和理解。基本書可以推薦:《TCP/IP 協議詳解》,必讀;《TCP/IP高效編程:改善網絡程序的44個技巧》,必讀;《Unix環境高級編程》,必讀;《Unix網絡編程:卷一》,我只讀過卷一;另外,還需要熟悉一下網絡工具,tcpdump以及wireshark,我的notes裡有一個一站式學習Wireshark:https://github.com/dafang/notebook/issues/114,也值得一讀。有了這些積累,可能就是一些實踐以及碎片化的學習和積累了。


TIME_WAIT很多,可怕嗎

回到正題,如果你通過 ss -tan state time-wait | wc -l 發現,系統中有很多TIME_WAIT,很多人都會緊張。多少算多呢?幾百幾千?如果是這個量級,其實真的沒必要緊張。第一,這個量級,因為TIME_WAIT所佔用的內存很少很少;因為記錄和尋找可用的local port所消耗的CPU也基本可以忽略。

會佔用內存嗎?當然!任何你可以看到的數據,內核裡都需要有相關的數據結構來保存這個數據啊。一條Socket處於TIME_WAIT狀態,它也是一條“存在”的socket,內核裡也需要有保持它的數據,由於內核需要保存這些數據,必然,會佔用一定的內存:

1:內核裡有保存所有連接的一個hash table,這個hash table裡面既包含TIME_WAIT狀態的連接,也包含其他狀態的連接。主要用於有新的數據到來的時候,從這個hash table裡快速找到這條連接。不同的內核對這個hash table的大小設置不同,你可以通過dmesg命令去找到你的內核設置的大小:

「系統編程」你所不知道的TIME_WAIT(下)

2:還有一個hash table用來保存所有的bound ports,主要用於可以快速的找到一個可用的端口或者隨機端口:

「系統編程」你所不知道的TIME_WAIT(下)

會消耗CPU嗎?當然!每次找到一個隨機端口,還是需要遍歷一遍bound ports的吧,這必然需要一些CPU時間。

TIME_WAIT很多,既佔內存又消耗CPU,這也是為什麼很多人,看到TIME_WAIT很多,就蠢蠢欲動的想去幹掉他們。其實,如果你再進一步去研究,1萬條TIME_WAIT的連接,也就多消耗1M左右的內存,對現代的很多服務器,已經不算什麼了。至於CPU,能減少它當然更好,但是不至於因為1萬多個hash item就擔憂。

如果,你真的想去調優,還是需要搞清楚別人的調優建議,以及調優參數背後的意義!

TIME_WAIT調優,需要理解的參數

在具體的圖例之前,我們還是先解析一下相關的幾個參數存在的意義。

net.ipv4.tcp_timestamps

RFC 1323 在 TCP Reliability一節裡,引入了timestamp的TCP option,兩個4字節的時間戳字段,其中第一個4字節字段用來保存發送該數據包的時間,第二個4字節字段用來保存最近一次接收對方發送到數據的時間。有了這兩個時間字段,也就有了後續優化的餘地。

tcp_tw_reuse 和 tcp_tw_recycle就依賴這些時間字段。


net.ipv4.tcp_tw_reuse

字面意思,reuse TIME_WAIT狀態的連接。

時刻記住一條socket連接,就是那個五元組,出現TIME_WAIT狀態的連接,一定出現在主動關閉連接的一方。所以,當主動關閉連接的一方,再次向對方發起連接請求的時候(例如,客戶端關閉連接,客戶端再次連接服務端,此時可以複用了;負載均衡服務器,主動關閉後端的連接,當有新的HTTP請求,負載均衡服務器再次連接後端服務器,此時也可以複用),可以複用TIME_WAIT狀態的連接。

通過字面解釋,以及例子說明,你看到了,tcp_tw_reuse應用的場景:某一方,需要不斷的通過“短連接”連接其他服務器,總是自己先關閉連接(TIME_WAIT在自己這方),關閉後又不斷的重新連接對方。

那麼,當連接被複用了之後,延遲或者重發的數據包到達,新的連接怎麼判斷,到達的數據是屬於複用後的連接,還是複用前的連接呢?那就需要依賴前面提到的兩個時間字段了。複用連接後,這條連接的時間被更新為當前的時間,當延遲的數據達到,延遲數據的時間是小於新連接的時間,所以,內核可以通過時間判斷出,延遲的數據可以安全的丟棄掉了。

這個配置,依賴於連接雙方,同時對timestamps的支持。同時,這個配置,僅僅影響outbound連接,即做為客戶端的角色,連接服務端[connect(dest_ip, dest_port)]時複用TIME_WAIT的socket。


net.ipv4.tcp_tw_recycle

字面意思,銷燬掉 TIME_WAIT。

當開啟了這個配置後,內核會快速的回收處於TIME_WAIT狀態的socket連接。多快?不再是2MSL,而是一個RTO(retransmission timeout,數據包重傳的timeout時間)的時間,這個時間根據RTT動態計算出來,但是遠小於2MSL。

有了這個配置,還是需要保障 丟失重傳或者延遲的數據包,不會被新的連接(注意,這裡不再是複用了,而是之前處於TIME_WAIT狀態的連接已經被destroy掉了,新的連接,剛好是和某一個被destroy掉的連接使用了相同的五元組而已)所錯誤的接收。在啟用該配置,當一個socket連接進入TIME_WAIT狀態後,內核裡會記錄包括該socket連接對應的五元組中的對方IP等在內的一些統計數據,當然也包括從該對方IP所接收到的最近的一次數據包時間。當有新的數據包到達,只要時間晚於內核記錄的這個時間,數據包都會被統統的丟掉。

這個配置,依賴於連接雙方對timestamps的支持。同時,這個配置,主要影響到了inbound的連接(對outbound的連接也有影響,但是不是複用),即做為服務端角色,客戶端連進來,服務端主動關閉了連接,TIME_WAIT狀態的socket處於服務端,服務端快速的回收該狀態的連接。

由此,如果客戶端處於NAT的網絡(多個客戶端,同一個IP出口的網絡環境),如果配置了tw_recycle,就可能在一個RTO的時間內,只能有一個客戶端和自己連接成功(不同的客戶端發包的時間不一致,造成服務端直接把數據包丟棄掉)。

我儘量嘗試用文字解釋清楚,但是,來點案例和圖示,應該有助於我們徹底理解。我們來看這樣一個網絡情況:


"
作者:大房
鏈接:https://mp.weixin.qq.com/s/mO-I7P2y9ERW7xp_l_85wQ


如果你沒有閱讀過上篇文章,可以點擊你所不知道的TIME_WAIT和CLOSE_WAIT(上)這裡閱讀,先閱讀上篇,搞清楚概念,再繼續今天的下篇吧。

「系統編程」你所不知道的TIME_WAIT和CLOSE_WAIT(上)

幾個問題

1. 請問我們所說連接池可以複用連接,是不是意味著,需要等到上個連接time wait結束後才能再次使用?

所謂連接池複用,複用的一定是活躍的連接,所謂活躍,第一表明連接池裡的連接都是ESTABLISHED的,第二,連接池做為上層應用,會有定時的心跳去保持連接的活躍性。既然連接都是活躍的,那就不存在有TIME_WAIT的概念了,在上篇裡也有提到,TIME_WAIT是在主動關閉連接的一方,在關閉連接後才進入的狀態。既然已經關閉了,那麼這條連接肯定已經不在連接池裡面了,即被連接池釋放了。

2. 想請問下,作為負載均衡的機器隨機端口使用完的情況下大量time_wait,不調整你文字裡說的那三個參數,有其他的更好的方案嗎?

第一,隨機端口使用完,你可以通過調整/etc/sysctl.conf下的net.ipv4.ip_local_port_range配置,至少修改成 net.ipv4.ip_local_port_range=1024 65535,保證你的負載均衡服務器至少可以使用6萬個隨機端口,也即可以有6萬的反向代理到後端的連接,可以支持每秒1000的併發(想一想,因為TIME_WAIT狀態會持續1分鐘後消失,所以一分鐘最多有6萬,每秒1000);如果這麼多端口都使用完了,也證明你應該加服務器了,或者,你的負載均衡服務器需要配置多個IP地址,或者,你的後端服務器需要監聽更多的端口和配置更多的IP(想一下socket的五元組)

第二,大量的TIME_WAIT,多大量?如果是幾千個,其實不用擔心,因為這個內存和CPU的消耗有一些,但是是可以忽略的。

第三,如果真的量很大,上萬上萬的那種,可以考慮,讓後端的服務器主動關閉連接,如果後端服務器沒有外網的連接只有負載均衡服務器的連接(主要是沒有NAT網絡的連接),可以在後端服務器上配置tw_recycle,然後同時,在負載均衡服務器上,配置tw_reuse。參見本文後面的解釋。

3. 如果想深入的學習一下網絡方面的知識,有什麼推薦的?

學習網絡比學一門編程語言“難”很多。所謂難,其實,是因為需要花很多的時間投入。我自己不算精通,只能說入門和理解。基本書可以推薦:《TCP/IP 協議詳解》,必讀;《TCP/IP高效編程:改善網絡程序的44個技巧》,必讀;《Unix環境高級編程》,必讀;《Unix網絡編程:卷一》,我只讀過卷一;另外,還需要熟悉一下網絡工具,tcpdump以及wireshark,我的notes裡有一個一站式學習Wireshark:https://github.com/dafang/notebook/issues/114,也值得一讀。有了這些積累,可能就是一些實踐以及碎片化的學習和積累了。


TIME_WAIT很多,可怕嗎

回到正題,如果你通過 ss -tan state time-wait | wc -l 發現,系統中有很多TIME_WAIT,很多人都會緊張。多少算多呢?幾百幾千?如果是這個量級,其實真的沒必要緊張。第一,這個量級,因為TIME_WAIT所佔用的內存很少很少;因為記錄和尋找可用的local port所消耗的CPU也基本可以忽略。

會佔用內存嗎?當然!任何你可以看到的數據,內核裡都需要有相關的數據結構來保存這個數據啊。一條Socket處於TIME_WAIT狀態,它也是一條“存在”的socket,內核裡也需要有保持它的數據,由於內核需要保存這些數據,必然,會佔用一定的內存:

1:內核裡有保存所有連接的一個hash table,這個hash table裡面既包含TIME_WAIT狀態的連接,也包含其他狀態的連接。主要用於有新的數據到來的時候,從這個hash table裡快速找到這條連接。不同的內核對這個hash table的大小設置不同,你可以通過dmesg命令去找到你的內核設置的大小:

「系統編程」你所不知道的TIME_WAIT(下)

2:還有一個hash table用來保存所有的bound ports,主要用於可以快速的找到一個可用的端口或者隨機端口:

「系統編程」你所不知道的TIME_WAIT(下)

會消耗CPU嗎?當然!每次找到一個隨機端口,還是需要遍歷一遍bound ports的吧,這必然需要一些CPU時間。

TIME_WAIT很多,既佔內存又消耗CPU,這也是為什麼很多人,看到TIME_WAIT很多,就蠢蠢欲動的想去幹掉他們。其實,如果你再進一步去研究,1萬條TIME_WAIT的連接,也就多消耗1M左右的內存,對現代的很多服務器,已經不算什麼了。至於CPU,能減少它當然更好,但是不至於因為1萬多個hash item就擔憂。

如果,你真的想去調優,還是需要搞清楚別人的調優建議,以及調優參數背後的意義!

TIME_WAIT調優,需要理解的參數

在具體的圖例之前,我們還是先解析一下相關的幾個參數存在的意義。

net.ipv4.tcp_timestamps

RFC 1323 在 TCP Reliability一節裡,引入了timestamp的TCP option,兩個4字節的時間戳字段,其中第一個4字節字段用來保存發送該數據包的時間,第二個4字節字段用來保存最近一次接收對方發送到數據的時間。有了這兩個時間字段,也就有了後續優化的餘地。

tcp_tw_reuse 和 tcp_tw_recycle就依賴這些時間字段。


net.ipv4.tcp_tw_reuse

字面意思,reuse TIME_WAIT狀態的連接。

時刻記住一條socket連接,就是那個五元組,出現TIME_WAIT狀態的連接,一定出現在主動關閉連接的一方。所以,當主動關閉連接的一方,再次向對方發起連接請求的時候(例如,客戶端關閉連接,客戶端再次連接服務端,此時可以複用了;負載均衡服務器,主動關閉後端的連接,當有新的HTTP請求,負載均衡服務器再次連接後端服務器,此時也可以複用),可以複用TIME_WAIT狀態的連接。

通過字面解釋,以及例子說明,你看到了,tcp_tw_reuse應用的場景:某一方,需要不斷的通過“短連接”連接其他服務器,總是自己先關閉連接(TIME_WAIT在自己這方),關閉後又不斷的重新連接對方。

那麼,當連接被複用了之後,延遲或者重發的數據包到達,新的連接怎麼判斷,到達的數據是屬於複用後的連接,還是複用前的連接呢?那就需要依賴前面提到的兩個時間字段了。複用連接後,這條連接的時間被更新為當前的時間,當延遲的數據達到,延遲數據的時間是小於新連接的時間,所以,內核可以通過時間判斷出,延遲的數據可以安全的丟棄掉了。

這個配置,依賴於連接雙方,同時對timestamps的支持。同時,這個配置,僅僅影響outbound連接,即做為客戶端的角色,連接服務端[connect(dest_ip, dest_port)]時複用TIME_WAIT的socket。


net.ipv4.tcp_tw_recycle

字面意思,銷燬掉 TIME_WAIT。

當開啟了這個配置後,內核會快速的回收處於TIME_WAIT狀態的socket連接。多快?不再是2MSL,而是一個RTO(retransmission timeout,數據包重傳的timeout時間)的時間,這個時間根據RTT動態計算出來,但是遠小於2MSL。

有了這個配置,還是需要保障 丟失重傳或者延遲的數據包,不會被新的連接(注意,這裡不再是複用了,而是之前處於TIME_WAIT狀態的連接已經被destroy掉了,新的連接,剛好是和某一個被destroy掉的連接使用了相同的五元組而已)所錯誤的接收。在啟用該配置,當一個socket連接進入TIME_WAIT狀態後,內核裡會記錄包括該socket連接對應的五元組中的對方IP等在內的一些統計數據,當然也包括從該對方IP所接收到的最近的一次數據包時間。當有新的數據包到達,只要時間晚於內核記錄的這個時間,數據包都會被統統的丟掉。

這個配置,依賴於連接雙方對timestamps的支持。同時,這個配置,主要影響到了inbound的連接(對outbound的連接也有影響,但是不是複用),即做為服務端角色,客戶端連進來,服務端主動關閉了連接,TIME_WAIT狀態的socket處於服務端,服務端快速的回收該狀態的連接。

由此,如果客戶端處於NAT的網絡(多個客戶端,同一個IP出口的網絡環境),如果配置了tw_recycle,就可能在一個RTO的時間內,只能有一個客戶端和自己連接成功(不同的客戶端發包的時間不一致,造成服務端直接把數據包丟棄掉)。

我儘量嘗試用文字解釋清楚,但是,來點案例和圖示,應該有助於我們徹底理解。我們來看這樣一個網絡情況:


「系統編程」你所不知道的TIME_WAIT(下)


1:客戶端IP地址為:180.172.35.150,我們可以認為是瀏覽器

2:負載均衡有兩個IP,外網IP地址為 115.29.253.156,內網地址為10.162.74.10;外網地址監聽80端口

3:負載均衡背後有兩臺Web服務器,一臺IP地址為 10.162.74.43,監聽80端口;另一臺為 10.162.74.44,監聽 80 端口

4:Web服務器會連接數據服務器,IP地址為 10.162.74.45,監聽 3306 端口

這種簡單的架構下,我們來看看,在不同的情況下,我們今天談論的tw_reuse/tw_recycle對網絡連接的影響。

先做個假定:

1:客戶端通過HTTP/1.1連接負載均衡,也就是說,HTTP協議中Connection為keep-alive,所以我們假定,客戶端 對 負載均衡服務器 的socket連接,客戶端會斷開連接,所以,TIME_WAIT出現在客戶端

2:Web服務器和MySQL服務器的連接,我們假定,Web服務器上的程序在連接結束的時候,調用close操作關閉socket資源連接,所以,TIME_WAIT出現在 Web 服務器端。

那麼,在這種假定下:

1:Web服務器上,肯定可以配置開啟的配置:tcp_tw_reuse;如果Web服務器有很多連向DB服務器的連接,可以保證socket連接的複用。

2:那麼,負載均衡服務器和Web服務器,誰先關閉連接,則決定了我們怎麼配置tcp_tw_reuse/tcp_tw_recycle了

方案一:負載均衡服務器 首先關閉連接

在這種情況下,因為負載均衡服務器對Web服務器的連接,TIME_WAIT大都出現在負載均衡服務器上,所以,在負載均衡服務器上的配置如下:

1:net.ipv4.tcp_tw_reuse = 1 //儘量複用連接

2:net.ipv4.tcp_tw_recycle = 0 //不能保證客戶端不在NAT的網絡啊

在Web服務器上的配置為:

1:net.ipv4.tcp_tw_reuse = 1 //這個配置主要影響的是Web服務器到DB服務器的連接複用

2:net.ipv4.tcp_tw_recycle: 設置成1和0都沒有任何意義。想一想,在負載均衡和它的連接中,它是服務端,但是TIME_WAIT出現在負載均衡服務器上;它和DB的連接,它是客戶端,recycle對它並沒有什麼影響,關鍵是reuse

方案二:Web服務器首先關閉來自負載均衡服務器的連接

在這種情況下,Web服務器變成TIME_WAIT的重災區。負載均衡對Web服務器的連接,由Web服務器首先關閉連接,TIME_WAIT出現在Web服務器上;Web服務器對DB服務器的連接,由Web服務器關閉連接,TIME_WAIT也出現在它身上,此時,負載均衡服務器上的配置:

1:net.ipv4.tcp_tw_reuse:0 或者 1 都行,都沒有實際意義

2:net.ipv4.tcp_tw_recycle=0 //一定是關閉recycle

在Web服務器上的配置:

1:net.ipv4.tcp_tw_reuse = 1 //這個配置主要影響的是Web服務器到DB服務器的連接複用

2:net.ipv4.tcp_tw_recycle=1 //由於在負載均衡和Web服務器之間並沒有NAT的網絡,可以考慮開啟recycle,加速由於負載均衡和Web服務器之間的連接造成的大量TIME_WAIT

"

相關推薦

推薦中...