首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

TCP 服務端收到 SYN 不回 SYN-ACK 根因分析:tcp_tw_recycle 與 NAT 環境的致命交互

     編輯:PHP 相關知識

TCP 服務端收到 SYN 不回 SYN-ACK 根因分析:tcp_tw_recycle 與 NAT 環境的致命交互

線上故障:客戶端 telnet server_ip port 一直卡住,服務端抓包見到 SYN 到達但無 SYN-ACK 回應,連接數正常,無明顯錯誤日誌。關閉 net.ipv4.tcp_tw_recycle 後瞬間恢復。本文深度剖析該經典故障的內核機制、觸發條件與排查路徑。

故障現象還原

  • 服務端監聽端口正常(ss -lntp 可見)
  • 客戶端發起 TCP 連接,發送 SYN
  • 服務端網卡收到 SYN(tcpdump -i eth0 port 80 可見)
  • 服務端不發送 SYN-ACK,客戶端超時重傳 SYN
  • netstat -s 顯示:packets rejects in established connections because of timestamp 計數器持續增長

根因:tcp_tw_recycle + NAT + 時間戳 = 合法 SYN 被丟棄

內核機制還原(net/ipv4/tcp_input.c → tcp_v4_conn_request())

// 簡化邏輯
if (tcp_tw_recycle && tcp_timestamps) {
    struct tcp_metrics_block *tm = tcp_get_metrics_req(sk, req);
    if (tm && tm->tcpm_ts) {
        // PAWS 檢查:新包時間戳 < 記錄時間戳 → 視為舊包丟棄
        if ((s32)(req->ts_recent - tm->tcpm_ts) < 0) {
            NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRFC1323PAWSREJECT);
            return; // 直接丟棄,不回 SYN-ACK,不進入 SYN_RECV
        }
    }
}

為什麼 NAT 環境必觸發?

  1. 多客戶端共享 NAT 公網 IP(企業出口、雲廠商 SNAT、容器網橋)
  2. 不同客戶端機器時鐘不同步(有的快、有的慢、有的漂移)
  3. 客戶端 A 先連接,時間戳 TS_A 被服務端記錄在 tcp_metrics_block
  4. 客戶端 B 後連接,時間戳 TS_B < TS_A(時鐘較慢)
  5. 服務端判定 B 的 SYN 時間戳「倒退」→ PAWS 拒絕 → 丟棄 SYN
  6. 結果:B 永遠無法建立連接,表現為「服務端不回 SYN-ACK」
  7. 驗證與排查三步法

    1. 確認參數狀態:
      sysctl net.ipv4.tcp_tw_recycle net.ipv4.tcp_timestamps
      # 輸出均為 1 即觸發條件滿足
    2. 觀察拒絕計數器:
      netstat -s | grep -i "timestamp\|paws"
      # 關鍵指標:packets rejects in established connections because of timestamp
      # 或:TCPRFC1323PAWSReject
    3. 抓包確認時間戳倒退:
      方案執行命令生效範圍副作用推薦指數
      關閉 tcp_tw_recyclesysctl -w net.ipv4.tcp_tw_recycle=0
      持久化:/etc/sysctl.d/99-tcp.conf全局TIME_WAIT 回收變慢(60s),內存微增⭐⭐⭐⭐⭐ (首選) 關閉 tcp_timestampssysctl -w net.ipv4.tcp_timestamps=0全局失去 PAWS 保護、RTT 測量不準、tw_reuse 失效、窗口縮放受限⭐⭐ (不推薦) 開啟 tcp_tw_reusesysctl -w net.ipv4.tcp_tw_reuse=1僅客戶端出站無副作用,緩解客戶端端口壓力⭐⭐⭐⭐ (配套推薦)

      為什麼不建議關閉 tcp_timestamps?

      • tcp_tw_recycle 依賴 tcp_timestamps 生效,關閉 timestamps 會導致 recycle 失效(但也同時失去了 PAWS 保護)
      • tcp_tw_reuse 同樣依賴 timestamps,關閉後客戶端無法快速復用端口
      • 時間戳選項還支撐:RTT 精準測量、擴展窗口(>64KB)、SACK、FACK 等核心性能特性

      結論:保留 timestamps,關閉 tw_recycle,開啟 tw_reuse 是最優組合。

      負載均衡器特殊情況

      • LVS (DR/NAT/TUN)、HAProxy、Nginx Stream、云廠商 SLB/CLB
      • 大多數四層負載均衡會剝離 TCP 選項(含時間戳)轉發給後端
      • 後端服務器收到無時間戳的 SYN,即使開啟 tw_recycle 也無法觸發 PAWS(無時間戳不檢查)
      • 但:若負載均衡保留時間戳(如某些 TCP 透傳模式),後端依然會中招

      完整修復驗證清單

      1. 修改 /etc/sysctl.d/99-tcp-fix.conf:
        net.ipv4.tcp_tw_recycle = 0
        net.ipv4.tcp_tw_reuse = 1
        net.ipv4.tcp_timestamps = 1
      2. sysctl --system 生效
      3. 客戶端並發測試:for i in {1..100}; do telnet server_ip port & done
      4. 觀察 netstat -s | grep -i paws 計數器不再增長
      5. 服務端日誌無連接報錯,業務恢復正常

      舉一反三:同類參數風險清單

      參數風險場景建議
      tcp_tw_recycleNAT 環境導致合法連接被丟棄生產環境永久關閉
      tcp_abort_on_overflowAccept 隊列滿直接發 RST,客戶端以為連接失敗實則服務端過載關閉,配合 somaxconn/backlog 擴容
      tcp_syncookiesSYN Flood 時啟用,但會導致某些舊設備兼容性問題保持開啟(默認),監控 syncookies 計數器
      tcp_timestamps關閉後失去多項 TCP 增強特性永久開啟

      這個故障是「內核參數優化不當遇上 NAT 普遍部署」的教科書級案例。它警示我們:任何修改 TCP 協議棧行為的參數,必須在包含 NAT、負載均衡、容器網絡的完整鏈路環境下全鏈路壓測驗證,單機測試毫無意義。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved