한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

遊戲 Lag 白皮書 › L8 Socket 與協定

SO_REUSEPORT 分配不均 SO_REUSEPORT imbalance, stuck worker

原因 ID sk-reuseport · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)

在含圖解與實驗的完整版中開啟卡片 →

多個處理程序共用同一個 port 接收時,kernel 會依位址雜湊為每個連線指定負責的處理程序,之後不再更換。其中一個處理程序停住時,只有分配給它的人要等待。

為什麼 閘道或登入伺服器用 SO_REUSEPORT 啟動多個處理程序 → 於是 即使某個處理程序因 GC 或過載停住,分配給它的新連線與 UDP 封包也不會轉給其他處理程序 → 畫面上 只有部分人連不上或定格。在處理程序數量改變的重新啟動時,部分 UDP session 會中斷

症狀
連不上/無限讀取, 定格, 斷線
因素
停滯, 遺失
誰會遇到
只有我, 整個伺服器
何時
剛登入/維護剛結束, 偶爾隨機發生
負責單位
主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事
確保接收執行緒絕不停住;實作重新啟動時交接 session 的流程。
基礎設施團隊要做的事
監控各處理程序的連線等待佇列(ss 的 Recv-Q);部署時若要改變處理程序數量,必須遵循 session 交接流程。
圖表上
只有部分偏高 · 每個 listen socket 的連線等待佇列(Recv-Q)
查看位置
用 ss -ltnp 看同一 port 上每個 listen socket 的 Recv-Q(等待 accept 的連線數)與負責的處理程序,並比較各處理程序的處理量
符合的跡象
同一 port 的多個 socket 中,只有一個的 Recv-Q 持續累積,且該處理程序已停住或處理量接近 0
不符合的跡象
所有 socket 的 Recv-Q 都平均累積時,是整體過載(「連線等待佇列(backlog)溢位」)
確認方式
用基礎設施工具確認(不需要遊戲程式碼)

出處

  1. socket(7) — Linux manual page Linux man-pages
    透過 SO_REUSEPORT,多個 socket bind 到同一位址,分擔接收 TCP 連線與 UDP 封包
  2. net/core/sock_reuseport.c (Linux v6.12) Linux kernel
    沒有 BPF 程式時,依群組內的 socket 數分配封包雜湊值來選出負責的 socket
  3. Why does one NGINX worker take all the load? Cloudflare
    SO_REUSEPORT 以簡單的雜湊為每個 worker 分配佇列,所以一個 worker 卡住時,排在該佇列的連線會全部停住
  4. net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
    ss 的 Recv-Q、Send-Q 值:listen socket 是等待 accept 的連線數與 backlog 上限;已連線的 socket 是應用程式尚未讀取的位元組數與尚未收到 ACK 的已送出位元組數

相關原因

同一層:L8 Socket 與協定

同一症狀(連不上/無限讀取)在其他層的原因

查看含圖解與實驗的完整版卡片