遊戲 Lag 白皮書 › TCP 重傳的根本原因
thin stream 復原緩慢 Thin streams fall back to RTO
原因 ID rt-thin · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
在含圖解與實驗的完整版中開啟卡片 →
像遊戲這樣零星送出小封包時,在湊齊「後續 3 個封包」之前 RTO 就先到了。同樣的遺失,停住的時間比大量傳輸長得多。
為什麼 封包間隔約 100ms,尚未收到 ACK 的封包(in-flight)沒有幾個 → 於是 要湊齊 3 個重複 ACK 得花 300ms 以上,所以 RTO(ping + 200ms)先觸發,連續遺失時每次加倍 → 畫面上 遺失一次就定格 0.3 秒左右,連重送的封包也遺失時,定格將近 1 秒後快轉
- 症狀
- 定格, 快轉
- 因素
- 遺失, 停滯
- 誰會遇到
- 只有我, 整個伺服器
- 何時
- 偶爾隨機發生
- 負責單位
- 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
- 遊戲開發團隊要做的事
- 伺服器:開啟 TCP_NODELAY(Nagle 開著時,RACK 沒有後續封包可用來判斷)、即時封包改用 UDP 加上自行實作的重傳。用戶端:開啟 TCP_NODELAY、即時封包用與伺服器相同的方式(UDP)傳送。
- 基礎設施團隊要做的事
- 使用 RACK-TLP(新版 Linux 預設)、用 tcp_thin_linear_timeouts 讓連續 RTO 不再加倍。
- 數值參考
- 封包間隔 100ms、ping 60ms 時,到快速重傳約需 360ms(直到後面 3 個封包抵達、確認回來為止),RTO 則約 260ms。使用 RACK 時,在下一個封包的確認回來的約 160ms 時就會立刻重送。封包間隔超過 200ms 時,RACK 也不會比 RTO 快。
- 圖表上
- 中斷後一次湧入 · 各連線的接收量、RTO 到期次數
- 查看位置
- 比較 nstat 的 TcpExtTCPTimeouts(RTO 到期)、TcpExtTCPFastRetrans(快速重傳)、TcpExtTCPLossProbes、TcpExtTCPLossProbeRecovery(TLP)增加量,並用 ss -ti 查看遊戲連線的 rto 與 backoff。也確認伺服器的 net.ipv4.tcp_recovery、tcp_early_retrans、tcp_sack 值
- 符合的跡象
- 重傳中 RTO 到期比快速重傳多,遊戲連線經常出現 backoff 大於 0(正在經歷 RTO)的情況。停住期間接收量為 0,復原後一次湧入
- 不符合的跡象
- 同一台伺服器的大量傳輸也同樣停住很久時,是與連線型態無關的遺失問題。集中在缺少 SACK 或時間戳記的連線時,是「中間設備移除 TCP 選項」
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
- 深入了解
- Linux 以前也有 thin stream 專用、收到 1 個重複 ACK 就重傳的選項(tcp_thin_dupack),但在 2017 年移除,現在由 RACK 取代這個角色。Nagle 開著時(TCP_NODELAY 關閉),等待遺失封包的確認期間也不會送出新封包,RACK 沒有後續封包可用來判斷,只能等到 RTO。
出處
- Thin-streams and TCP Linux kernel
像遊戲這樣零星傳送的 thin stream,快速重傳不太能發揮作用,只能依賴很長的逾時;判定基準為尚未收到 ACK 的封包(in-flight)未滿 4 個 - RFC 5681: TCP Congestion Control IETF
在第三個重複 ACK 時進行快速重傳 - RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
RACK 以較晚送出的封包已送達來判斷遺失,TLP 等待時間為 2·SRTT(未確認的封包只有一個時,再加上延遲 ACK 的餘裕) - include/net/tcp.h Linux kernel
TCP_RTO_MIN 200ms、thin stream 判定(in-flight 封包未滿 4 個)與線性重試 6 次 - tcp: remove thin_dupack feature Linux kernel
2017 年 1 月移除 thin_dupack(Linux 4.11),並說明由 RACK 取代其角色 - IP Sysctl Linux kernel
tcp_thin_linear_timeouts:thin stream 最多前 6 次重試不把 RTO 加倍(預設關閉) - tcp(7) — Linux manual page Linux man-pages
TCP_NODELAY 會關閉 Nagle 演算法 - net/ipv4/proc.c Linux kernel
nstat 顯示的計數器名稱 TCPTimeouts、TCPFastRetrans、TCPLossProbes、TCPLossProbeRecovery - net/ipv4/tcp_timer.c Linux kernel
TCPTimeouts 在重傳計時器(RTO)到期時增加 - SNMP counter Linux kernel
TcpExtTCPFastRetrans(不在 Loss 狀態時的重傳)、TcpExtTCPLossProbes(送出 TLP)、TcpExtTCPLossProbeRecovery(以 TLP 復原遺失) - ss(8) — Linux manual page iproute2
ss -i 的 rto(ms)、backoff(RTO 加倍的次數)
相關原因
同一層:TCP 重傳的根本原因
同一症狀(定格)在其他層的原因
查看含圖解與實驗的完整版卡片