調整 net.ipv4.tcp_tw_recycle 造成的故障


  • 背景

在 nat 的網絡環境訪問服務器時會有不定時連接超時的問題

  • 原因

出現此問題,可能是系統參數設置問題,即以下兩個參數都設置為 1

1
2
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 1

RFC1323中有如下一段描述:

An additional mechanism could be added to the TCP, a per-host cache of the last timestamp received from any connection. This value could then be used in the PAWS mechanism to reject old duplicate segments from earlier incarnations of the connection, if the timestamp clock can be guaranteed to have ticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT together must be at least one tick of the sender’s timestamp clock. Such an extension is not part of the proposal of this RFC.

大概意思是說TCP有一種行為,可以緩存每個主機最新的時間戳,后續請求中如果時間戳小於緩存的時間戳,即視為無效,相應的數據包會被丟棄。

Linux是否啟用這種行為取決於tcp_timestamps和tcp_tw_recycle,因為tcp_timestamps缺省就是開啟的,所以當tcp_tw_recycle被開啟后,實際上這種行為就被激活了,當客戶端或服務端以NAT方式構建的時候就可能出現問題,下面以客戶端NAT為例來說明:

當多個客戶端通過NAT方式聯網並與服務端交互時,服務端看到的是同一個IP,也就是說對服務端而言這些客戶端實際上等同於一個,可惜由於這些客戶端的時間戳可能存在差異,於是乎從服務端的視角看,便可能出現時間戳錯亂的現象,進而直接導致時間戳小的數據包被丟棄。如果發生了此類問題,具體的表現通常是是客戶端明明發送的SYN,但服務端就是不響應ACK,我們可以通過下面命令來確認數據包不斷被丟棄的現象:

1
2
shell> netstat -s | grep timestamp
... packets rejects in established connections because of timestamp

安全起見,通常要禁止tcp_tw_recycle。說到這里,大家可能會想到另一種解決方案:把tcp_timestamps設置為0,tcp_tw_recycle設置為1,這樣不就可以魚與熊掌兼得了么?可惜一旦關閉了tcp_timestamps,那么即便打開了tcp_tw_recycle,也沒有效果。

引用地址: https://huoding.com/2012/01/19/142

  • 解決辦法

    解決的方法就是將這兩個參數修改為:

    1
    2
    net.ipv4.tcp_timestamps = 1
    net.ipv4.tcp_tw_recycle = 0
  • 遇到的問題

    本來修改完成后再次請求就沒有問題了,但如果是 docker 服務器的話,會發現容器中無法連接網絡!

    因為修改 net.ipv4.tcp_tw_recycle 影響的是 nat 相關,所以如果容器是以 nat 方式上網的話,就會造成影響

  • 解決辦法

    解決以上問題,需要先停掉 docker 主進程,然后修改參數,再啟動

-


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM