ゲームラグ白書 › TCP再送の根本原因
遅延の急上昇による不要な再送 Spurious RTO from delay spikes
原因ID rt-spurious-delay · 主担当 外部・外部 · 副担当 インフラチーム・サーバーインフラ, ゲーム開発チーム・クライアント開発
図と実験のあるメインページでこのカードを開く →
パケットは消えておらず、一時的にとても遅れて届いただけなのに、その遅延がRTOより長いと、送信側はパケットロスと判断して再送します。
なぜ バッファブロート、Wi-Fiの省電力、モバイルの無線状態の切り替え、仮想マシンの一時停止で、瞬間的な遅延が数百ms → すると RTOが先に満了して再送、元のパケットもすぐに到着(受信側は重複して受け取る) → 画面では フリーズ・早送りは遅延の急上昇そのものが原因。不要な再送は止まる時間をほとんど延ばさず、再送のメトリクスだけを押し上げるため、パケットロスと誤解される
- 症状
- フリーズ, 早送り, 入力遅延
- 要因
- 遅延, ジッター
- 誰に起きるか
- 自分だけ, サーバー全体
- いつ
- ときどきランダムに, しばらく放置した後
- 担当
- 主担当 外部・外部 · 副担当 インフラチーム・サーバーインフラ, ゲーム開発チーム・クライアント開発
- ゲーム開発チームの対応
- Android 10以上のクライアントは、ゲーム中に低遅延Wi-Fiモード(WIFI_MODE_FULL_LOW_LATENCYのWi-Fiロック、画面がオンでゲームがフォアグラウンドにあるときだけ適用)を要求し、省電力による遅延の急上昇を減らす。
- インフラチームの対応
- バースト可能インスタンスを避ける、RTOの最小値を下げすぎない、F-RTO・タイムスタンプを維持(tcp_frto、tcp_timestamps)、再送のメトリクスはnstatのTCPSpuriousRTOs・TCPDSACKRecvとあわせて確認し、パケットロスと誤解しない。
- 外部の対応
- 遅延の急上昇そのものを減らすため、ユーザーにルーターのSQMの利用、Wi-Fiの省電力の無効化を案内。
- 数値の目安
- LinuxはF-RTOで不要なRTOを検知し、送信量の絞り込みを元に戻すこともあります。nstatのTCPSpuriousRTOs(不要なRTOと判定した回数)とTCPDSACKRecv(受信側が「もう受け取った」と知らせてきた回数)で確認します。
- グラフでは
- 不定期なスパイク · RTT(Ping)、不要なRTOの数
- 確認箇所
- nstatを1分間隔で実行し、TcpExtTCPTimeouts(RTOの満了)、TcpExtTCPSpuriousRTOs、TcpExtTCPDSACKRecv、TcpExtTCPLostRetransmitの増分をあわせて確認。パケットキャプチャがあれば、Wiresharkのフィルターtcp.analysis.spurious_retransmissionを使う
- 該当する場合
- RTOが増えるときにTcpExtTCPSpuriousRTOsやTcpExtTCPDSACKRecvもそろって増え、同じ時刻にRTTが数百msに跳ねる。受信側のキャプチャに、元のパケットと再送の両方が届いている
- 該当しない場合
- TcpExtTCPSpuriousRTOs・DSACKは変わらないのにTcpExtTCPLostRetransmit(送り直したものまでまた失う)が増えるなら実際のパケットロス。RTTは跳ねないのにDSACKだけが継続的に多いなら「順序の入れ替わりによる不要な高速再送」
- 確認手段
- インフラのツールで確認(ゲームコード不要)
出典
- RFC 5682: Forward RTO-Recovery (F-RTO): An Algorithm for Detecting Spurious Retransmission Timeouts with TCP IETF
F-RTO:RTOの後に届いたACKで、不要なRTOだったかを見分ける - RFC 3481: TCP over Second (2.5G) and Third (3G) Generation Wireless Networks IETF
モバイル回線の遅延の急上昇(ハンドオーバー、リンクの回復など)が、不要なTCPタイムアウト・再送と輻輳ウィンドウの縮小を引き起こす - RFC 2883: An Extension to the Selective Acknowledgement (SACK) Option for TCP IETF
DSACK:受信側が重複受信を知らせることで、送信側が不要な再送に気づける - SNMP counter Linux kernel
TcpExtTCPSpuriousRTOs(F-RTOが検知した不要なRTO)、TcpExtTCPDSACKRecv(受信したDSACKの数)、TcpExtTCPLostRetransmit(送り直したパケットをまた失ったとSACKが知らせてきた数) - IP Sysctl Linux kernel
tcp_frtoはデフォルトで有効(RTTが揺れる無線ネットワークで有利)、tcp_timestampsのデフォルト値は1 - RFC 6298: Computing TCP's Retransmission Timer IETF
不要な再送を防ぐには大きな最小RTOが必要だという根拠(最小1秒を推奨) - WifiManager Android (Google)
WIFI_MODE_FULL_LOW_LATENCY(API 29、Android 10):APに接続していて、画面がオンで、アプリがフォアグラウンドにあるときだけ適用される低遅延Wi-Fiロック - net/ipv4/proc.c Linux kernel
nstatに表示されるカウンター名TCPTimeouts・TCPSpuriousRTOs・TCPDSACKRecv・TCPLostRetransmit - net/ipv4/tcp_timer.c Linux kernel
TCPTimeoutsは再送タイマー(RTO)が満了したときに増加 - nstat(8) — Linux manual page iproute2
nstatはデフォルトで、前回の実行以降の増分を表示 - Display Filter Reference: Transmission Control Protocol Wireshark
tcp.analysis.spurious_retransmissionの表示フィルター
あわせて読みたい原因
同じ層:TCP再送の根本原因
同じ症状(フリーズ)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る