遊戲 Lag 白皮書 › L8 Socket 與協定
慢速用戶端造成的阻塞式傳送 Blocking send on a full socket
原因 ID sk-block-send · 主要負責 遊戲開發團隊(伺服器開發)
在含圖解與實驗的完整版中開啟卡片 →
線路很慢的某位玩家傳送緩衝區已滿時,若用阻塞方式(緩衝區有空間之前呼叫不會返回的傳送)送出,伺服器執行緒就會一直等那一個人。
為什麼 慢速用戶端的傳送緩衝區已滿 → 於是 由於是阻塞式傳送,伺服器執行緒會等到緩衝區有空間為止 → 畫面上 該執行緒負責的所有人都出現定格、慢動作
- 症狀
- 定格, 慢動作
- 因素
- 停滯
- 誰會遇到
- 特定地點/頻道, 整個伺服器
- 何時
- 偶爾隨機發生, 人潮湧入時
- 負責單位
- 主要負責 遊戲開發團隊(伺服器開發)
- 遊戲開發團隊要做的事
- 改用非阻塞式傳送、為每個用戶端設定傳送佇列上限、丟棄過時的狀態更新。
- 圖表上
- 偶爾隨機飆高 · 伺服器 tick 時間、每條連線的 Send-Q
- 查看位置
- 用 ss -tn 找出 Send-Q(尚未收到 ACK 或尚未送出的位元組)已塞滿傳送緩衝區的連線,並在 tick 飆高的當下看遊戲伺服器的 thread dump(堆疊)中是否有停在 send 呼叫的執行緒
- 符合的跡象
- 有 Send-Q 塞滿的慢速連線時,負責該連線的執行緒停在 send,且只有同一執行緒負責的玩家一起停住
- 不符合的跡象
- 停住的執行緒在 send 以外的地方(鎖、DB 呼叫)等待時是「鎖競爭」、「遊戲執行緒上的同步呼叫」
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
出處
- send(2) — Linux manual page Linux man-pages
傳送緩衝區沒有空間時 send() 會阻塞,非阻塞模式下則立刻以 EAGAIN 返回 - send function (winsock2.h) Microsoft
Winsock 在緩衝區空間不足時,除非是非阻塞模式,send 也會阻塞 - net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
ss 的 Recv-Q、Send-Q 值:listen socket 是等待 accept 的連線數與 backlog 上限;已連線的 socket 是應用程式尚未讀取的位元組數與尚未收到 ACK 的已送出位元組數
相關原因
同一層:L8 Socket 與協定
同一症狀(定格)在其他層的原因
查看含圖解與實驗的完整版卡片