遊戲 Lag 白皮書 › TCP 重傳的根本原因
中間設備移除 TCP 選項 Middlebox strips TCP options
原因 ID rt-sack-stripped · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
在含圖解與實驗的完整版中開啟卡片 →
部分防火牆或加速設備刪除或改寫 TCP 選項時,遺失多個封包後一個往返只能復原一個,或是視窗(一次可送出的量)變小,傳輸因此變慢。
為什麼 防火牆的「TCP 正規化」、老舊的加速設備移除 SACK、時間戳記、視窗縮放選項 → 於是 遺失多個封包時每個往返只能復原一個,視窗被限制在 64KB → 畫面上 每次遺失時定格的時間都長得多(沒有 SACK 就無法使用 RACK-TLP),恢復後快轉。更新檔這類大量傳輸也會變慢
- 症狀
- 定格, 快轉
- 因素
- 停滯, 延遲
- 誰會遇到
- 特定地區/電信業者, 整個伺服器
- 何時
- 一直都有
- 負責單位
- 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
- 基礎設施團隊要做的事
- 網路:關閉該設備的 TCP 正規化設定、也確認防火牆的序號隨機化、以兩端的封包擷取比較 SYN 中的選項。伺服器設備/OS:在 ss -ti 確認缺少 sack、wscale 標示的連線是否集中在特定路徑(Windows 電腦依設定可能不使用 ts,所以只少了 ts 可能是正常的)、確認伺服器的 net.ipv4.tcp_sack 為 1。
- 圖表上
- 一開始就一直偏高 · 沒有 SACK 就開始的復原次數(TcpExtTCPRenoRecovery)
- 查看位置
- 在 ss -ti 查看每條連線是否有 sack、wscale 標示,並查看 nstat 的 TcpExtTCPRenoRecovery(沒有 SACK 就開始的復原)與 TcpExtTCPSackRecovery 的比例、TcpExtTCPSACKDiscard(因前後對不上而丟棄的 SACK 區塊數)。可疑路徑則在兩端擷取 SYN,比較其中的選項(Wireshark 的 tcp.options.sack_perm 等)
- 符合的跡象
- 只有經過特定路徑或設備的連線缺少 sack、wscale,TcpExtTCPRenoRecovery 比重偏高。傳送端 SYN 中原有的 SACK 允許選項,在接收端收到的 SYN 中消失。原因是序號隨機化時,選項還在,但 TcpExtTCPSACKDiscard 增加
- 不符合的跡象
- 所有連線都缺少 sack 時,先確認伺服器的 net.ipv4.tcp_sack 值。選項完整、TcpExtTCPSACKDiscard 也沒有變化時,復原慢的原因在別處(「thin stream 復原緩慢」)
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
- 深入了解
- 即使選項還在,SACK 也可能失效。防火牆的序號隨機化(sequence randomization)只改標頭中的序號、沒有改 SACK 裡的序號時,傳送端會丟棄前後對不上的 SACK。2019 年 SACK 安全問題發生時,在伺服器設定 tcp_sack=0 關掉之後就忘了改回來,結果也一樣。
出處
- RFC 2018: TCP Selective Acknowledgment Options IETF
沒有 SACK、只靠累積 ACK 時,每個往返只能得知一個遺失的封包 - RFC 7323: TCP Extensions for High Performance IETF
沒有視窗縮放選項時,視窗最大為 2^16 = 64KiB - RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
RACK-TLP 必須使用 SACK - net/ipv4/tcp_output.c Linux kernel
Linux 的 TLP 只會在使用 SACK 的連線上排程 - IP Sysctl Linux kernel
tcp_sack 預設 1(開啟) - misc/ss.c iproute2
ss -ti 會依連線使用的選項顯示 ts、sack、wscale:傳送,接收 - tcp: limit payload size of sacked skbs Linux kernel
修正 2019 年 SACK 處理漏洞(CVE-2019-11477)的 commit - Linux and FreeBSD Kernel: Multiple TCP-based remote denial of service vulnerabilities (NFLX-2019-001) Netflix
當時建議的臨時對策是 tcp_sack=0(關閉 SACK 處理) - SNMP counter Linux kernel
TcpExtTCPRenoRecovery(沒有 SACK 就開始復原)、TcpExtTCPSackRecovery(以 SACK 開始復原)、TcpExtTCPSACKDiscard(無效的 SACK 區塊數) - Display Filter Reference: Transmission Control Protocol Wireshark
tcp.options.sack_perm(SYN 中的 SACK 允許選項)顯示篩選條件
相關原因
同一層:TCP 重傳的根本原因
同一症狀(定格)在其他層的原因
查看含圖解與實驗的完整版卡片