遊戲 Lag 白皮書純文字版
將線上遊戲畫面卡頓、角色瞬移、斷線的 228 個原因,從玩家畫面到伺服器資料庫逐層整理的純文字版。每個原因都附上症狀、負責團隊(遊戲開發團隊、基礎設施團隊)、數值與可信的出處。
含圖解與可親手操作實驗的完整版是遊戲 Lag 白皮書 。本版把相同的原因、術語與出處集中在一頁,不需要 JavaScript 就能閱讀。每個原因也有獨立頁面(c/ID.html)。單一 Markdown 檔案版本請見 llms-full.txt 。
目錄
依症狀查找
Lag 源自四個因素: 延遲 (因為距離、佇列與處理時間,所有封包都固定晚一段時間才抵達。) 抖動 (平均值沒問題,但有的封包來得快、有的來得慢。常見來源是 Wi-Fi、壅塞的線路和忙碌的 CPU。) 遺失 (佇列滿溢、無線干擾、故障的設備都會丟棄封包。線路短暫中斷也等於連續遺失。) 停滯 (伺服器的 tick 延後或停住(GC、鎖、同步呼叫、過載),自己電腦的畫格也會停住。線路完全正常時也會發生。)
卡頓 (60 個原因): 動作不流暢,不斷短暫停住又繼續動。瞬移 (47 個原因): 角色沒有移動過程,一下子就出現在很遠的位置。拉回 (14 個原因): 自己的角色往前走到一半,被拉回剛剛經過的位置。快轉 (36 個原因): 停住的畫面重新動起來時,積壓的移動、打擊和傷害一口氣快速跑完。慢動作 (24 個原因): 所有東西都變慢,技能施放和怪物移動看起來像被拉長。依伺服器設計不同,也可能速度不變,改以卡頓或瞬移的形式出現。輸入延遲 (76 個原因): 按下去之後要等一段時間才看到結果。畫面本身可能很流暢。定格 (67 個原因): 畫面裡所有東西停住一下(0.5 秒到數秒),然後又開始動。吃指令/回檔 (36 個原因): 明明做了的動作變成沒發生過,或是結果過了好一陣子才被推翻。斷線 (51 個原因): 遊戲中連線中斷,被送回登入畫面或重新連線視窗。連不上/無限讀取 (45 個原因): 進不了遊戲,或是停在讀取、進場畫面。看不見/幽靈物件 (20 個原因): 應該存在的 NPC、怪物、玩家只在自己的畫面上消失,或是早已消失的物件只留在自己的畫面上。
負責團隊與負責代碼
代碼 團隊 負責單位 範圍
cli遊戲開發團隊 用戶端開發 遊戲用戶端程式碼:畫格、GC、載入,內插、外插、預測,用戶端的網路處理(包含送出心跳封包、自動重新連線)
srv遊戲開發團隊 伺服器開發 遊戲伺服器程式碼:tick、執行緒、鎖,同步設計,連線處理(accept 迴圈、listen 參數),心跳回應與斷線連線的清理,socket 選項,查詢與 transaction 設計
net基礎設施團隊 網路基礎設施 線路與 IDC 網路設備(交換器、路由器、防火牆、負載平衡器、DDoS 防護),雲端網路 ACL、VPC 路由、負載平衡器,電信業者與 peering
sys基礎設施團隊 伺服器基礎設施 伺服器設備與雲端執行個體(包含安全群組、連線追蹤),OS 與 kernel 設定,NIC,部署與監控環境
dba基礎設施團隊 DB 基礎設施 DB 伺服器與儲存裝置,DB 設定、複寫、備份,快取伺服器
ext外部 外部 玩家的電腦與家用網路、電信業者路段(不在我方合約範圍內)、雲端供應商。無法直接修正,以公告說明、提出請求、繞道等方式因應
L1 用戶端遊戲程式
16 個原因 · 完整版章節
ID cg-hitch · 主要負責 遊戲開發團隊(用戶端開發)
某一個畫格的計算時間比平常多出好幾倍,畫面短暫停住。
為什麼 技能特效暴增、大量生成(spawn)、整個 UI 重新整理,全擠在同一個畫格 → 於是 無法在 16.7ms 內完成,花了 50~300ms → 畫面上 畫面頓一下,下一個畫格所有東西一次移動到位
症狀 卡頓 , 定格
因素 停滯
誰會遇到 只有我
何時 人潮湧入時, 做特定動作時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 把繁重的工作分散到多個畫格、用 profiler 找出飆高的畫格、設定特效數量上限。
數值參考 60FPS 時一個畫格是 16.7ms。只要出現一個超過 50ms 的畫格,就很容易讓人覺得「卡了一下」。
圖表上 偶爾隨機飆高 · 畫格時間
查看位置 用 PresentMon 錄下遊戲中的畫格時間(FrameTime),以及 CPU、GPU 在該畫格花費的時間(CPUBusy、GPUBusy)。行動裝置看 Android vitals 的慢速工作階段(slow session)與渲染緩慢指標 符合的跡象 平常在 16.7ms 左右的畫格時間往上衝到超過 50ms 的瞬間,與技能演出、大量生成、整個 UI 重新整理重疊,而當下 ping 沒有變化 不符合的跡象 畫格時間平穩、只有其他角色頓一下時,屬於「沒有內插緩衝或緩衝太短」這類網路端問題。飆高的間隔規律時,先查「用戶端垃圾回收」 確認方式 在玩家端環境確認
出處 3 筆
用戶端垃圾回收 Client GC (Unity C#, Unreal, Lua)
ID cg-gc · 主要負責 遊戲開發團隊(用戶端開發)
回收用過即丟的記憶體(垃圾)期間,整個遊戲會暫停。特徵是以規律的間隔出現卡頓。
為什麼 每個畫格都建立再丟棄暫時性的字串、陣列、List → 於是 垃圾累積起來後,GC 暫停主執行緒進行回收 → 畫面上 每隔幾秒~幾十秒規律地出現卡頓
症狀 卡頓 , 定格
因素 停滯
誰會遇到 只有我
何時 固定週期, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 減少記憶體配置(避免字串串接、LINQ、lambda 捕捉)、使用物件池、開啟漸進式 GC(Unity 2020 以後為預設值)、趁讀取畫面這類暫停也無妨的時機先執行 GC。
數值參考 一般每次數 ms~100ms,低階手機或記憶體用量大的遊戲會更久(實驗中約 150~170ms)。Unity 的 GC 每次執行都會檢查整個 heap,所以遊戲使用中的記憶體越多,暫停就越久。
圖表上 固定週期飆高 · 畫格時間、GC 執行時間點
查看位置 在開發版本中查看 Unity Profiler 的 GC.Collect、GC.Alloc 標記。Unreal 則看 stat GC 與 stat Hitches(把超過 t.HitchFrameTimeThreshold 所設時間的畫格記進 log) 符合的跡象 每個飆高的畫格都有 GC.Collect 區段,長度與飆高的長度相近,間隔為幾秒~幾十秒且規律。在人多的地方,每個畫格的 GC.Alloc 會增加 不符合的跡象 飆高的畫格沒有 GC 區段時,是「主執行緒同步載入、著色器編譯」或「大量角色同畫面的渲染負載」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 在 Unity 這類使用 C# 的用戶端很常見。主要元凶是每個畫格都重新產生戰鬥紀錄字串、傷害數字、UI 文字的程式碼。如果只在人多的地方卡頓,代表有程式碼產生的垃圾會隨人數成比例增加。漸進式 GC 會把回收工作分散到每個畫格各做一點(Unity 預設 3ms),但產生垃圾的速度一旦快過回收速度,最後還是會一次暫停。Unreal Engine 也有自己的 GC,負責清理不再使用的遊戲物件;雖然依引擎版本與設定而不同,預設設定下約每 1 分鐘執行一次,有時會造成每隔 1 分鐘頓一下。遊戲規則用 Lua 等腳本撰寫的用戶端,該腳本的 GC 也會另外執行。
出處 5 筆
主執行緒同步載入、著色器編譯 Synchronous asset load, shader compile
ID cg-sync-load · 主要負責 遊戲開發團隊(用戶端開發)
要繪製第一次出現的地圖、怪物、特效之前,得先讀取檔案並建立著色器,畫面因此停住。
為什麼 進入新地圖,或第一次出現的技能、裝備、怪物登場 → 於是 主執行緒等待讀取檔案與著色器編譯 → 畫面上 只有第一次停住 0.1~1 秒,第二次起就正常
症狀 定格 , 卡頓
因素 停滯
誰會遇到 只有我
何時 移動中/切換地圖時, 做特定動作時
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 非同步載入、預先載入(prewarming)、在讀取畫面或首次執行時預先編譯著色器、善用讀取畫面。
數值參考 編譯一個著色器需要數十 ms,久的話超過 100ms。貼圖載入依儲存裝置速度需要數十~數百 ms。
圖表上 剛開服或維護結束後暴增 · 畫格尖峰次數(遊戲或驅動程式剛更新時)
查看位置 用 PresentMon 把同一條路線錄兩次,比較第一次與第二次經過。開發版本在 Unreal 開啟 r.PSOPrecache.Validation,查看 stat PSOPrecache 與 log 中的「PSO PRECACHING MISS」;Unity 則在 Profiler 的 Timeline 查看飆高畫格中的載入與著色器區段 符合的跡象 只在第一次去的地方、第一次用的技能飆高 0.1~1 秒,第二次就消失。遊戲或顯示卡驅動程式剛更新時回報集中,之後逐漸減少 不符合的跡象 同一個地方每次都飆高時,與著色器快取無關。只有儲存裝置慢的電腦每次移動都重複發生時,是「儲存裝置太慢,資源串流跟不上」;專用 GPU 記憶體已滿時,是「顯示記憶體(VRAM)不足」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 在電腦上,建立過一次的著色器會由顯示卡驅動程式存進著色器快取,之後重複使用。因此在更新顯示卡驅動程式或遊戲更新剛推出時,這個快取會失效,原本正常的人也會有一段時間再度卡頓。典型的回報是「更新後每到一個沒去過的地方就頓一下」。
出處 5 筆
儲存裝置太慢,資源串流跟不上 Slow storage stalls asset streaming
ID cg-asset-stream · 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
在 HDD 這類較慢的儲存裝置上,讀取開放世界貼圖與模型的速度跟不上移動,物件會晚出現,或遊戲為了等待讀取而卡頓。
為什麼 騎坐騎、傳送等快速移動,或進入人多的地方,一次需要大量新的貼圖與模型 → 於是 HDD 等較慢的儲存裝置無法以需要的速度讀取,讀取請求越積越多,部分載入還要主執行緒等到完成為止 → 畫面上 貼圖有一段時間是模糊的,建築與角色晚出現;等待讀取的瞬間出現卡頓、定格
症狀 看不見/幽靈物件 , 卡頓 , 定格
因素 停滯
誰會遇到 只有我
何時 移動中/切換地圖時, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲開發團隊要做的事 採用主執行緒不必等待讀取的非同步串流、依移動方向與速度預先讀取、先顯示低解析度(mipmap)與簡化模型再替換、快速移動時串流跟不上就暫時限制移動速度或改用讀取畫面、在最低與建議配備中註明是否需要 SSD。
外部要做的事 引導玩家把遊戲安裝在 SSD 上,並請玩家確認同一顆磁碟上是否正在下載或執行防毒掃描。
數值參考 根據 Microsoft 的說明,舊式硬碟每秒可讀取數十 MB,NVMe SSD 每秒可讀取數 GB,而上一世代的遊戲串流每秒大約使用 50MB。以 SSD 速度為前提、讀取量遠多於此的遊戲放在 HDD 上執行,讀取很容易跟不上移動。
圖表上 只有部分偏高 · 畫格尖峰次數(依儲存裝置類型)、磁碟讀取延遲
查看位置 快速移動時,同時記錄 Windows 效能監視器的 PhysicalDisk\Avg. Disk sec/Read(單次讀取的平均時間)、Current Disk Queue Length 與 PresentMon 畫格時間。開發版本看 Unreal 的 stat Streaming、stat AsyncLoad,以及 Unity Profiler 的 AssetBundle.asset/allAssets 警告(在載入完成前就要求結果,主執行緒只好等待) 符合的跡象 快速移動時磁碟讀取延遲與佇列暴增,同一時間畫格飆高,或貼圖、物件晚出現。同一場景改在 SSD 上執行就消失 不符合的跡象 磁碟很閒、貼圖卻模糊時,是「顯示記憶體(VRAM)不足」;同一個地方第二次去就正常時,是「主執行緒同步載入、著色器編譯」 確認方式 在玩家端環境確認
深入了解 如果只有第一次停住、之後就正常,比較接近「主執行緒同步載入、著色器編譯」;只有儲存裝置慢的電腦每次移動都重複發生,就是這個原因。顯示記憶體不夠、貼圖被反覆移出又載入的「顯示記憶體(VRAM)不足」也會造成貼圖模糊,所以要同時查看磁碟讀取等待與顯示記憶體用量。防毒軟體的即時掃描會在遊戲每次開啟檔案時介入,也可能讓讀取更慢。
出處 8 筆
大量角色同畫面的渲染負載 Render/animation cost of crowds
ID cg-crowd · 主要負責 遊戲開發團隊(用戶端開發)
攻城戰、世界王這類數百人擠進同一個畫面的場合,光是繪製的成本就負荷不了。
為什麼 同一個畫面裡數百人與特效重疊 → 於是 動畫、陰影、名字、特效的成本隨人數成比例增加 → 畫面上 FPS 由 60 → 15 大幅下降,所有動作都卡頓,輸入也跟著延遲
症狀 卡頓 , 輸入延遲
因素 停滯
誰會遇到 特定地點/頻道, 只有我
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 依距離簡化(LOD)、設定顯示人數上限、提供特效簡化選項、降低動畫更新頻率。
數值參考 即使每個角色只要 0.02~0.1ms,300 人就是 6~30ms。60FPS 的畫格預算是 16.7ms,光這部分就用掉 1/3 以上,多的時候直接超出預算。
圖表上 隨人數/負載上升 · 畫格時間、畫面內角色數
查看位置 比較攻城戰、世界王前後的 PresentMon 畫格時間與 CPUBusy、GPUBusy。開發版本看 Unreal 的 stat Unit(遊戲執行緒、渲染執行緒、GPU 時間) 符合的跡象 畫面內人數越多,畫格時間跟著上升;開啟顯示人數限制或特效簡化選項後立刻改善 不符合的跡象 與人數無關也會飆高時,是「畫格時間尖峰」或「用戶端垃圾回收」。FPS 正常、只有其他人的動作延遲時,是「主執行緒封包處理瓶頸」 確認方式 在玩家端環境確認
出處 4 筆
主執行緒封包處理瓶頸 Network processing on the main thread
ID cg-net-mainthread · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
每個畫格只處理固定數量的已接收封包時,一次湧入的封包會不斷延到下一個畫格。
為什麼 人多的地方每秒湧入數千筆更新 → 於是 主執行緒碰到每畫格的處理量上限,讀不完 → 畫面上 其他人的動作越來越晚反映,而且一次湧入
症狀 快轉 , 輸入延遲
因素 停滯, 延遲
誰會遇到 特定地點/頻道, 只有我
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:接收與解析交給獨立執行緒,同一對象的舊位置更新合併後只套用最新的一筆。伺服器:人多的地方降低遠處角色的更新頻率,減少傳輸量。
數值參考 未處理的封包一旦累積,只要幾秒就會落後 1 秒的份量。
圖表上 隨人數/負載上升 · 未處理的接收封包數、從接收到套用的延遲
查看位置 把用戶端每個畫格處理不完而剩下的封包數,以及封包從抵達到套用至遊戲的延遲記進 log,對照周圍人數查看 符合的跡象 人多的地方剩餘封包數與套用延遲持續增加,同一時間 ping 與伺服器的傳送間隔正常 不符合的跡象 沒有套用延遲、封包本身卻晚到時,問題在網路區段。畫格時間大幅上升時,是「大量角色同畫面的渲染負載」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
沒有內插緩衝或緩衝太短 Missing/short interpolation buffer
ID cg-no-buffer · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
一收到伺服器封包就立刻繪製時,抖動(封包抵達間隔忽長忽短)會原封不動地出現在畫面上。
為什麼 收到位置就直接繪製,或緩衝比抖動還短 → 於是 封包晚到多久就停多久,一次湧入多少就跳多少 → 畫面上 其他角色走走停停,一頓一頓地移動
症狀 卡頓
因素 抖動
誰會遇到 只有我
何時 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:加入內插緩衝,依線路狀態自動調整緩衝長度。伺服器:套用延遲補償(回溯判定),讓玩家看著緩衝時間之前的畫面射擊,判定也正確。
數值參考 一般會保留約為伺服器封包傳送間隔 2 倍的緩衝(每秒收到 20 次時為 100ms)。
圖表上 一開始就一直偏高 · 封包抵達間隔、內插緩衝變空的次數
查看位置 在用戶端記錄伺服器封包的抵達間隔分布,以及因為沒有下一個可內插的快照而停住或改用外插的畫格數 符合的跡象 抵達間隔的波動經常超過內插緩衝長度,每次緩衝都會變空、其他角色頓一下。加長緩衝後減少 不符合的跡象 緩衝足夠卻仍會頓一下時,確認伺服器的傳送間隔本身是否不規律(tick 延遲) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 加長緩衝會更流暢,但看到的對手也會落後同樣的時間。因此攻擊判定會搭配延遲補償,由伺服器回溯到「那位玩家當時看到的過去」來確認。
出處 3 筆
用戶端預測不一致 Prediction mismatch / reconciliation
ID cg-predict · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
自己的用戶端已經先顯示移動,伺服器卻算出不同的結果時,自己的角色就會被拉回去。
為什麼 用戶端在伺服器確認前先移動(預測) → 於是 伺服器對碰撞、移動速度、buff 的計算結果不同,或沒收到指令 → 畫面上 確認到達時,自己的角色被往回拉
症狀 拉回
因素 遺失, 延遲
誰會遇到 只有我
何時 移動中/切換地圖時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:使用與伺服器相同的移動程式碼、重複傳送輸入、平滑地校正。伺服器:使用與用戶端相同的移動程式碼,重複收到的輸入依輸入編號過濾,只處理一次。
數值參考 被拉回的距離是「偏差時間 × 移動速度」。只要掉了幾個指令,就會差 1~3m。
圖表上 偶爾隨機飆高 · 伺服器校正(預測失敗)次數
查看位置 記錄伺服器送出的位置校正次數與校正距離。Unreal 計算伺服器的 ClientAdjustPosition 校正次數,Unity Netcode for Entities 計算因預測失敗而回溯重算的次數 符合的跡象 校正集中在回報拉回的時間點,在特定 buff、地形、位移技能下校正距離反覆偏大 不符合的跡象 校正只在封包遺失嚴重時集中出現,屬於輸入封包遺失(線路)。沒有校正、只有其他角色看起來被拉回時,是「過度外插(dead reckoning)」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
固定時間步長追趕失控 Fixed-timestep catch-up / spiral of death
ID cg-fixed-step · 主要負責 遊戲開發團隊(用戶端開發)
停過一次之後集中補算落後的部分,又因為這些計算而再度落後。
為什麼 以固定間隔執行的遊戲模擬停了一次 → 於是 把積欠的每一步集中在一個畫格內算完 → 畫面上 長畫格接連出現而飆高,或碰到上限使整個世界變慢
症狀 卡頓 , 快轉 , 慢動作
因素 停滯
誰會遇到 只有我
何時 偶爾隨機發生, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 設定每個畫格的追趕上限,剩餘的時間以內插處理。
圖表上 偶爾隨機飆高 · 畫格時間、每畫格的固定步數
查看位置 在開發版本的 profiler 同時查看一個畫格內固定步長執行了幾次(Unity 看 FixedBehaviourUpdate 等 FixedUpdate 階段標記的數量)與畫格時間 符合的跡象 一個長畫格之後,接連出現多次執行步長的長畫格;碰到上限(Unity 的 Maximum Allowed Timestep)時,遊戲時間比實際時間走得慢 不符合的跡象 長畫格只出現一次就結束時,是「畫格時間尖峰」或「用戶端垃圾回收」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 Unity 的物理計算(FixedUpdate)是典型的固定步長(預設 0.02 秒,每秒 50 次)。Time 設定中的 Maximum Allowed Timestep(一個畫格最多追趕的時間,預設約 0.33 秒)就是追趕上限。一個畫格比這更長時,超出的時間會被捨棄,遊戲時鐘也就比實際時間慢了這麼多。
出處 3 筆
時鐘同步誤差 Clock sync error
ID cg-clock · 主要負責 遊戲開發團隊(用戶端開發)
用戶端推估的伺服器時間不準時,內插時間點與冷卻判定就會出現偏差。
為什麼 只在連線時對時一次,ping 改變了也不重新校正 → 於是 內插時間點與冷卻結束時間跟伺服器不一致 → 畫面上 對手偶爾頓一下;冷卻明明結束了,技能卻被拒絕
症狀 卡頓 , 吃指令/回檔
因素 延遲
誰會遇到 只有我
何時 開越久越嚴重, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 定期做時間同步(量測往返時間後校正)、逐步校正以免時間突然跳動、用 monotonic clock 量測經過時間,不依賴電腦的系統時間。
圖表上 緩慢爬升 · 推估伺服器時間的誤差
查看位置 定期記錄用戶端推估的伺服器時間,與伺服器放在封包裡送來的伺服器時間(tick 編號)之間的差距 符合的跡象 誤差在連線後隨時間越來越大,或在電腦時鐘被校正的瞬間一次跳開,同一時期技能被拒、頓一下的回報增加 不符合的跡象 誤差一直很小、技能仍被拒絕時,屬於伺服器判定或延遲的問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 用電腦的日期時間(wall clock)量測經過時間時,在 Windows 依網際網路時間校正時鐘,或使用者修改時鐘的瞬間,遊戲時間就會跳動。經過時間必須用不會倒退的 monotonic clock(Stopwatch 等)量測。
出處 3 筆
float 時間精度損失 Float time precision loss on long sessions
ID cg-float-time · 主要負責 遊戲開發團隊(用戶端開發)
以精度較低的浮點數格式(float)保存遊戲時間時,開著的時間越久,時間解析度(能分辨的最小時間差)就越差,動作與特效會顫動。
為什麼 把遊戲啟動後經過的時間累加在 float 裡,或直接傳給著色器 → 於是 開著的時間越久,float 能表示的最小差距就越大 → 畫面上 只有連續開了好幾天的用戶端,角色、動畫、流動特效會不停顫動,重新開啟就恢復正常
症狀 卡頓
因素 抖動
誰會遇到 只有我
何時 開越久越嚴重
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 經過時間以 double(64 位元)或整數保存、傳給著色器的時間定期歸零重算、進行連續數天的長時間自動化測試。
數值參考 32 位元 float 的有效位數只有 7 位多一點,開了一天(約 86,400 秒)時間解析度約為 8ms,大約是 60FPS 一個畫格(16.7ms)的一半;一週則約 60ms,比一個畫格還大。
圖表上 緩慢爬升 · 依開啟時長統計的顫動回報
查看位置 收集顫動回報時一併取得用戶端已開啟的時間,並比較重新啟動前後。開發端則把遊戲啟動時間的值設成已經過好幾天的值來測試 符合的跡象 只在開了好幾天的用戶端顫動,重新啟動就消失,開得越久越嚴重 不符合的跡象 一開啟就顫動時,是「沒有內插緩衝或緩衝太短」或「計時器解析度」 確認方式 在玩家端環境確認
深入了解 在開著自動打怪、一連好幾天都不關的手機 MMO 特別常見。Unity 的 Time.time 也是 float,因此 Unity 另外提供 double 型別的 Time.timeAsDouble,並建議改用它。
出處 2 筆
ID cg-vsync · 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
GPU 畫好的畫格會先在佇列裡堆上幾張,再配合螢幕的更新週期送出,這段期間輸入就被延遲。
為什麼 顯示卡驅動程式預先在佇列中堆積 1~3 張畫格 → 於是 輸入反映到畫面上也要多花這麼多時間 → 畫面上 ping 很低,操作卻沉重遲鈍
症狀 輸入延遲 , 卡頓
因素 延遲
誰會遇到 只有我
何時 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲開發團隊要做的事 支援低延遲模式、縮短畫格佇列、提供略低於更新率的畫格上限選項、手機開啟 frame pacing 功能。
外部要做的事 引導玩家搭配可變更新率螢幕,把畫格上限設得略低於更新率,並開啟顯示卡驅動程式的低延遲模式。
數值參考 60Hz 下每張 16.7ms。CPU 比 GPU 或螢幕週期快、佇列的三張(DirectX 11 預設值)全部塞滿時,會多出 50ms。在雙緩衝 V-Sync 下,花了 17ms 的畫格要等到下一次畫面更新的時間點(33.3ms),這段期間上一個畫格會再顯示一次。
圖表上 一開始就一直偏高 · 從輸入到畫面的延遲
查看位置 切換 V-Sync、低延遲模式、畫格上限,比較 PresentMon 的 MsClickToPhotonLatency、MsAllInputToPhotonLatency(從滑鼠、鍵盤輸入到送出至螢幕)與 DisplayLatency。MsPCLatency(電腦收到輸入後到送往螢幕)只有在遊戲送出 PC Latency 事件時才會記錄 符合的跡象 開啟 V-Sync 或沒有畫格上限時,這段延遲增加一兩個畫格(數十 ms),在低延遲模式或略低於更新率的畫格上限下減少。ping 沒有變化 不符合的跡象 電腦內部的延遲很低、操作仍慢半拍時,是「顯示器、輸入裝置與畫格生成的延遲」;ping 很高時,屬於網路端 確認方式 在玩家端環境確認
深入了解 垂直同步(V-Sync)是只在螢幕更新畫面的瞬間才送出新畫格的設定。畫面撕裂會消失,但等待那個瞬間會讓輸入延遲,而且 FPS 掉到 60 以下時,會在 60 與 30 之間來回切換而出現卡頓。可變更新率(VRR)螢幕會配合畫格完成的時機更新畫面,縮短這段等待。手機也會發生同樣的情況。30FPS 的遊戲如果無法把畫格平均地配合 60Hz 螢幕送出,雖然平均是 30FPS,每張畫格停留的時間卻像 49、16、33ms 這樣忽長忽短,造成卡頓(Android 開發文件的例子)。可以用 Android 的 Frame Pacing 程式庫(讓畫格輸出間隔保持均勻)或引擎中的同類選項來改善。
出處 5 筆
用戶端記憶體洩漏 Client memory leak
ID cg-leak · 主要負責 遊戲開發團隊(用戶端開發)
開得越久,記憶體用量越大,遊戲越來越慢,最後被強制關閉。
為什麼 切換地圖時,貼圖、UI、特效沒有釋放 → 於是 GC 越來越頻繁,OS 記憶體不足而發生 swap → 畫面上 玩了幾個小時後越來越卡頓,最後強制結束(在玩家看來像斷線)
症狀 卡頓 , 斷線
因素 停滯
誰會遇到 只有我
何時 開越久越嚴重
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 在切換地圖時量測記憶體用量、找出沒有釋放的貼圖、UI、特效並修正、進行長時間自動化測試(soak test)。
圖表上 緩慢爬升 · 遊戲處理程序的記憶體
查看位置 用效能監視器記錄數小時的 Process(遊戲)\Private Bytes。行動裝置看 Android ApplicationExitInfo 的結束原因(REASON_LOW_MEMORY)與 iOS jetsam 報告 符合的跡象 每次切換地圖記憶體都上升且不會下降,開得越久,卡頓與強制結束越多 不符合的跡象 記憶體持平、只是開得越久越顫動時,是「float 時間精度損失」 確認方式 在玩家端環境確認
深入了解 手機主要靠壓縮記憶體撐住。即使如此記憶體仍不夠時,OS 會直接把遊戲關掉(閃退)。RAM 越小的裝置越先被關掉。
出處 4 筆
用戶端閃退 Client crash
ID cg-crash · 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲因未處理的錯誤而關閉。在玩家看來像斷線,但伺服器是正常的。
為什麼 null 參考、記憶體不足、顯示卡驅動程式錯誤 → 於是 遊戲處理程序被強制結束 → 畫面上 回報「閃退了」。同一時間其他人都正常
症狀 斷線
因素 停滯
誰會遇到 只有我
何時 做特定動作時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲開發團隊要做的事 收集 crash report、依裝置與驅動程式統計、從最集中的錯誤開始修正。
外部要做的事 集中在特定顯示卡驅動程式版本時,引導玩家更新驅動程式。
圖表上 只有部分偏高 · 閃退次數(依裝置、顯示卡驅動程式、build)
查看位置 依裝置、驅動程式、build 查看 crash report 與 Android vitals 的當機率。玩家電腦則查看事件檢視器「應用程式」log 中的事件識別碼 1000(發生錯誤的模組名稱)與「Display driver stopped responding and has recovered」紀錄 符合的跡象 回報斷線的時間點有閃退紀錄,同一時間同一伺服器的其他玩家正常。集中在特定裝置、驅動程式版本、模組 不符合的跡象 沒有閃退紀錄、只是連線中斷時,是「NAT mapping 過期」或線路問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
遊戲安全模組(反作弊)檢查 Anti-cheat scan and heartbeat
ID cg-anticheat · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
為了防範外掛而與遊戲一起執行的安全模組會定期檢查。檢查太重,或與安全伺服器往來的心跳封包(定期確認連線存活的訊號)延遲時,就會卡頓或斷線。
為什麼 安全模組定期檢查遊戲記憶體、執行中的程式與驅動程式 → 於是 檢查期間遊戲執行緒停住,或心跳封包沒能準時送出 → 畫面上 以固定間隔頓一下,嚴重時跳出安全錯誤訊息並斷線
症狀 卡頓 , 定格 , 斷線
因素 停滯
誰會遇到 只有我
何時 固定週期, 剛登入/維護剛結束, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:把重量級檢查移到遊戲執行緒之外分批執行、比較各安全模組版本的卡頓與閃退統計(剛更新後集中發生時轉交安全模組廠商)。伺服器:容許心跳封包延遲一兩次。
數值參考 輕量的檢查通常不到 1ms,但在遊戲執行緒上執行的重量級檢查,依實作不同,有時一次會占用數十~數百 ms。
圖表上 固定週期飆高 · 畫格時間、反作弊踢出次數
查看位置 從 PresentMon 畫格時間量出飆高的間隔,並把伺服器收到的反作弊踢出原因(EOS 為 ClientActionReason 的 AuthenticationFailed / Authentication Timed Out 等)依安全模組版本與配備彙總 符合的跡象 與遊戲狀況無關、以固定間隔反覆短暫停住;安全模組剛更新後,特定配備的卡頓與驗證逾時踢出增加 不符合的跡象 與安全模組版本無關、所有配備都以相同間隔發生時,是「用戶端垃圾回收」或「背景處理程序占用 CPU」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 安全模組以驅動程式的形式深入 OS,有時會與防毒軟體、overlay、其他遊戲的安全模組衝突。安全模組剛更新後、只有特定配備集中出現卡頓或閃退回報時,要先懷疑這個原因。
出處 2 筆
L2 用戶端 OS 與裝置
15 個原因 · 完整版章節
背景處理程序占用 CPU Background CPU contention
ID co-background · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
防毒掃描、Windows Update、直播軟體、瀏覽器影片占住 CPU 核心時,遊戲執行緒分配不到 CPU,只能等待。
為什麼 其他程式長時間占用 CPU 核心 → 於是 遊戲執行緒等待排程 → 畫面上 畫格延遲,已接收封包的處理也跟著變慢
症狀 卡頓 , 快轉
因素 停滯
誰會遇到 只有我
何時 偶爾隨機發生, 固定週期
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 調整遊戲執行緒的優先順序、在出現卡頓時的 log 中一併記錄整台電腦的 CPU 使用率,以分辨是否為其他程式造成。
外部要做的事 引導玩家開啟 Windows 遊戲模式,並在遊戲中關閉不必要的程式(防毒掃描、Windows Update、直播軟體、瀏覽器影片)。
數值參考 Windows 通常一次把核心交給一個執行緒數 ms~數十 ms。排程上只要被擠掉一次,就會少掉一個畫格。
圖表上 偶爾隨機飆高 · 整台電腦的 CPU 使用率、畫格時間
查看位置 把工作管理員「處理程序」索引標籤的 CPU 欄、效能監視器的 Processor Information(_Total)\% Processor Time 與 PresentMon 畫格時間一起記錄。懷疑是防毒軟體時,用 New-MpPerformanceRecording 錄製,再用 Get-MpPerformanceReport 查看掃描時間長的檔案與處理程序 符合的跡象 卡頓時其他程式(防毒掃描、更新、直播軟體)的 CPU 使用往上衝,或遊戲資料夾的檔案排在掃描時間的前幾名。關掉該程式或將其設為排除項目後就消失 不符合的跡象 CPU 使用率很低,整個畫面卻頓一下且聲音出現雜音時,是「網路卡省電、驅動程式問題」(DPC 延遲) 確認方式 在玩家端環境確認
深入了解 Windows 會給前景視窗的程式稍高的優先順序,但要做的工作比核心還多時,遊戲也得等。比起占用 CPU,防毒軟體更常透過「即時監控」介入。遊戲每次開啟檔案都會被掃描,讀取資源當下的停頓就會拉長。
出處 6 筆
省電模式、過熱降頻 Power saving, thermal throttling
ID co-power · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
筆電的電池模式、手機的省電模式、裝置過熱,都會讓 CPU、GPU 速度下降。過熱的特徵是一開始正常,過了一段時間才變慢。
為什麼 處於電池或省電模式,或裝置發燙 → 於是 依裝置不同,CPU、GPU 時脈降低 30~50% → 畫面上 省電模式一開就發生,過熱則在玩了幾分鐘~20 分鐘左右後,FPS 下降並出現卡頓
症狀 卡頓 , 輸入延遲
因素 停滯
誰會遇到 只有我
何時 開越久越嚴重, 一直都有
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 自動調整畫質選項、以畫格上限控制發熱、依 OS 回報的熱狀態等級(iOS 的 thermalState、Android 的熱狀態 API)提前調低選項、在有兩顆顯示晶片的筆電上於執行檔中標示使用獨立顯示卡(匯出 NvOptimusEnablement、AmdPowerXpressRequestHighPerformance)。
外部要做的事 引導玩家關閉省電模式、筆電建議接上電源;遇到「筆電規格很好 FPS 卻很低」的回報時,確認遊戲在哪一顆顯示晶片上執行,並引導玩家在 Windows 的圖形設定中把遊戲指定為高效能 GPU。
圖表上 緩慢爬升 · FPS、CPU 與 GPU 時脈
查看位置 用 PresentMon 把 CPUFrequency、GPUFrequency、CPUTemperature、GPUTemperature 與畫格時間一起記錄 20~30 分鐘,並用工作管理員「處理程序」索引標籤的「GPU 引擎」欄確認遊戲在哪一顆顯示晶片上執行。行動裝置則把 Android 的熱狀態 API(getThermalHeadroom、熱狀態)與 iOS thermalState 和 FPS 一起記錄 符合的跡象 溫度上升、時脈開始下降的時間點起 FPS 跟著下降,或只有在電池、省電模式下時脈偏低。也可能是遊戲正在內建顯示晶片上執行 不符合的跡象 時脈與溫度不變、FPS 卻下降時,是「背景處理程序占用 CPU」或「用戶端記憶體洩漏」 確認方式 在玩家端環境確認
深入了解 有兩顆顯示晶片的筆電,有時會為了省電讓遊戲在較慢的內建顯示晶片上執行。遇到「筆電規格很好 FPS 卻很低」的回報,先確認遊戲在哪一顆顯示晶片上執行。
出處 5 筆
計時器解析度 Timer resolution (Windows 15.6ms)
ID co-timer · 主要負責 遊戲開發團隊(用戶端開發)
Windows 的預設計時器以 15.6ms 為單位,所以「只休息 1ms」實際上會等到下一個計時器週期,最長拉長到 15.6ms。
為什麼 用 Sleep(短暫等待)的方式實作畫格限制與封包傳送 → 於是 OS 只以 15.6ms 為單位喚醒 → 畫面上 畫格間隔與輸入傳送間隔忽長忽短
症狀 卡頓
因素 抖動
誰會遇到 只有我
何時 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 使用高解析度計時器、改以事件或 V-Sync 為基礎控制節奏,取代 Sleep 等待。
數值參考 以 15.6ms 為單位無法對準 16.7ms 的間隔,畫格間隔會在 15.6ms 與 31.2ms 之間來回跳動。
圖表上 一開始就一直偏高 · 畫格間隔分布
查看位置 查看 PresentMon 的 MsBetweenPresents(畫格間隔)分布,以及 powercfg /energy 報告中的「Platform Timer Resolution」項目(變更過計時器解析度的處理程序) 符合的跡象 畫格間隔集中在 15.6ms、31.2ms 這類 15.6ms 的倍數,且遊戲沒有要求更高的計時器解析度 不符合的跡象 間隔平均分散時,比起計時器,更可能是「背景處理程序占用 CPU」或畫格負載 確認方式 在玩家端環境確認
深入了解 以前的 Windows 只要有一個程式把計時器改成 1ms,就會套用到所有程式,所以才有「開著瀏覽器遊戲會變順」的說法。從 Windows 10 2004 版起只套用到提出要求的程式,Windows 11 則可能不套用最小化或完全被遮住、也沒有發出聲音的視窗所提出的要求。
出處 6 筆
手機 App 切到背景 App suspended in background
ID co-mobile-bg · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
為了看通知而把 App 暫時切到背景時,OS 會在幾秒後暫停(suspend)App,這段期間伺服器就會切斷玩家的連線。
為什麼 為了看訊息、接電話把遊戲切到背景 → 於是 遊戲引擎暫停遊戲進行,OS 很快也會停止 App 與網路 → 畫面上 回到遊戲時早已斷線,只能重新連線
症狀 斷線
因素 停滯, 遺失
誰會遇到 只有我
何時 閒置一段時間後, 做特定動作時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:回到前景時不要等待已中斷的連線,直接用 session token 自動重新連線(不必重新登入就能接續),並一次取得最新狀態同步。伺服器:心跳封包中斷時先清理連線,但角色 session 在短暫的寬限時間內保留(不立刻踢出),在這段時間內重新連線就用 session token 接續。
數值參考 遊戲引擎通常在切到背景的瞬間就暫停。iOS 會在幾秒後暫停 App,即使申請了額外時間,通常也在數十秒內暫停;Android 14 以上則會在 App 離開畫面約 10 秒後將其凍結(freeze)。
圖表上 連線同時大量中斷 · 斷線次數(心跳逾時)、App 暫停紀錄
查看位置 以 session ID 對照用戶端 log 中 App 暫停與恢復的時間(Unity 為 OnApplicationPause)和伺服器端的斷線原因與時間。Android 也一併查看 ApplicationExitInfo 留下的處理程序結束原因(REASON_LOW_MEMORY 等) 符合的跡象 伺服器因心跳逾時斷線之前,用戶端剛進入暫停狀態,恢復後隨即重新連線 不符合的跡象 App 在前景時就斷線的話,是「NAT mapping 過期」、「電信業者共用 IP(CGNAT)」或「Wi-Fi ↔ LTE/5G 切換」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 手機記憶體不足時,有時會直接結束切到背景的遊戲。這就是切去相機或付款、驗證 App 再回來時,遊戲會從頭重新啟動的原因。越低階的裝置越常見。
出處 5 筆
ID co-netswitch · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(網路基礎設施)
走出家門時 Wi-Fi 斷掉、改用 LTE/5G,自己的 IP 位址會改變,原本的連線就此失效。
為什麼 Wi-Fi 訊號變弱,切換到行動網路 → 於是 自己的 IP 位址改變,用舊位址建立的連線無法再收送資料 → 畫面上 短暫停住後斷線,或重新連線
症狀 定格 , 斷線
因素 遺失
誰會遇到 只有我
何時 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 伺服器:位址改變時也用 session token 接續成同一位玩家,並立刻清理舊位址的連線;評估位址改變也能延續連線的協定(QUIC 的連線遷移等)。用戶端:偵測到網路切換時,不要等心跳逾時,直接用 session token 重新連線。
基礎設施團隊要做的事 使用 QUIC 連線遷移時,把負載平衡器設定成依連線 ID 選擇伺服器,不依位址與 port(依位址與 port 選擇時,位址改變後的封包會被送到別台伺服器)。
圖表上 連線同時大量中斷 · 斷線與重新連線次數、重新連線時改變的 IP
查看位置 在伺服器連線 log 中找出同一個 session token 從不同 IP 重新連線的紀錄,並對照用戶端預設網路變更回呼(registerDefaultNetworkCallback)的時間 符合的跡象 斷線後重新連線的 IP 從 Wi-Fi(家用線路)網段變成行動電信業者網段,或反過來,且在那之前剛收到網路切換回呼 不符合的跡象 IP 沒變卻斷線時,是「基地台換手(移動中)」或「行動網路訊號弱、收訊死角」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
安全軟體的封包檢查 Antivirus / firewall inspection
ID co-security · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
防毒軟體、防火牆檢查每一個封包時延遲會增加,太過頭還會把遊戲誤判為攻擊而封鎖。
為什麼 安全軟體逐一檢查收送的封包 → 於是 每個封包都多出延遲,檢查來不及時封包會被丟棄 → 畫面上 ping 不規則地飆高,或連線被封鎖
症狀 卡頓 , 連不上/無限讀取
因素 抖動, 遺失
誰會遇到 只有我
何時 一直都有, 剛登入/維護剛結束
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 維護安全軟體相容性清單,安裝時在 Windows 防火牆加入遊戲的例外規則。
外部要做的事 引導玩家在安全軟體中把遊戲加入例外;遊戲被誤判為攻擊時,請安全軟體廠商修正誤判。
數值參考 正常情況下,封包檢查所花的時間通常不到 1ms。問題出在檢查模組塞車或有 bug 時,以及把遊戲通訊誤判為攻擊時。
圖表上 只有部分偏高 · RTT、連線失敗(依玩家)
查看位置 暫時關閉安全軟體,或把遊戲加入例外後比較。Windows 在稽核原則中開啟 Audit Filtering Platform Connection、Audit Filtering Platform Packet Drop 後,「安全性」log 會留下 5157(連線遭封鎖)、5152(封包遭封鎖);丟棄的封包數用效能監視器的 WFPv4\Packets Discarded/sec 查看 符合的跡象 留下前往遊戲伺服器位址的連線或封包遭封鎖的紀錄,或關閉安全軟體後 ping 飆高、無法連線的情況消失 不符合的跡象 與安全軟體無關、同一個家裡的其他裝置也一樣時,問題在分享器或線路 確認方式 在玩家端環境確認
出處 6 筆
接收緩衝區溢位 Socket receive buffer overflow
ID co-rcvbuf · 主要負責 遊戲開發團隊(用戶端開發)
遊戲太忙,太晚從 socket(OS 提供的網路收送介面)取出封包時,OS 緩衝區就會溢位。
為什麼 畫格延誤,遊戲太晚讀取 socket → 於是 OS 接收緩衝區滿了,UDP 直接丟棄,TCP 則縮小接收視窗讓對方停止傳送 → 畫面上 瞬移(UDP)或快轉(TCP)
症狀 瞬移 , 快轉
因素 遺失, 停滯
誰會遇到 只有我
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 專用的接收執行緒、調整緩衝區大小(SO_RCVBUF)。
數值參考 預設接收緩衝區依 OS 與設定為數十~數百 KB。人多的地方,更新量有時每秒可達數百 KB。
圖表上 隨人數/負載上升 · UDP 接收緩衝區丟棄數、畫格時間
查看位置 把 Windows 效能監視器的 Microsoft Winsock BSP\Dropped Datagrams(因 socket 接收緩衝區不足而丟棄的 UDP 數)與 UDPv4\Datagrams Received Errors 跟畫格時間一起記錄,遊戲端則計算收到封包序號中的缺漏 符合的跡象 人多的地方或長畫格剛結束時 Dropped Datagrams 增加,同一瞬間遊戲序號出現缺漏。同一時間線路端沒有封包遺失 不符合的跡象 Dropped Datagrams 沒變、只有序號缺漏時,是傳輸路徑上的封包遺失 確認方式 在玩家端環境確認
出處 5 筆
ID co-swap · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
同時開著數十個瀏覽器分頁和遊戲時,OS 會把遊戲的一部分記憶體移到磁碟上。
為什麼 整體 RAM 不足 → 於是 OS 把遊戲暫時沒用到的記憶體移到磁碟 → 畫面上 再次用到那部分的瞬間,依儲存裝置不同會停住數十~數百 ms
症狀 定格 , 卡頓
因素 停滯
誰會遇到 只有我
何時 移動中/切換地圖時, 偶爾隨機發生
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 減少記憶體用量,剩餘記憶體不多時顯示警告。
外部要做的事 告知玩家最低配備,並引導玩家在遊戲中關閉其他程式(瀏覽器分頁等)。
圖表上 偶爾隨機飆高 · 硬分頁錯誤、記憶體用量
查看位置 把效能監視器的 Memory\Pages Input/sec(為了解決硬分頁錯誤而從磁碟讀入的分頁數)與工作管理員「效能」索引標籤的記憶體用量、已認可量跟畫格時間一起記錄 符合的跡象 停住的瞬間 Pages Input/sec 往上衝,記憶體幾乎全滿。關掉瀏覽器等其他程式後就消失 不符合的跡象 記憶體還有餘裕、Pages Input/sec 也很平靜時,是「主執行緒同步載入、著色器編譯」或「儲存裝置太慢,資源串流跟不上」 確認方式 在玩家端環境確認
出處 3 筆
ID co-vram · 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
畫質選項需要的記憶體比顯示卡記憶體還大時,OS 會把貼圖移到電腦的主記憶體再搬回來,因此出現卡頓。
為什麼 高貼圖選項,加上人多的地方各式各樣的裝備與特效,讓顯示卡記憶體全滿 → 於是 OS 把暫時沒用到的貼圖移到電腦的主記憶體,需要時再透過較慢的 PCIe 匯流排搬回來 → 畫面上 每次出現新場景或新角色都會頓一下,貼圖有一段時間是模糊的
症狀 卡頓 , 定格
因素 停滯
誰會遇到 只有我
何時 人潮湧入時, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲開發團隊要做的事 依顯示卡記憶體大小設定選項預設值、超出記憶體預算時自動調低貼圖品質、人多的地方簡化角色貼圖。
外部要做的事 引導玩家調低貼圖選項,同時開兩個用戶端時要把選項調得更低。
數值參考 顯示卡記憶體每秒可讀取數百 GB,但與電腦主記憶體之間往來的 PCIe 匯流排依世代約為每秒 16~64GB,慢了十倍以上。
圖表上 碰到上限後持平 · 專用 GPU 記憶體、共用 GPU 記憶體
查看位置 把工作管理員「效能」索引標籤 GPU 項目中的專用 GPU 記憶體、共用 GPU 記憶體圖表(也可以在「詳細資料」索引標籤加上各處理程序的欄位)跟 PresentMon 畫格時間一起查看 符合的跡象 專用 GPU 記憶體貼著上限持平、共用 GPU 記憶體持續增加的期間經常頓一下,調低貼圖選項後就消失 不符合的跡象 專用記憶體還有餘裕時,是「儲存裝置太慢,資源串流跟不上」或「主執行緒同步載入、著色器編譯」 確認方式 在玩家端環境確認
深入了解 Windows 工作管理員的 GPU 項目中,「專用 GPU 記憶體」全滿、「共用 GPU 記憶體」增加,就是這個狀態。在同一台電腦上開兩個用戶端會更快用滿(見「記憶體/VRAM 不足導致串流失敗」項目)。
出處 4 筆
Wi-Fi 背景掃描 Periodic Wi-Fi background scan
ID co-wifi-scan · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
OS 為了尋找周圍的 Wi-Fi,會定期切換到其他頻道,這段期間通訊會短暫停止。
為什麼 OS 或驅動程式以固定週期搜尋周圍的 Wi-Fi → 於是 搜尋期間收送短暫停止 → 畫面上 ping 以非常固定的間隔(例如每 60 秒)飆高
症狀 卡頓 , 瞬移
因素 抖動
誰會遇到 只有我
何時 固定週期
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 在遊戲中要求減少無線掃描的模式(Android 為低延遲 Wi-Fi 模式 WIFI_MODE_FULL_LOW_LATENCY,Windows 為 WlanSetInterface 的媒體串流模式。依裝置與驅動程式不同,有時沒有效果)。
外部要做的事 引導玩家改用有線連線、調整定位服務與 Wi-Fi 自動搜尋設定、更新無線網路驅動程式。
數值參考 通常每次數十~數百 ms。規律得太過頭時,先懷疑這個原因。
圖表上 固定週期飆高 · 到分享器的 RTT
查看位置 在遊戲中用 ping /t 量測分享器位址(ipconfig 顯示的預設閘道)幾分鐘,記下飆高的間隔。再改用有線做同樣的量測 符合的跡象 到分享器的 ping 以非常固定的間隔(例如 60 秒)飆高數十~數百 ms,改用有線就消失 不符合的跡象 飆高的間隔不規則時,是「Wi-Fi 干擾與訊號減弱」。到分享器都正常、只有分享器之後的區段飆高時,問題在線路或電信業者區段 確認方式 在玩家端環境確認
出處 5 筆
網路卡省電、驅動程式問題 NIC power saving, driver bugs
ID co-driver · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
有線網路卡或 Wi-Fi 晶片在封包與封包之間進入省電狀態時,要重新喚醒需要時間。
為什麼 網路裝置的省電功能開著,或驅動程式太舊 → 於是 喚醒(wake-up)延遲,偶爾裝置會重新啟動 → 畫面上 不規則的延遲,少數情況會停住數秒
症狀 卡頓 , 定格
因素 抖動, 遺失
誰會遇到 只有我
何時 閒置一段時間後, 偶爾隨機發生
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 Android 用戶端在遊戲中要求低延遲 Wi-Fi 模式(WIFI_MODE_FULL_LOW_LATENCY),關閉 Wi-Fi 省電。
外部要做的事 引導玩家更新網路驅動程式、在裝置管理員中關閉網路裝置的省電;整個畫面頓一下且聲音出現雜音時,引導玩家用 LatencyMon 找出造成問題的驅動程式。
圖表上 偶爾隨機飆高 · DPC 與 ISR 時間、到分享器的 RTT
查看位置 用 Windows 效能記錄器(WPR)錄製,在 Windows 效能分析器(WPA)的 DPC/ISR 圖表中找出執行時間長的驅動程式(Module 欄),並在裝置管理員中確認網路介面卡的電源管理(省電)設定 符合的跡象 頓一下的時間點,網路驅動程式的 DPC、ISR 連續執行好幾 ms,或關閉省電後不規則的延遲消失 不符合的跡象 DPC 很短、關閉省電後仍一樣時,是「Wi-Fi 干擾與訊號減弱」或「Wi-Fi 背景掃描」 確認方式 在玩家端環境確認
深入了解 驅動程式為了處理中斷(interrupt)而長時間占用 CPU 時(Windows 稱為 DPC 延遲),遊戲執行緒在這段期間也用不到該核心。這時 CPU 使用率很低,整個畫面卻會頓一下,聲音也會出現雜音。用 LatencyMon 這類工具可以找出是哪個驅動程式,Wi-Fi 與有線網路驅動程式是常見的原因。
出處 4 筆
ID co-other-apps · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
雲端同步、大型下載、遊戲更新在同一台電腦上執行時,遊戲封包得在佇列中等待。
為什麼 其他 App 把上傳、下載用到滿 → 於是 遊戲封包堆積在電腦與分享器的佇列中 → 畫面上 ping 暴增、輸入延遲、快轉
症狀 輸入延遲 , 快轉
因素 延遲, 抖動
誰會遇到 只有我, 同一個家
何時 偶爾隨機發生
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 我方的啟動器與更新程式在遊戲中暫停背景下載或限制速度。
外部要做的事 引導玩家限制下載速度,並在遊戲中關閉自動更新。
圖表上 隨人數/負載上升 · RTT、電腦收送量
查看位置 把效能監視器的 Network Interface\Bytes Sent/sec、Bytes Received/sec 與 ping 一起記錄。做法與開著 ping、刻意進行大量傳輸的 bufferbloat 測試相同 符合的跡象 下載或上傳接近線路速度的期間,ping 上升數十~數百 ms,停止傳輸後馬上恢復 不符合的跡象 電腦收送量很低、ping 卻上升時,是同一個家裡其他裝置造成的「Bufferbloat(分享器佇列)」或電信業者區段 確認方式 在玩家端環境確認
出處 4 筆
視窗最小化或非作用中時的處理限制 Minimized / unfocused window throttling
ID co-unfocused · 主要負責 遊戲開發團隊(用戶端開發)
切到其他視窗或把遊戲最小化時,遊戲與 Windows 會為了省電讓遊戲跑得比較慢。回到遊戲時,累積的封包會一口氣湧入,或者早已斷線。
為什麼 用 Alt+Tab 切到其他視窗,或把遊戲最小化 → 於是 遊戲看不見的期間,FPS 會大幅降低或停止,Windows 也會調低看不見的程式的優先順序 → 畫面上 切回來的瞬間出現快轉,切出去太久則會斷線
症狀 快轉 , 卡頓 , 斷線
因素 停滯
誰會遇到 只有我
何時 做特定動作時, 閒置一段時間後
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 視窗看不見時,封包接收與心跳封包仍在獨立執行緒中持續處理;確認引擎的「在背景執行」設定;切回來時一次同步到最新狀態。
數值參考 視窗看不見時把 FPS 降到 5~10,一個畫格就是 100~200ms。每個畫格處理一次封包的遊戲,讀取封包也會晚同樣的時間。
圖表上 中斷後一次湧入 · 畫格間隔(切換視窗前後)、已處理的封包數
查看位置 開著 PresentMon 試著按 Alt+Tab 或最小化,查看視窗看不見時的畫格間隔。在遊戲 log 中記錄視窗焦點改變的時間,與斷線原因對照 符合的跡象 視窗看不見的期間畫格間隔拉長到 100ms 以上,或紀錄中斷;切回來的瞬間一次處理累積的封包而出現快轉。切出去太久時因心跳逾時而斷線 不符合的跡象 視窗一直開在前景也一樣時,是「背景處理程序占用 CPU」或網路端問題 確認方式 在玩家端環境確認
深入了解 Windows 11 不保證最小化或完全被遮住、也沒有發出聲音的視窗程式能取得 1ms 計時器。以電池運作的筆電會把這類程式降到最省電的速度,若 CPU 混用不同種類的核心,有時也會把它們放到較慢的效率核心上執行。同一台電腦的兩個用戶端中只有背景那一個異常時,請一併參考「背景視窗的處理限制」項目。
出處 4 筆
overlay 程式干擾 Overlays and screen hooks
ID co-overlay · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
通訊軟體、啟動器、錄影、FPS 顯示程式為了在遊戲畫面上疊加自己的 UI,會介入遊戲的渲染流程(hook)。每個畫格的工作量因此增加,偶爾還會與遊戲衝突,造成頓一下或遊戲被強制關閉。
為什麼 通訊軟體、遊戲啟動器、顯示卡工具、錄影程式的 overlay 開著 → 於是 每次把畫格輸出到畫面時,overlay 都會介入疊加自己的 UI → 畫面上 畫格一點一點變慢,通知跳出的瞬間頓一下,或出現畫面錯誤、強制關閉(玩家看起來像斷線)
症狀 卡頓 , 定格 , 斷線
因素 停滯
誰會遇到 只有我
何時 一直都有, 偶爾隨機發生
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 在閃退報告與卡頓 log 中一併收集執行中的 overlay 清單。
外部要做的事 收到回報時,引導玩家關閉所有 overlay 再測一次。
圖表上 只有部分偏高 · 畫格時間、閃退次數(開啟 overlay 的玩家)
查看位置 關閉所有 overlay,比較同一場景的 PresentMon 畫格時間;有閃退時,查看事件檢視器中事件識別碼 1000 的錯誤模組名稱(Faulting module name) 符合的跡象 關閉 overlay 後頓一下、畫面錯誤消失,或閃退的錯誤模組是 overlay 程式的 DLL 不符合的跡象 關閉所有 overlay 後仍一樣時,是顯示卡驅動程式或「用戶端閃退」 確認方式 在玩家端環境確認
深入了解 只有特定的人卡頓或遊戲被關掉,又無法用配備解釋時,先懷疑 overlay 與遊戲安全模組的衝突。
出處 3 筆
顯示器、輸入裝置與畫格生成的延遲 Display, input device and frame generation latency
ID co-display-input · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
ping 正常、操作卻很沉重時,可能是電視的影像處理、無線控制器或畫格生成功能在輸入與畫面之間增加了延遲。
為什麼 電視的遊戲模式沒開、使用藍牙或無線控制器,或開啟了畫格生成(DLSS、FSR 畫格生成) → 於是 電視在進行畫質處理時會延後輸出畫格,無線輸入會因傳輸週期與干擾而晚到,畫格生成則要等下一個畫格才能做出中間的畫格 → 畫面上 ping 與 FPS 數字都很好,按下按鍵後卻要過一會兒才反映在畫面上,形成輸入延遲
症狀 輸入延遲
因素 延遲
誰會遇到 只有我
何時 一直都有
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 把畫格生成設為可選選項,並說明開啟後輸入延遲可能增加;使用畫格生成時一併整合顯示卡廠商的低延遲功能(NVIDIA Reflex、AMD Anti-Lag 2);在遊戲中顯示電腦端從輸入到畫面的延遲;Android TV 與機上盒版本用 Window.setPreferMinimalPostProcessing(true) 要求電視進入低延遲模式(ALLM)。
外部要做的事 引導玩家開啟電視、螢幕的遊戲模式(ALLM),競技類內容改用有線控制器並關閉畫格生成,藍牙裝置放近一點,Wi-Fi 改用 5GHz。
數值參考 60Hz 畫面光是傳送一個畫格就要 16.7ms,120Hz 則要 8.3ms。舊款 Xbox 控制器每 8ms 讀取並傳送一次輸入。電視影像處理增加的延遲因機種而異,很難用一個數字說明,遊戲模式就是減少這些處理的設定。畫格生成方面,AMD 建議在生成前的畫格率達 60FPS 以上時使用。
圖表上 一開始就一直偏高 · 從輸入到畫面的延遲
查看位置 開啟、關閉畫格生成,比較 PresentMon 的 MsAllInputToPhotonLatency(從鍵盤、滑鼠輸入到送往螢幕為止),並用 FrameType(只在驅動程式或 SDK 回報時才會記錄)查看是否混有生成的中間畫格。這個值不包含控制器的無線區段與電視內部的處理,這部分要切換電視遊戲模式、有線控制器來比較 符合的跡象 ping 正常,關閉畫格生成後從輸入到畫面的延遲減少,或改用電視遊戲模式、有線控制器後體感延遲消失 不符合的跡象 這些設定全部改過仍一樣,且 ping 偏高或飆高時,是網路端問題。電腦端延遲因垂直同步或畫格佇列而偏高時,是「垂直同步(V-Sync)與渲染佇列」 確認方式 在玩家端環境確認
深入了解 網路延遲可以從 ping 看出來,這種延遲卻不會反映在 ping 上。因此遇到「ping 很低卻很 lag」的回報時,要先確認這裡。畫格生成會讓畫面上的 FPS 數字提高到約兩倍,但要做出中間的畫格,就得等下一個真正的畫格,所以輸入反映到畫面所需的時間會變長(AMD 表示這在設計上就會增加延遲)。藍牙裝置與 Wi-Fi 使用同樣的 2.4GHz 頻段,受到干擾時輸入可能中斷或跳動。會加大電腦內部延遲的垂直同步與渲染佇列,請參考「垂直同步(V-Sync)與渲染佇列」項目。
出處 9 筆
L3 家用網路
10 個原因 · 完整版章節
Wi-Fi 干擾與訊號減弱 Wi-Fi interference, weak signal
ID hn-wifi · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
訊號弱或有干擾時,無線區段要反覆重送好幾次,封包抵達的時間就會忽快忽慢。
為什麼 牆壁、距離、微波爐、藍牙、鄰居的分享器讓無線訊號品質變差 → 於是 無線區段傳送失敗 → 重傳好幾次 → 畫面上 封包抵達忽快忽慢(抖動),角色走走停停,嚴重時封包遺失而出現瞬移
症狀 卡頓 , 瞬移 , 拉回
因素 抖動, 遺失
誰會遇到 只有我, 同一個家
何時 偶爾隨機發生, 一直都有
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 依線路狀態自動調整內插緩衝長度,抖動或封包遺失嚴重時在畫面上顯示網路狀態。
外部要做的事 引導玩家改用有線連線、使用 5GHz/6GHz、移動分享器的位置。
數值參考 每重傳一次約多花 1~4ms。訊號弱時會以較低速率重送好幾次,還要等頻道空出來,有時會飆高 50~200ms。平均 ping 看起來正常,這正是容易誤判的地方。
圖表上 偶爾隨機飆高 · 到分享器的 RTT
查看位置 用 ping /t 量測到分享器位址(ipconfig 顯示的預設閘道)幾分鐘,並用 netsh wlan show networks mode=bssid 查看自己分享器的訊號強度與頻道。在同一個位置改用有線比較 符合的跡象 從到分享器的 ping 開始就不規則地飆高數十~數百 ms,偶爾有封包遺失,且訊號強度偏低。改用有線或靠近分享器就消失 不符合的跡象 到分享器都很平穩、只有分享器之後的區段飆高時,問題在線路或電信業者區段。只以固定間隔飆高時,是「Wi-Fi 背景掃描」 確認方式 在玩家端環境確認
深入了解 Mesh Wi-Fi 的分享器(節點)之間以無線相連(無線回程,backhaul)時,負責中繼的節點在接收期間無法傳送,還要和使用同一頻道的前後區段分享傳送機會,壅塞時處理量可能下降、延遲增加。有回程專用無線頻段的產品影響可能較小;節點之間改用有線(乙太網路)連接,這一段就不再走無線。電力線網路橋接器(PLC)也和 Wi-Fi 一樣,採用先確認媒介空閒再傳送的方式(CSMA/CA),品質會隨家電產生的雜訊與家電的開關而隨時變化,可能造成重傳與抖動。
實際案例 Square Enix 2021: FINAL FANTASY XIV 資料片上市的壅塞與登入排隊錯誤
出處 8 筆
Wi-Fi 頻道壅塞 Crowded Wi-Fi channel
ID hn-channel · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
在公寓大樓這類有數十台分享器的地方,大家共用同一個頻道,只能等待傳送機會。
為什麼 數十台分享器使用同一個 2.4GHz 頻道 → 於是 要傳送就得等其他裝置傳完、頻道空出來 → 畫面上 大家回到家的晚間時段抖動(封包抵達間隔忽長忽短)增加,出現卡頓
症狀 卡頓 , 輸入延遲
因素 抖動, 延遲
誰會遇到 同一個家
何時 晚間尖峰時段
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 抖動增加時自動加長內插緩衝。
外部要做的事 引導玩家使用 5GHz/6GHz、較不擁擠的頻道或有線連線。
圖表上 只在特定時段偏高 · 到分享器的 RTT 與抖動
查看位置 用 netsh wlan show networks mode=bssid 查看周圍 Wi-Fi 的頻道與訊號強度,並在晚上與白天量測到分享器的 ping 進行比較 符合的跡象 在 2.4GHz 同一頻道上偵測到很多周圍的分享器,到分享器的抖動只在晚間時段變大。改用 5GHz/6GHz 或較不擁擠的頻道後減少 不符合的跡象 與時段無關也會飆高時,是「Wi-Fi 干擾與訊號減弱」。到分享器正常、只有晚上分享器之後的區段變差時,是「尖峰時段 peering 區段壅塞」 確認方式 在玩家端環境確認
出處 4 筆
ID hn-bufferbloat · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
家人上傳影片或下載大型檔案時,分享器佇列會堆積相當於數百 ms 的封包,遊戲封包也得排在後面等待。
為什麼 家人上傳影片、雲端備份、自己的直播推流、大量下載把線路塞滿 → 於是 分享器或數據機把滿出來的封包堆進很大的佇列 → 畫面上 遊戲封包也排在佇列後面等待,ping 暴增到數百 ms
症狀 輸入延遲 , 快轉 , 瞬移
因素 延遲, 抖動
誰會遇到 同一個家, 只有我
何時 偶爾隨機發生, 晚間尖峰時段
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 ping 突然升到數百 ms 時在畫面上顯示網路狀態(提示可能有同一條線路上的大量傳輸)。
外部要做的事 引導玩家使用有 SQM(fq_codel、CAKE)或 QoS 的分享器,把 SQM 速率設為線路速度的 90~95%(這樣佇列才會產生在分享器內,才有效果),並限制上傳速度。
數值參考 上傳 10Mbps 的線路配上 1MB 緩衝區,佇列最長會累積到相當於 800ms 的量。
圖表上 隨人數/負載上升 · RTT、線路上傳與下載用量
查看位置 開著 ping 用測速把線路塞滿,或使用量測負載下延遲的網頁測試(Bufferbloat.net 的說明)。與分享器介面上的上傳、下載用量一起查看 符合的跡象 上傳或下載塞滿線路的期間 ping 升到數百 ms,傳輸結束後恢復(負載下延遲超過 50ms 就值得懷疑)。開啟 SQM 後消失 不符合的跡象 線路很閒 ping 卻飆高時,是「Wi-Fi 干擾與訊號減弱」或「線路品質不良」 確認方式 在玩家端環境確認
深入了解 上傳方向特別容易塞住,因為 Cable 寬頻與行動網路的上傳頻寬往往比下載窄得多。光纖頻寬充足的家庭則是 Wi-Fi 區段成為瓶頸,同樣的情況會發生在分享器的無線佇列。遊戲封包很小,幾乎不占頻寬,但同樣得在佇列中等待。只有上傳方向塞住時,延遲的只有自己的輸入,其他人的動作正常。手機上,同一支手機的照片備份與 App 更新會塞滿手機數據機與基地台的佇列,造成同樣的情況。
出處 4 筆
ID hn-nat · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
分享器會把一段時間沒有封包往來的閒置連線從 NAT 表中刪除。這是閒置一段時間後一有動作就斷線的常見原因。
為什麼 分享器把「內部裝置 ↔ 外部伺服器」的連線記錄在 NAT 表(位址轉換表)中 → 於是 一段時間沒有封包就從表中刪除(UDP 通常為 30~120 秒) → 畫面上 伺服器的封包進不了家中網路,造成斷線
症狀 斷線
因素 遺失
誰會遇到 只有我, 同一個家
何時 閒置一段時間後
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:以最短閒置逾時一半以下的間隔送出心跳封包(UDP mapping 只有從家中送出的封包才能確實更新,所以由用戶端送),斷線時自動重新連線。伺服器:回應心跳封包,一段時間沒收到就先清理連線;mapping 被刪除導致外部位址、port 改變時,也要用 session token(連線時取得的識別碼)確認是同一位玩家並接續。
圖表上 連線同時大量中斷 · 斷線次數(心跳逾時)、斷線前的閒置時間
查看位置 收集伺服器端的斷線原因,以及斷線前該連線最後一次封包往來後經過的時間(閒置時間),查看其分布。測試時把 UDP 封包間隔逐步拉長到 30 秒、60 秒、120 秒,量出回應中斷的間隔 符合的跡象 只有閒置中的連線會斷,且閒置時間集中在 30~120 秒這類特定值之後。把心跳間隔縮得比這更短就消失 不符合的跡象 移動中也會斷線時,問題在線路或路由。只在特定行動電信業者集中於較短的值時,是「電信業者共用 IP(CGNAT)」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
分享器效能不足、過熱 Router CPU / session table exhaustion
ID hn-router · 主要負責 外部(外部)
便宜的分享器同時接了數十台裝置、數千條連線時,分享器本身就處理不過來。
為什麼 數十台裝置,加上 P2P、BT(torrent)開啟數千條連線 → 於是 分享器的 CPU 與 session 表飽和 → 畫面上 封包處理延遲、封包遺失,新連線失敗
症狀 卡頓 , 連不上/無限讀取 , 斷線
因素 遺失, 抖動
誰會遇到 同一個家
何時 開越久越嚴重, 偶爾隨機發生
負責單位 主要負責 外部(外部)
外部要做的事 引導玩家重新啟動分享器(暫時解法)、更換分享器、整理會開大量連線的程式(P2P、BT)。
圖表上 碰到上限後持平 · 分享器 CPU 與連線數、到分享器的 RTT
查看位置 在分享器管理介面查看 CPU 使用率、連線(session)數、連線中的裝置數(分享器有支援時),並比較重新啟動前後到分享器本身的 ping 符合的跡象 連線數多時,從到分享器的 ping 開始就飆高或遺失封包,新連線也失敗。重新啟動後正常一陣子,之後又變差 不符合的跡象 到分享器正常、只有分享器之後的區段變差時,問題在線路或電信業者區段 確認方式 在玩家端環境確認
出處 2 筆
ID hn-handover · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
搭公車、捷運移動時,切換基地台的期間通訊會中斷。
為什麼 移動中連線的基地台改變 → 於是 通常只空白數十 ms,但訊號差導致切換失敗時,有時會中斷數百 ms~數秒 → 畫面上 停住後瞬移,時間長的話會斷線
症狀 定格 , 瞬移 , 斷線
因素 遺失
誰會遇到 只有我
何時 移動中/切換地圖時
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:設定能撐過短暫中斷的逾時,快速重新連線。伺服器:設定中斷數秒也不立刻踢出的逾時,重新連線時接續同一個 session。
外部要做的事 向玩家說明移動中(公車、捷運)斷線是基地台切換造成的。
圖表上 中斷後一次湧入 · 已接收封包數、RTT
查看位置 確認斷線回報是否發生在移動中(公車、捷運),並查看用戶端 log 中的接收空白時間、網路類型與訊號變化 符合的跡象 只有移動中接收會空白數百 ms~數秒再一次湧入,靜止時無法重現 不符合的跡象 靜止時也一樣時,是「行動網路訊號弱、收訊死角」或「5G↔LTE 頻繁切換(5G 涵蓋邊緣)」 確認方式 在玩家端環境確認
出處 2 筆
ID hn-rrc · 主要負責 遊戲開發團隊(用戶端開發)
手機一段時間沒有通訊時,會把無線連線降到低耗電狀態,下一個封包要送出時得重新拉高,因此變慢。
為什麼 短暫沒有通訊時,手機把無線連線切換到省電狀態 → 於是 要送出下一個封包,必須重新拉高連線 → 畫面上 閒置一段時間後的第一個動作特別慢
症狀 輸入延遲
因素 延遲
誰會遇到 只有我
何時 閒置一段時間後
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 以輕量的週期性傳送維持活躍狀態(以耗電為代價)。
數值參考 LTE 通常在約 10 秒沒有通訊後進入省電,重新拉高需要數十~數百 ms(實測例:約 0.3~0.6 秒)。3G 則要 1 秒以上。
圖表上 只有部分偏高 · 閒置後第一個請求的 RTT(行動網路)
查看位置 把遊戲內的 RTT 依與前一次通訊的間隔分組查看。比較在行動網路上閒置超過 10 秒後送出的第一個封包,與連續送出的封包的 RTT 符合的跡象 在行動網路上,只有閒置後送出的第一個封包慢了數百 ms,緊接著送出的封包正常。在 Wi-Fi 上沒有差異 不符合的跡象 連續送出也很慢時,問題在訊號、線路或路由 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
ID hn-weak-cell · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
在電梯、地下室、建築物深處,重傳會增加、速度下降,最後斷線。
為什麼 移動到訊號弱的地方 → 於是 無線重傳增加、速度下降、瞬間斷訊 → 畫面上 抖動與封包遺失造成卡頓、瞬移,最後斷線
症狀 卡頓 , 瞬移 , 斷線
因素 抖動, 遺失
誰會遇到 只有我
何時 移動中/切換地圖時
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 改善重新連線流程,顯示網路品質。
外部要做的事 向玩家說明這是在訊號弱的地方(電梯、地下室、建築物深處)發生的問題。
圖表上 只有部分偏高 · RTT、封包遺失(依行動網路玩家)
查看位置 確認回報斷線時的地點(電梯、地下室、建築物內)與手機的訊號顯示,並在訊號好的地方重複同樣的動作比較 符合的跡象 只有在訊號弱的地方 RTT 與封包遺失增加並斷線,移到訊號好的地方就消失 不符合的跡象 訊號良好也一樣時,問題在電信業者區段或伺服器端 確認方式 在玩家端環境確認
出處 1 筆
ID hn-5g-flip · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
在 5G 訊號弱的建築物內或 5G 涵蓋邊緣,手機會頻繁在 5G 與 LTE 之間切換,每次切換 ping 都會飆高或通訊短暫中斷。
為什麼 身處 5G 訊號時好時壞的地方(建築物內、5G 涵蓋邊緣) → 於是 手機隨時在 5G 與 LTE 之間切換,每次都會出現短暫空白 → 畫面上 即使靜止不動,ping 也會不規則地飆高,偶爾定格、瞬移
症狀 卡頓 , 瞬移 , 定格
因素 抖動, 遺失
誰會遇到 只有我
何時 偶爾隨機發生, 移動中/切換地圖時
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 抖動增加時自動加長內插緩衝,在出現延遲時的 log 中一併記錄網路類型(5G、LTE)的變化以區分原因。
外部要做的事 引導玩家在設定中改成 LTE 優先模式比較看看,並建議使用 Wi-Fi。
數值參考 每次切換數十~數百 ms。韓國的 5G 大多採用與 LTE 搭配使用的方式(NSA),因此很容易只有 5G 這一側時連時斷。
圖表上 偶爾隨機飆高 · RTT、網路類型(5G、LTE)變化
查看位置 把手機設定改成 LTE 優先,在同一個位置比較。用戶端把 Android TelephonyDisplayInfo 的網路類型顯示(OVERRIDE_NETWORK_TYPE_NR_NSA 等)變化與 RTT 一起記錄會更確實 符合的跡象 RTT 飆高的時間點與 5G↔LTE 顯示切換的時間點重疊,在 LTE 優先模式下飆高消失 不符合的跡象 網路類型顯示沒有改變也會飆高時,是「行動網路訊號弱、收訊死角」或線路問題 確認方式 在玩家端環境確認
出處 3 筆
公共 Wi-Fi/公司網路限制 Captive portal, restrictive network
ID hn-captive · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
咖啡廳 Wi-Fi 的登入頁面或公司防火牆會擋掉遊戲連線。
為什麼 尚未通過登入頁面認證,或防火牆封鎖遊戲 port 與 UDP → 於是 連線嘗試本身被擋,或只有部分通過 → 畫面上 無法連線,或能登入卻進不了遊戲
症狀 連不上/無限讀取
因素 遺失
誰會遇到 只有我
何時 剛登入/維護剛結束
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:被擋時提示原因(尚未通過登入頁面認證、UDP 遭封鎖等),UDP 被擋時自動切換到替代路徑。伺服器:提供 TCP 443 這類替代路徑。
外部要做的事 引導玩家使用公共 Wi-Fi 時先完成登入頁面認證,在公司網路這類受限的地方改用其他網路。
圖表上 只有部分偏高 · 連線失敗次數(依網路)
查看位置 請連線失敗的玩家改用行動數據等其他網路連線看看,並在伺服器連線 log 中查看 UDP 的第一個封包是否抵達,以及能否透過 TCP 443 替代路徑連上 符合的跡象 只在特定 Wi-Fi(咖啡廳、公司)失敗,換其他網路就馬上連上。尚未通過登入頁面認證,或只有 UDP 到不了伺服器 不符合的跡象 任何網路都失敗時,問題在帳號、伺服器或「DNS 故障與延遲」。特定國家或電信業者整體都失敗時,是「國家/電信業者層級的 UDP 限制與封包檢測」 確認方式 在玩家端環境確認
出處 2 筆
L4 網際網路線路
14 個原因 · 完整版章節
ID isp-distance · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(網路基礎設施), 遊戲開發團隊(伺服器開發)
光在光纖中 1 秒也只能前進約 20 萬 km。伺服器在遠方,效能再好也會慢。
為什麼 伺服器位在遠方(海外伺服器、其他大陸) → 於是 距離越遠,往返時間越長(每 1,000km 至少 10ms) → 畫面上 所有動作都有固定的輸入延遲,判定上也吃虧
症狀 輸入延遲
因素 延遲
誰會遇到 特定地區/電信業者
何時 一直都有
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(網路基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 物理定律無法用程式碼改變,只能緩解:提供地區選擇讓玩家挑選較近的地區伺服器,並用延遲補償(回溯)減少判定上的劣勢。
基礎設施團隊要做的事 伺服器設備/OS:在玩家多的地區設置各地區的伺服器。網路:在玩家附近設置接入據點(edge),選擇繞路較少的線路與路由。
數值參考 首爾–東京約 30ms,首爾–新加坡約 75ms,首爾–美國西岸約 140ms,首爾–歐洲約 230~270ms(往返,以實際路徑為準)。歐洲方向在直線上幾乎沒有大型海底電纜,必須繞經東南亞與蘇伊士或繞經美國,所以延遲比距離推算的長得多。
圖表上 一開始就一直偏高 · RTT(依國家/地區)
查看位置 依連線 IP 標上國家,查看各國的 RTT 分布;再從該地區的雲端區域(region)VM 或 RIPE Atlas probe(依國家、ASN 挑選)用 ping、traceroute 量測到伺服器的延遲 符合的跡象 遠方國家的 RTT 不分時段一直偏高,且數值接近依距離算出的最小延遲(每 1,000km 往返 10ms)與公開的延遲統計 不符合的跡象 遠高於距離能解釋的數值時是「繞遠路的路由」,只在晚上升高時是「尖峰時段 peering 區段壅塞」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 Riot Games 2015: 繞遠路的 League of Legends 流量與 Riot Direct
出處 4 筆
衛星網路(低軌/同步軌道) Satellite internet (LEO, GEO)
ID isp-satellite · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
衛星網路的電波必須往返太空。同步軌道衛星光是往返就超過 0.5 秒;Starlink 這類低軌衛星平時很快,但在重新分配路徑的瞬間延遲會忽高忽低,有時還會短暫中斷。
為什麼 在家中、船上或飛機上,透過同步軌道衛星、低軌衛星網路,或使用衛星的機上 Wi-Fi 連線 → 於是 同步軌道衛星高度約 36,000km,往返距離本身就很長;低軌衛星則以很短的週期重新分配終端設備、衛星、地面站之間的路徑,在那一瞬間會短暫出現延遲與封包遺失 → 畫面上 同步軌道衛星讓所有動作都有很大的輸入延遲;低軌衛星平時正常,但會每隔固定時間出現卡頓、瞬移
症狀 輸入延遲 , 卡頓 , 瞬移
因素 延遲, 抖動, 遺失
誰會遇到 只有我, 同一個家, 特定地區/電信業者
何時 一直都有, 固定週期
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:依抖動自動拉長內插緩衝,重複傳送輸入,以撐過短暫的封包遺失,顯示連線品質。伺服器:訂定判定區間與延遲補償上限時考慮衛星線路的延遲;逾時設定不要因 1 秒左右的空白就立刻把玩家踢出。
外部要做的事 告知玩家衛星網路的延遲可能很大或週期性飆高,建議競技類內容盡量使用地面有線網路。
數值參考 同步軌道(高度 36,000km)光是電波穿越太空的單程就要 260ms,往返超過 520ms(ITU-T G.114)。低軌的 Starlink 依官方資料(15 秒平均值),美國尖峰時段的中位數為 33ms,最差的 1%(p99)也低於 65ms(2024 年);量測研究則發現,每 15 秒重新分配路徑的瞬間延遲會改變,並出現不到 1 秒的短暫中斷。2018 年的機上網路量測中,衛星方式的往返延遲平均為 750ms。
圖表上 只有部分偏高 · RTT、抖動(依衛星網路業者 ASN)
查看位置 查看連線 IP 的 ASN 是否屬於衛星網路業者,另外畫出這些業者玩家的 RTT 分布與時間序列。從該 ASN 的 RIPE Atlas probe 持續 ping 伺服器幾分鐘,或請玩家開著 ping 量測飆高的間隔 符合的跡象 同步軌道業者的 RTT 一直超過 500ms;低軌業者平時為數十 ms,但約每 15 秒 RTT 改變一次或短暫中斷 不符合的跡象 不是衛星業者但 RTT 一直偏高時,是「傳播延遲(物理距離)」或「繞遠路的路由」;不規則飆高時,查 Wi-Fi、行動網路訊號 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 低軌衛星離地面近(Starlink 單段 1.8~3.6ms),平時延遲可能與地面線路相近。但地面站連上網際網路的出口(PoP)若離遊戲伺服器很遠,路徑就會拉長;若經衛星間的雷射鏈路繞行,延遲還會再增加。量測研究認為,15 秒週期的波動與衛星之間的切換無關,來自全球同一時刻進行的路徑重新分配。機上 Wi-Fi 的延遲依方式(衛星、地面基地台)差異很大,若使用同步軌道衛星,就會出現上述的長往返時間。
出處 5 筆
繞遠路的路由 Suboptimal routing
ID isp-routing · 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部)
受電信業者之間互連合約的影響,連到附近的伺服器也可能繞到遠處再回來。
為什麼 自己的電信業者與伺服器端的電信業者沒有直接互連 → 於是 經過其他國家或其他城市,距離與經過的設備都增加 → 畫面上 只有特定電信業者的使用者 ping 特別高
症狀 輸入延遲
因素 延遲
誰會遇到 特定地區/電信業者
何時 一直都有
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部)
基礎設施團隊要做的事 與多家電信業者互連(multihoming),監控各電信業者的 ping 以找出繞路的業者,並與電信業者協調路由。
外部要做的事 請該電信業者調整路由。
數值參考 即使在同一個國家內,ping 也可能因路徑不同而相差兩三倍。
圖表上 一開始就一直偏高 · RTT(依電信業者/ASN)
查看位置 比較各電信業者(ASN)的 RTT,並用較慢業者的 RIPE Atlas probe 或向玩家取得的 traceroute、mtr,查看路徑經過哪些國家與城市。IPv4 與 IPv6 分開量測(mtr -4、-6) 符合的跡象 同一地區只有特定電信業者一直偏高,路徑中有經過其他國家或遠方城市的區段。或只有其中一種位址類型(IPv4 或 IPv6)偏高 不符合的跡象 所有電信業者都差不多高時是「傳播延遲(物理距離)」,只在晚上偏高時是「尖峰時段 peering 區段壅塞」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 IPv4 與 IPv6 的路徑是分開決定的,同一台伺服器也可能只有其中一邊繞遠路而變慢(2016 年 APNIC 量測:同一家電信業者內,出現了 IPv6 比 IPv4 慢 15、25、75ms 的不同使用者群)。採用 Happy Eyeballs(RFC 8305,IPv6 與 IPv4 哪邊先連上就用哪邊)的應用程式會先嘗試 IPv6,只要 IPv6 在建議值 250ms 內連上,就不會再嘗試 IPv4。因此即使 IPv6 稍慢,也很容易走那條路徑。只有特定電信業者 ping 偏高時,請把 IPv4 與 IPv6 分開量測。
實際案例 Riot Games 2015: 繞遠路的 League of Legends 流量與 Riot Direct
出處 6 筆
ID isp-peak · 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部)
晚上 9~11 點左右影音流量暴增,電信業者之間的互連區段(peering)容易壅塞。
為什麼 晚上串流與下載的流量集中湧入 → 於是 peering 區段出現排隊與封包遺失 → 畫面上 只在晚上,特定電信業者的使用者出現卡頓、瞬移
症狀 卡頓 , 瞬移 , 拉回
因素 抖動, 遺失, 延遲
誰會遇到 特定地區/電信業者
何時 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部)
基礎設施團隊要做的事 增加與該電信業者的直接互連,避開壅塞路徑,監控各電信業者晚間的封包遺失與 ping。
外部要做的事 請該電信業者擴充 peering 區段的容量。
圖表上 只在特定時段偏高 · RTT、遺失(依電信業者)
查看位置 依時段畫出各電信業者(ASN)的 RTT 與遺失,並從該業者的 RIPE Atlas probe 或玩家那裡分別取得晚間與白天的 mtr,找出開始遺失的區段 符合的跡象 只有特定電信業者每天晚上 9~11 點左右 RTT 與遺失上升,mtr 顯示從電信業者之間的互連區段一路到目的地都有遺失與延遲 不符合的跡象 所有電信業者一起升高時,問題在我方線路或伺服器端。只有同一個家裡的連線在晚上變差時是「Wi-Fi 頻道壅塞」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 2 筆
ID isp-cable · 主要負責 外部(外部) · 協同 基礎設施團隊(網路基礎設施)
海底電纜一旦斷裂,修復前的幾週(長則幾個月)流量都得繞遠路,剩下的線路也會壅塞。
為什麼 電纜被切斷或設備故障 → 於是 流量集中到繞遠路的路徑與剩下的線路上 → 畫面上 海外玩家的 ping 暴增並出現封包遺失,持續幾天到幾週
症狀 輸入延遲 , 瞬移
因素 延遲, 遺失
誰會遇到 特定地區/電信業者
何時 一直都有
負責單位 主要負責 外部(外部) · 協同 基礎設施團隊(網路基礎設施)
基礎設施團隊要做的事 準備走不同路徑的線路,故障時把流量移到那條路徑。
外部要做的事 向海外玩家公告原因與預計修復時間,並請線路業者確認修復時程。
圖表上 從某個時間點起階梯式上升 · RTT(依海外國家)
查看位置 在各國 RTT、遺失圖表中找出升高的時間點,對照 Cloudflare Radar 的網路中斷摘要與海底電纜業者的公告,再用 traceroute 確認路徑是否繞經其他大陸 符合的跡象 從某個時間點起,特定海外地區的 RTT 升高一階並維持幾天到幾週,同期有電纜故障報告。路徑改走與平常不同、繞遠路的路線 不符合的跡象 幾天內恢復原狀且沒有故障報告時,是「BGP 路由變更與收斂」或電信業者區段的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
BGP 路由變更與收斂 Route change / BGP convergence
ID isp-bgp · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
網際網路的路由資訊改變後重新收斂的幾秒到幾十秒(偶爾幾分鐘)之間,封包會遺失。
為什麼 某個電信業者區段的路由資訊改變 → 於是 幾秒到幾十秒之間封包消失,或切換到新路徑 → 畫面上 突然停住幾秒,之後 ping 值改變(例:40 → 70ms)
症狀 定格 , 瞬移
因素 遺失, 延遲
誰會遇到 特定地區/電信業者
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
遊戲開發團隊要做的事 設定能撐過短暫中斷的逾時(停住幾秒的連線不要立刻切斷)。
基礎設施團隊要做的事 監控路由(監看我方 IP 區段的路由與 ping 變化);我方線路故障用 BFD 在 1 秒內偵測並切換(BGP 預設 hold time 為 90~180 秒);若改走遠路後遲遲沒有恢復,就把流量移到其他線路。
外部要做的事 路由經常變動的電信業者區段,請該電信業者查明原因。
圖表上 從某個時間點起階梯式上升 · RTT、traceroute 路徑
查看位置 比較 RTT 改變前後的 traceroute、mtr 路徑,並用 RIPEstat BGPlay 查看我方位址區段(prefix)的 BGP 路由變更紀錄 符合的跡象 停住幾秒的同時 RTT 移到另一個數值,同一時間有 BGP 更新與 AS 路徑變更 不符合的跡象 沒有路由變更紀錄、只在晚上升高時是「尖峰時段 peering 區段壅塞」,只有部分連線變差時是「ECMP 其中一條路徑異常」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 Cloudflare 2020: Cloudflare 骨幹設定錯誤導致部分城市的流量遺失 Meta 2021: 一道骨幹指令讓 Facebook 連 DNS 都消失的事故 Cloudflare 2025: Cloudflare 公用 DNS 1.1.1.1 事故
出處 4 筆
ECMP 其中一條路徑異常 ECMP / link bundle member fault
ID isp-ecmp · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
電信業者與資料中心會為同一個目的地準備多條路徑,並替每條連線指定其中一條傳送。只要其中一條路徑故障,被分配到那條路徑的人就會持續遇到 lag。
為什麼 在多條線路綁在一起的區段中,其中一條線路或一台設備異常或壅塞 → 於是 路徑由位址與 port 的組合(雜湊)決定,只有被分配到那條路徑的連線出現封包遺失與延遲 → 畫面上 同一地區、同一電信業者,卻只有部分人持續瞬移。重新連線後有時就恢復正常
症狀 瞬移 , 拉回 , 卡頓
因素 遺失, 抖動
誰會遇到 只有我, 特定地區/電信業者
何時 一直都有
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
遊戲開發團隊要做的事 記錄每條連線的遺失與重傳統計,讓受影響者的 IP、port 與時間點能被撈出來(TCP 用 TCP_INFO 的重傳次數,UDP 用缺漏的封包序號計算)。
基礎設施團隊要做的事 收集受影響者的 IP、port 與時間點,提供給電信業者與資料中心;監控各路徑的遺失;量測路徑時使用與遊戲相同的協定與 port(mtr --tcp、--udp 搭配 --port);若是我方設備的路徑,就把異常線路或設備從綁定中移除。
外部要做的事 請電信業者確認並更換異常路徑,並引導玩家以重新連線暫時避開(重新連線會換 port 的情況)。
數值參考 有 4 條路徑時,只有約 1/4 的使用者會遇到。量測 ping 時可能走的是和遊戲不同的路徑,結果看起來正常。
圖表上 只有部分偏高 · 每條連線的遺失與重傳(依 IP/port)
查看位置 依來源 IP、port 分開查看每條連線的遺失與重傳;用 UDP(-u)把 mtr 送往遊戲 port(-P),並指定來源 port(-L)量測,再換不同來源 port 重複多次。只給 -P 不給 -L 時,每次請求的來源 port 都會變,多條路徑的結果會混在一起 符合的跡象 同一地區、同一電信業者內,只有特定來源 port(或位址)的組合持續遺失,重新連線換了 port 後就恢復正常 不符合的跡象 換了 port 仍然全部都差時,是整個區段的壅塞或故障 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 為了不打亂同一條連線的封包順序,設備會依位址與 port(依設備設定,也可能只看位址)算出的值,替每條連線固定一條路徑(ECMP、LAG)。只看位址的地方,重新連線後仍是同一條路徑,不會改善。因此同時收到「ping 正常,只有遊戲 lag」、「重新連線後就好了」這類回報時,就要懷疑是這個原因。
出處 3 筆
電信業者限速與流量管理 Traffic shaping, data caps
ID isp-shaping · 主要負責 外部(外部) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施)
在用量超過上限或會管理特定流量的資費方案中,封包會被延後或丟棄。
為什麼 資費方案的行動數據用完後被限速,或特定流量受到限制 → 於是 封包排隊等待或被丟棄 → 畫面上 用到一定用量之後開始 lag,行動網路特別常見
症狀 輸入延遲 , 瞬移
因素 延遲, 遺失
誰會遇到 只有我, 特定地區/電信業者
何時 一直都有, 晚間尖峰時段
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 減少遊戲流量(壓縮、只傳必要的資料)。
基礎設施團隊要做的事 若只有特定電信業者的遊戲流量被延後或丟棄,整理資料後向電信業者提報(escalation)。
外部要做的事 引導玩家確認資費方案的數據是否用完、是否被限速,以及同一支手機上其他 App 的使用情況;請電信業者確認是否限制遊戲流量。
數值參考 韓國國內的行動資費方案在數據用完後通常限速為 1~5Mbps,便宜的方案限速為數百 kbps。遊戲本身流量不大,但同一支手機上的其他 App 一用網路,限速設備前就會出現排隊。
圖表上 碰到上限後持平 · 處理量、RTT
查看位置 請玩家在電信業者 App 確認剩餘數據與是否限速,並用測速查看最高速度。伺服器端比較各電信業者的遺失與 RTT 符合的跡象 處理量卡在 1~5Mbps 或數百 kbps 這類固定數值上不去,從那時起同一支手機的其他 App 一用網路,RTT 與遺失就增加。加購數據或改用 Wi-Fi 後消失 不符合的跡象 沒有限速卻只有特定電信業者變差時,是「尖峰時段 peering 區段壅塞」或「繞遠路的路由」 確認方式 在玩家端環境確認
出處 2 筆
國家/電信業者層級的 UDP 限制與封包檢測 UDP blocking, throttling and inspection by networks
ID isp-udp-block · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施)
部分網路會封鎖特定 UDP 位址與 port,或限制 UDP 速度;封包檢測設備也會過濾掉無法辨識的協定。用 UDP 通訊的遊戲在這類網路上會連不上或經常斷線。
為什麼 從限制 UDP 速度的部分電信業者網路,或設有國家/電信業者層級流量檢測(審查)設備的網路連線 → 於是 封鎖特定 UDP 位址與 port、在壅塞時段限制 UDP 速度、過濾不在允許清單上的 port 與協定,或只放行前幾個封包後就封鎖 → 畫面上 只有特定國家或電信業者的玩家連不上/無限讀取,或連上後很快斷線,壅塞時段因封包遺失而瞬移
症狀 連不上/無限讀取 , 斷線 , 瞬移
因素 遺失
誰會遇到 特定地區/電信業者
何時 剛登入/維護剛結束, 一直都有, 晚間尖峰時段
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 用戶端:UDP 在幾秒內連不上時,自動切換到 TCP/TLS 443 替代路徑;也要偵測一開始連上、很快又斷掉的情況,改用替代路徑重試;在 log 中記錄是走哪條路徑連上的。伺服器:同一套遊戲協定也透過 TCP 443(TLS)接收;替代路徑的延遲可能增加,需調整逾時。
基礎設施團隊要做的事 新增海外國家之前,先在當地電信業者網路量測 UDP 是否能連通與尖峰時段的遺失;在當地附近設置接收 TCP 443 替代路徑的中繼(relay)或閘道;監看各國家、ASN 的 UDP 與 TCP 連線成功率;確認有 UDP 限速的電信業者,整理資料後提報(escalation)。
外部要做的事 向該電信業者或機關詢問 UDP 限制的標準與放寬方式,並引導玩家改從其他網路連線比較看看。
數值參考 根據 IETF 文件引用的量測,3~5% 的網路會完全封鎖 UDP。Google 在 2016 年檢視 QUIC(以 UDP 為基礎)的使用結果,發現 4.4% 的用戶端因 UDP 或 QUIC 被封鎖,或路徑 MTU 太小而無法使用,其中大多位於企業防火牆後方,沒有觀察到整個電信業者全面封鎖的情況。另有 0.3% 位於尖峰時段封包遺失大幅增加、看起來在限制 UDP 速度的網路上;Google 請電信業者處理後,這個比例已從 2015 年的 1% 降下來。
圖表上 只有部分偏高 · UDP 連線成功率(依國家/ASN)
查看位置 依國家、ASN 分開查看 UDP 連線成功率與 TCP 443 替代路徑的成功率。從該電信業者網路上的雲端 VM 或玩家電腦,分別對遊戲 UDP port 與 TCP 443 做連線測試,並用 mtr -u -P(遊戲 port)與 mtr -T -P 443 比較從哪個區段開始沒有回應 符合的跡象 只有特定國家、ASN 的 UDP 收不到第一個回應或幾秒內就斷線,同一地點的 TCP 443 則正常。若是限速,只在尖峰時段 UDP 遺失明顯增加,TCP 受影響較小 不符合的跡象 TCP 也一起失敗時,查路徑故障、IP 封鎖或「DNS 故障與延遲」。所有國家都一樣時,查我方伺服器與防火牆設定;不分 UDP、TCP,只在瞬間傳輸量大時才遺失,是「Policer 丟棄超額流量」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 封包檢測設備可能依位址、port、協定挑出 UDP flow 加以封鎖,也可能採取只放行允許的協定、其餘全部封鎖的允許清單方式(IRTF 調查文件)。設備若只看封包的部分欄位來判斷,協定稍有改動就可能被擋。QUIC 早期曾有一款防火牆在標頭的 1 個位元改變後,只放行前幾個封包、之後的封包全部封鎖,導致用戶端改用 TCP 連線的邏輯無法運作。新增海外國家時,這個問題可能以「韓國沒問題,只有該國部分電信業者連不上」的回報形式浮現。如果只在咖啡廳、公司這類特定場所的網路被擋,請參考「公共 Wi-Fi/公司網路限制」。
出處 4 筆
線路品質不良 Faulty last-mile line / modem
ID isp-line · 主要負責 外部(外部)
接頭接觸不良、老舊線路或數據機異常,會造成持續的封包遺失與週期性的線路中斷。
為什麼 纜線受損、接觸不良,或數據機、光纖終端設備異常 → 於是 位元錯誤導致封包被丟棄,有時線路會重新連線,因而中斷數秒到 1 分鐘左右 → 畫面上 持續少量的封包遺失,偶爾定格數秒或斷線
症狀 瞬移 , 定格 , 斷線
因素 遺失
誰會遇到 同一個家
何時 偶爾隨機發生
負責單位 主要負責 外部(外部)
外部要做的事 引導玩家確認其他遊戲與視訊通話是否也會斷,若是,請玩家向電信業者申請檢修。
圖表上 偶爾隨機飆高 · 遺失率、線路重新連線紀錄
查看位置 用 pathping(或 mtr)量測幾分鐘到電信業者第一段的遺失,並在分享器管理頁面的網際網路(WAN)連線紀錄中查看重新連線的時間 符合的跡象 線路空閒時也從電信業者第一段起持續遺失,分享器紀錄的線路重新連線時間與定格、斷線的時間重疊。其他遊戲與視訊通話也一起斷 不符合的跡象 遺失從到分享器之間的無線區段開始時是「Wi-Fi 干擾與訊號減弱」,從電信業者較遠的區段開始時是電信業者路徑的問題 確認方式 在玩家端環境確認
出處 3 筆
DNS 故障與延遲 DNS failure / slowness
ID isp-dns · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
負責把伺服器名稱轉成位址的 DNS 一旦變慢或失敗,就找不到登入伺服器與更新伺服器。
為什麼 電信業者的 DNS 故障或設定錯誤 → 於是 找不到登入伺服器、更新伺服器的位址 → 畫面上 按下連線按鈕後要等很久,或連不上。已經連上的人不受影響
症狀 連不上/無限讀取
因素 延遲, 遺失
誰會遇到 特定地區/電信業者, 只有我
何時 剛登入/維護剛結束
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 位址快取(記住最後一次成功連線的伺服器位址),準備多個 DNS(一處失敗時改向其他 DNS 重新查詢)。
外部要做的事 引導玩家把 DNS 改成公共 DNS 等其他服務試試看。
圖表上 只有部分偏高 · 登入失敗次數(依電信業者)、DNS 查詢時間
查看位置 用 Resolve-DnsName -Server(或 nslookup)分別向電信業者 DNS 與公共 DNS 查詢登入伺服器名稱,比較回應時間與結果 符合的跡象 只有電信業者 DNS 沒有回應或花很久,改用公共 DNS 後立刻連上。已連上的玩家不受影響 不符合的跡象 不論用哪個 DNS 都能立刻查到位址卻仍連不上時,查路徑、防火牆或伺服器端 確認方式 在玩家端環境確認
實際案例 Meta 2021: 一道骨幹指令讓 Facebook 連 DNS 都消失的事故 Cloudflare 2025: Cloudflare 公用 DNS 1.1.1.1 事故 AWS 2025: AWS us-east-1 DynamoDB DNS 事故與漫長的復原
出處 4 筆
DDoS 造成共用線路飽和 DDoS saturating shared links
ID isp-ddos-path · 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部)
針對遊戲公司,或同一網路上其他對象的大量攻擊,會塞滿共用的線路。
為什麼 出現大量攻擊流量 → 於是 連走同一條線路的正常流量也被擠壓、丟棄 → 畫面上 許多人同時瞬移、斷線、連不上
症狀 瞬移 , 斷線 , 連不上/無限讀取
因素 遺失, 延遲
誰會遇到 整個伺服器, 特定地區/電信業者
何時 偶爾隨機發生, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部)
基礎設施團隊要做的事 使用 DDoS 防護服務,攻擊時把流量改道,隱藏伺服器位址(放在防護設備後方,不暴露真實位址)。
外部要做的事 若攻擊是針對同一網路上的其他對象,請電信業者在上游區段阻擋。
圖表上 碰到上限後持平 · 線路接收量(bps、pps)、介面丟棄數
查看位置 把我方線路與設備的介面接收量、丟棄封包數,以及 DDoS 防護服務的攻擊偵測紀錄,對照斷線集中的時間點一起看 符合的跡象 線路接收量貼齊線路容量而持平,丟棄數增加,同一時間多個地區、多家電信業者的玩家一起瞬移、斷線 不符合的跡象 線路還有餘裕、只有部分電信業者變差時,是電信業者區段的壅塞或路由問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID isp-cgnat · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施)
行動網路與部分電信業者讓多位用戶共用一個 IP,並在短時間內清除閒置連線的 NAT mapping。
為什麼 電信業者的設備要管理大量用戶的 session 表 → 於是 session 表有上限,閒置逾時很短 → 畫面上 閒置一陣子後斷線;共用同一個 IP 的人被誤判而一起封鎖
症狀 斷線 , 連不上/無限讀取
因素 遺失
誰會遇到 特定地區/電信業者
何時 閒置一段時間後
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 用戶端:以最短閒置逾時(行動網路有時只有 30 秒左右)一半以下的間隔送出心跳封包(電信業者的 CGNAT mapping 只有從內部送出的封包才能確實更新,所以由用戶端送),斷線時自動重新連線。伺服器:回應心跳封包,一段時間沒收到就先清理連線;mapping 改變導致位址、port 不同時,也要用 session token 接續成同一位玩家;一個 IP 可能由多人共用,以 IP 為單位的封鎖政策要謹慎(搭配帳號、裝置一起判斷)。
基礎設施團隊要做的事 依電信業者共用 IP 的情況,調整防火牆、DDoS 防護設備的每 IP 連線數與每秒新連線數限制(行動電信業者的位址區段提高門檻或列為例外)。
數值參考 行動網路的 UDP 閒置逾時有時只有 30 秒左右。
圖表上 連線同時大量中斷 · 斷線次數(心跳逾時)、斷線前的閒置時間(依電信業者)
查看位置 在連線 log 中查看同一個 IP 同時連上的帳號數與電信業者(ASN),並依電信業者彙整閒置後才斷線的連線,統計其閒置時間。玩家端請確認分享器管理頁面上的網際網路(WAN)位址 符合的跡象 行動電信業者的位址區段中同一個 IP 連上多個帳號,斷線前的閒置時間集中在 30~60 秒左右的短時間。分享器的 WAN 位址是 100.64.0.0/10(電信業者 NAT 用的共用位址),或與伺服器看到的位址不同 不符合的跡象 與電信業者無關、集中在使用家用分享器的玩家時是「NAT mapping 過期」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 4 筆
經由 VPN/遊戲加速器 VPN / game accelerator detour
ID isp-vpn · 主要負責 外部(外部) · 協同 基礎設施團隊(網路基礎設施), 遊戲開發團隊(伺服器開發)
開啟 VPN 或遊戲加速器後,封包會經過該公司的中繼伺服器。中繼伺服器很遠或壅塞時,反而會變慢。
為什麼 VPN 或加速器把遊戲封包全部轉送到中繼伺服器 → 於是 加上到中繼伺服器的距離與壅塞,通道標頭也讓 MTU(一次能傳送的封包大小)變小 → 畫面上 ping 升高並出現封包遺失;與使用同一中繼位址的人一起被封鎖而連不上
症狀 輸入延遲 , 瞬移 , 連不上/無限讀取
因素 延遲, 遺失
誰會遇到 只有我
何時 一直都有, 剛登入/維護剛結束
負責單位 主要負責 外部(外部) · 協同 基礎設施團隊(網路基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 UDP 封包維持在 1,200 位元組以下(即使通道標頭讓 MTU 變小也不會被分段);以 IP 為單位的封鎖要考量 VPN、加速器的公用中繼位址,搭配帳號、裝置一起判斷。
基礎設施團隊要做的事 海外玩家多時自行設置附近的接入據點;對「開了加速器就變好」回報集中的電信業者檢查路由。
外部要做的事 引導玩家關閉 VPN、加速器後比較看看。
數值參考 中繼伺服器在附近時增加數 ms,繞經其他國家時會增加數十~100ms 以上。
圖表上 只有部分偏高 · RTT(依玩家)、連線 IP 所屬業者
查看位置 查看連線 IP 的 ASN 是否屬於 VPN、加速器或主機代管業者,並請玩家關閉 VPN、加速器後比較 ping 與 traceroute 符合的跡象 只有開啟 VPN、加速器時 RTT 與遺失增加或被擋在外面,traceroute 中可以看到經過中繼伺服器的區段 不符合的跡象 開關都一樣時,是線路或電信業者區段的問題。開了反而變好時,是原本電信業者路徑(「繞遠路的路由」、「尖峰時段 peering 區段壅塞」)的問題 確認方式 在玩家端環境確認
深入了解 反過來說,電信業者的路徑不好時,加速器繞經較好的路徑,ping 有時反而會下降。「開了加速器就變好」的回報,是繞遠路的路由或晚間壅塞等電信業者路徑問題的線索。
出處 3 筆
L5 資料中心網路設備
11 個原因 · 完整版章節
防火牆 session 表飽和 Firewall session table exhaustion
ID dc-firewall · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
防火牆會把放行的每條連線記錄在 session 表中追蹤。表一旦滿了,就無法接受新連線。
為什麼 連線暴增或遭受攻擊,使 session 數達到上限 → 於是 沒有空的項目可以記錄新連線,因此拒絕連線 → 畫面上 想新連進來的人連不上/無限讀取,部分既有連線也會斷線
症狀 連不上/無限讀取 , 斷線
因素 遺失
誰會遇到 整個伺服器
何時 剛登入/維護剛結束, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:用登入排隊系統調節一次湧入的連線;重複使用連線,避免反覆建立短連線;心跳封包中斷的連線要主動先清理(避免死掉的連線長時間佔用 session 表)。用戶端:以最短閒置逾時一半以下的間隔送出心跳封包;斷線時自動重新連線,但要逐步拉長重試間隔並隨機分散(避免大家又同時湧入)。
基礎設施團隊要做的事 加大 session 表;盡快清理很快就結束的連線(縮短已結束 session 的逾時);縮短閒置 session 逾時時,要把數值告知遊戲團隊以配合調整心跳封包間隔;阻擋攻擊;設定 session 使用率警示。
圖表上 碰到上限後持平 · 防火牆 session 數、新連線失敗數
查看位置 把防火牆設備的同時 session 數與 session 上限畫在同一張圖上,並在設備 log 中找出無法建立 session 而丟棄的紀錄。若是 Linux 防火牆,比較 nf_conntrack_count 與 nf_conntrack_max,並查看 dmesg 中的「nf_conntrack: table full, dropping packet」;若是 AWS 執行個體,查看 ethtool -S 的 conntrack_allowance_exceeded 符合的跡象 session 數在上限處持平的時間點起,新連線失敗增加,session 建立失敗紀錄或丟棄計數器也一起增加 不符合的跡象 session 數遠低於上限卻連不上時,是「連線等待佇列(backlog)溢位」或登入伺服器端的問題。只有閒置連線被切斷時是「雲端安全群組的連線追蹤過期」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
DDoS 防護導流與誤判 DDoS scrubbing latency, false positives
ID dc-ddos · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
為了擋下攻擊而把流量導向清洗中心時,路徑會變長,有時還會把正常使用者誤判為攻擊而封鎖。
為什麼 偵測到攻擊後(或常態性地)把進來的流量導向清洗中心 → 於是 路徑變長,部分正常封包被判定為攻擊 → 畫面上 整體 ping 上升,只有特定地區/電信業者連不上
症狀 輸入延遲 , 連不上/無限讀取 , 瞬移
因素 延遲, 遺失
誰會遇到 整個伺服器, 特定地區/電信業者
何時 人潮湧入時, 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 整理遊戲流量模式(port、封包大小、每秒封包數)並提供給基礎設施團隊,UDP 封包維持在 1,200 位元組以下。
基礎設施團隊要做的事 制定符合遊戲流量模式的防護規則,設置各地區的清洗據點,在通道區段縮小 TCP 封包大小(MSS 調整),以各地區、各電信業者的連線失敗率確認是否誤判。
數值參考 清洗據點在同一個國家時增加數 ms,經過其他國家的據點時會增加 30~100ms 以上。通常只有進來的方向會繞道,伺服器的回應則直接送出。若清洗後的流量透過通道送回,一次能傳送的大小(MTU)也會變小,有時會演變成只有大封包消失的問題。
圖表上 從某個時間點起階梯式上升 · RTT(ping)、各地區/電信業者的連線失敗率
查看位置 把防護設備或服務的導流(清洗)開始與結束紀錄、封鎖 log,與 RTT 圖表、各地區與電信業者的連線失敗率放在同一條時間軸上比對。在問題地區用 mtr、traceroute 確認路徑中是否夾著清洗據點 符合的跡象 導流開啟的時間點 RTT 升高一階並維持,關閉後恢復。或封鎖 log 中出現正常玩家的位址,且只有該地區、該電信業者的連線失敗率上升 不符合的跡象 沒有導流、封鎖紀錄的時段 RTT 仍升高時,是「繞遠路的路由」或「BGP 路由變更與收斂」。只有大封包消失時是「MTU 不一致(只有大封包消失)」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 2 筆
負載平衡器閒置逾時 Load balancer idle timeout
ID dc-lb-idle · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
負載平衡器會在一段時間後清除閒置連線。遊戲還以為連線仍然維持著,結果就斷線了。
為什麼 玩家有一段時間完全沒送出任何封包(開著對話視窗、暫離) → 於是 負載平衡器清理閒置連線(常見的預設值為 60~350 秒) → 畫面上 再次移動的瞬間斷線
症狀 斷線
因素 遺失
誰會遇到 只有我, 整個伺服器
何時 閒置一段時間後
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:以最短閒置逾時一半以下的間隔送出心跳封包(位於 60 秒逾時的 ALB 後方時,就是 30 秒以下),斷線時自動重新連線。伺服器:回應心跳封包,一段時間沒收到就先清理連線,用 session token 接續連線。
基礎設施團隊要做的事 確認路徑上負載平衡器的閒置逾時數值並提供給遊戲團隊,必要時調長。
數值參考 AWS ALB 的預設值是 60 秒,NLB 是 TCP 350 秒、UDP 120 秒,Azure Load Balancer 是 TCP 4 分鐘。ALB 與 NLB 的 TCP 數值可以修改,但 NLB 的 UDP 120 秒無法修改。ALB 時間到時也會關閉伺服器端的連線;NLB 則是默默清除,伺服器很容易在不知情的狀態下留著連線。
圖表上 連線同時大量中斷 · 斷線次數、斷線前的閒置時間
查看位置 確認路徑上負載平衡器的閒置逾時設定值,並彙整每條斷線連線從最後一個封包到斷線所經過的時間。若是 AWS NLB,也查看 CloudWatch 的 TCP_ELB_Reset_Count(負載平衡器送出的 RST 數) 符合的跡象 斷線連線的閒置時間集中在設定值(ALB 60 秒、NLB TCP 350 秒等)剛過之後,閒置超過該時間再移動就能重現。NLB 在該時間點 TCP_ELB_Reset_Count 增加 不符合的跡象 與閒置時間無關的斷線,就不是這個原因。沒有經過負載平衡器、直接連線的伺服器集中在 350 秒附近斷線時是「雲端安全群組的連線追蹤過期」,問題在玩家家中的分享器時是「NAT mapping 過期」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
雲端安全群組的連線追蹤過期 Cloud security group connection tracking timeout
ID dc-cloud-conntrack · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
雲端伺服器上的防火牆(安全群組)也會追蹤連線,閒置連線的追蹤項目會在一定時間後過期。即使是沒有經過負載平衡器、直接連線的伺服器,靜止不動的玩家也可能斷線。
為什麼 安全群組處於會追蹤遊戲連線的設定(只允許特定位址、限制輸出規則、經由 NLB 等) → 於是 連線閒置一段時間後追蹤項目過期,之後進來的封包被安全群組默默丟棄 → 畫面上 暫離後再移動時沒有反應,接著斷線。伺服器程式很長一段時間都沒察覺
症狀 斷線
因素 遺失
誰會遇到 只有我, 整個伺服器
何時 閒置一段時間後
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(用戶端開發), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:以最短閒置逾時一半以下的間隔送出心跳封包(TCP 350 秒時為 175 秒以下,UDP 串流 180 秒時為 90 秒以下),斷線時自動重新連線。伺服器:回應心跳封包,一段時間沒收到就先清理連線,用 session token 接續連線。
基礎設施團隊要做的事 確認執行個體的連線追蹤時間(TcpEstablishedTimeout),必要時調長(UDP 最多 180 秒,無法再調長);檢討不會產生追蹤的安全群組配置(遊戲 port 允許所有位址、輸出規則全部允許;經由 NLB 的連線仍會被追蹤);換到新世代執行個體時進行閒置測試。
數值參考 以 AWS 為例,Nitro v6 執行個體類型預設在 350 秒後清除閒置 TCP 連線的追蹤項目(其他類型為 5 天)。UDP 的預設值為:請求與回應往返多次的 flow(串流)180 秒,只往單一方向送出或請求與回應只有一次的 flow 30 秒。
圖表上 連線同時大量中斷 · 斷線次數、斷線前的閒置時間
查看位置 確認執行個體的連線追蹤時間設定與安全群組規則(是否為會產生追蹤的配置),並彙整斷線連線的閒置時間。剛斷線時在伺服器用 ss -tnoi 查看該連線是否仍以 ESTABLISHED 殘留、重傳計時器(timer:(on,…))在跑且 backoff 變大 符合的跡象 斷線連線的閒置時間集中在 TCP 350 秒、UDP 串流 180 秒、UDP 單向 30 秒剛過之後,伺服器端的 socket 沒偵測到斷線、仍以 ESTABLISHED 殘留(伺服器有資料要送時只會一直重傳) 不符合的跡象 安全群組處於不追蹤的配置(遊戲 port 允許所有位址、輸出規則全部允許、不經過 NLB)時,就不是這個原因。經過 NLB 時,與「負載平衡器閒置逾時」的數值比較 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
雲端 NAT 閘道的連線與 port 上限 Cloud NAT gateway connection / port limits
ID dc-nat-gateway · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
私有子網路中的伺服器對外(平台驗證、付款、外部 API)的連線,由 NAT 閘道轉換位址與 port 後送出。送往同一目的地的同時連線超過閘道的 port 上限時,新連線就會失敗。
為什麼 伺服器對平台驗證、付款這類同一個外部位址大量開啟短連線,或長時間開著連線 → 於是 NAT 閘道無法再分配該目的地可用的來源 port,新連線失敗 → 畫面上 遊戲內一切正常,只有登入、付款、發放獎勵這類呼叫外部的功能失敗或變慢(連不上/無限讀取、吃指令/回檔)
症狀 連不上/無限讀取 , 吃指令/回檔
因素 遺失, 延遲
誰會遇到 只有特定功能, 整個伺服器
何時 剛登入/維護剛結束, 晚間尖峰時段, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 外部 API 要重複使用連線(HTTP keep-alive、連線池),不要每次請求都開新連線;留在池中的閒置連線,要以比 NAT 閒置逾時(AWS 350 秒)更短的間隔送出 keepalive,或先行關閉;失敗時逐步拉長重試間隔並隨機分散;記錄各外部呼叫的失敗率與延遲。
基礎設施團隊要做的事 為 NAT 閘道增加 IP 位址(AWS 公用 NAT 閘道預設只能掛 2 個彈性 IP,超過需申請提高配額);依可用區域、子網路拆分閘道;為 port 分配失敗指標(AWS ErrorPortAllocation、Azure SNAT Connection Count 的 Failed、Google Cloud dropped_sent_packets_count 的 OUT_OF_RESOURCES)設定警示;Google Cloud NAT 可提高每個 VM 的最少 port 數,或改用動態 port 分配。
數值參考 AWS NAT 閘道每個 IP 位址對同一目的地(IP、port、協定)最多可開 5 萬 5 千條同時連線,最多可掛 8 個 IP 來擴充。350 秒沒有流量的連線會被清除,之後再從這條連線送出的封包會收到 RST。Azure NAT Gateway 每個公用 IP 有 64,512 個 SNAT port(IP 最多 16 個)。Google Cloud NAT 把每個 NAT IP 的 64,512 個 port 分給各 VM,但每個 VM 的最少 port 數預設為 64 個(靜態分配),所以預設設定下,一台 VM 對同一目的地能同時開的連線通常被限制在 64 條。
圖表上 碰到上限後持平 · NAT 閘道同時連線數、port 分配失敗數
查看位置 AWS 查看 CloudWatch 中的 NAT 閘道指標 ErrorPortAllocation、ActiveConnectionCount、PacketsDropCount(Azure 為以 Failed 狀態篩選的 SNAT Connection Count 與 Dropped Packets,Google Cloud 為 dropped_sent_packets_count 中 reason 為 OUT_OF_RESOURCES 的值),與遊戲伺服器外部呼叫失敗的時間點並排比對 符合的跡象 外部呼叫失敗的時間點 ErrorPortAllocation(Azure 為 Failed 狀態的 SNAT Connection Count,Google Cloud 為 OUT_OF_RESOURCES 丟棄)大於 0,失敗集中在驗證、付款伺服器這類連線大量集中的一兩個目的地 不符合的跡象 port 分配失敗為 0,但遊戲伺服器的 connect 以 EADDRNOTAVAIL 失敗、TIME_WAIT 數接近臨時 port 範圍時,是「伺服器間連線的臨時 port 耗盡」。能連上但只有回應很慢時,是「依賴外部服務」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 與單台伺服器的臨時 port 用完的「伺服器間連線的臨時 port 耗盡」不同,這個上限卡在 NAT 閘道上,由閘道後方的伺服器共用(Google Cloud NAT 則分給各 VM)。伺服器端的 TIME_WAIT 與臨時 port 範圍都還有餘裕,卻只有外部呼叫失敗時,就是這個原因。已關閉連線的 port 也不會立刻再用於同一目的地(Azure 有冷卻時間,Google Cloud 在 TIME_WAIT 期間無法使用),所以越常反覆建立短連線,越快碰到上限。
出處 7 筆
ID dc-lb-imbalance · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
連線全集中到一台伺服器,或持續把人送往已經掛掉的伺服器。
為什麼 分配規則不合適,或健康檢查(health check)看不到實際狀態 → 於是 只有一台伺服器過載,或連線被送往掛掉的伺服器 → 畫面上 只有部分頻道、部分人出現慢動作,或連不上/無限讀取
症狀 慢動作 , 連不上/無限讀取
因素 停滯, 遺失
誰會遇到 特定地點/頻道
何時 剛登入/維護剛結束, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 實作健康檢查,依實際遊戲狀態(tick 是否推進、DB 連線)回應負載平衡器的檢查請求,並一併回報伺服器負載值。
基礎設施團隊要做的事 把健康檢查改成確認實際遊戲回應的方式,依伺服器負載分配,監控各伺服器連線數的差距。
圖表上 只有部分偏高 · 各伺服器的連線數與 CPU 使用率
查看位置 把負載平衡器後方每台伺服器的連線數(ss -s)與 CPU 使用率疊在同一張圖上,並將負載平衡器的目標健康狀態(AWS 為 CloudWatch 的 HealthyHostCount、UnHealthyHostCount)與遊戲伺服器的實際狀態比較 符合的跡象 只有一兩台伺服器的連線數與 CPU 明顯高於其他伺服器,或 tick 已停住的伺服器仍以健康狀態「正常」留著,持續接收新連線 不符合的跡象 各伺服器連線數平均、只有一個頻道變慢時,是該頻道內部的負載問題(「單執行緒區域過載(熱點)」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 AWS 2025: AWS us-east-1 DynamoDB DNS 事故與漫長的復原
出處 3 筆
ID dc-microburst · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施), 基礎設施團隊(伺服器基礎設施)
多台伺服器在同一瞬間同時對數千人送出封包時,這些流量匯集的交換器 port 上的小緩衝區,不到 1ms 就會滿溢。
為什麼 世界王出現、大範圍技能,或多台伺服器的 tick 在同一瞬間對齊,同時送出封包 → 於是 多個 port 匯入一個 port,或從快速 port 轉到慢速 port 的地方,緩衝區(每個 port 數百 KB~數 MB)瞬間塞滿 → 畫面上 部分封包被丟棄,許多人同時瞬移、技能被吃
症狀 瞬移 , 吃指令/回檔
因素 遺失
誰會遇到 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 在一個 tick 內平均分散傳送(pacing),讓各伺服器的 tick 開始時間稍微錯開。
基礎設施團隊要做的事 網路:採用緩衝區較大的交換器,分散流量(把伺服器分散接到多台交換器、多個 port),監看各交換器 port 的丟棄計數器。伺服器設備/OS:為整台伺服器設定傳送速率上限(Linux tc shaper)。
數值參考 10Gbps 的 port 在 1ms 內能送出的量約為 1.25MB。兩個 port 的流量同時湧入一個 port 時,每 1ms 就會累積 1.25MB。即使 1 秒平均使用率只有 10%,以 1ms 為單位來看仍可能滿溢。
圖表上 隨人數/負載上升 · 交換器 port 輸出丟棄數
查看位置 以盡可能短的間隔收集伺服器所接交換器 port,以及其流量匯集 port 的輸出丟棄計數器(ifOutDiscards,依設備可能為 output drops),對照世界王出現、大規模戰鬥的時間點。只看 1 秒、1 分鐘平均使用率圖表是看不出來的 符合的跡象 平均使用率很低,但每當人潮集中到一處的瞬間輸出丟棄就增加,同時多位玩家回報瞬移、技能被吃 不符合的跡象 丟棄在平均使用率高的時段持續增加時是「資料中心線路飽和」。輸入錯誤(CRC)增加時是「纜線不良與 port 錯誤」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
資料中心線路飽和 Uplink saturation
ID dc-uplink · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
更新檔發布、log 傳送、備份與遊戲共用同一條線路時,線路會被塞滿。
為什麼 大量傳輸佔用同一條線路 → 於是 線路上的排隊與封包遺失增加 → 畫面上 整個伺服器的 ping 上升並出現瞬移
症狀 輸入延遲 , 瞬移
因素 延遲, 遺失
誰會遇到 整個伺服器
何時 固定週期, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 網路:遊戲流量優先處理(QoS),把大量傳輸的線路分開,設定線路使用率警示。伺服器設備/OS:替備份、log 傳送、部署加上速率限制,並在離峰時段執行。
圖表上 碰到上限後持平 · 線路使用率、RTT(ping)
查看位置 把資料中心線路(上行鏈路)介面的使用率(以 SNMP ifHCInOctets、ifHCOutOctets 計算)與輸出丟棄(ifOutDiscards),和備份、部署、log 傳送排程放在同一條時間軸上比對 符合的跡象 線路使用率貼齊頻寬上限而持平的時間點,整個伺服器的 RTT 與丟棄上升,且該時間點與大量傳輸作業重疊 不符合的跡象 分鐘級使用率遠低於上限卻有丟棄時是「交換器 microburst」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID dc-failover · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
路由器或防火牆有一台故障、切換到備援設備(failover)的幾秒之間,所有人的畫面都會停住。
為什麼 設備故障或維護,切換到備援設備 → 於是 切換需要數秒;session 資訊沒有同步時,連線會被重置 → 畫面上 伺服器上的所有玩家同時定格,大量斷線
症狀 定格 , 斷線
因素 遺失
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:設定能撐過短暫中斷(數秒)的逾時,斷線後重新連線時,用 session token 接續 session。用戶端:斷線時自動重新連線(隨機分散重試間隔,避免同時湧入)。
基礎設施團隊要做的事 採用共享連線狀態的備援架構,用 BFD 在 1 秒內偵測故障,定期進行切換測試。
數值參考 設備立刻偵測到故障時約 1~3 秒。沒有快速故障偵測(BFD)、只靠 BGP 預設計時器時,相鄰設備偵測到之前,路由可能中斷 90~180 秒。
圖表上 連線同時大量中斷 · 連線數、整個伺服器的收發量
查看位置 查看路由器、防火牆的事件 log(VRRP 角色切換、BFD 與 BGP session down、容錯移轉紀錄),以及同一時間整個伺服器的連線數與收發量 符合的跡象 在設備 log 的切換時間點,該設備後方所有伺服器的流量有幾秒降為 0,或連線數同時下降 不符合的跡象 只有一台伺服器的連線數下降時,是「伺服器當機」或「NIC 驅動程式/韌體問題」。設備 log 很乾淨、停住的是一台雲端虛擬機器時,是「雲端主機維護與即時遷移」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
纜線不良與 port 錯誤 Bad cable / optics (CRC errors)
ID dc-bad-cable · 主要負責 基礎設施團隊(網路基礎設施)
光模組或纜線不良時,經過該路徑的封包會有一定比例損毀。
為什麼 光模組或纜線不良造成位元錯誤 → 於是 損毀的封包被設備默默丟棄 → 畫面上 只有使用該路徑的部分伺服器與使用者因持續的封包遺失而瞬移、拉回
症狀 瞬移 , 拉回
因素 遺失
誰會遇到 特定地點/頻道
何時 一直都有
負責單位 主要負責 基礎設施團隊(網路基礎設施)
基礎設施團隊要做的事 監控 port 錯誤(CRC)計數器並設定警示,更換光模組、纜線等零件,更換前先把問題鏈路移出、改走其他路徑。
圖表上 只有部分偏高 · 各 port 的 CRC 錯誤數、各伺服器/路徑的遺失率
查看位置 查看鏈路兩端的 CRC 計數器。交換器看 port 的 FCS 錯誤(dot3StatsFCSErrors)與輸入錯誤(ifInErrors),伺服器看 ip -s -s link 的 RX errors 中的 crc(kernel 統計 rx_crc_errors) 符合的跡象 某個 port 的 CRC 錯誤不分流量大小與時段持續增加,且只有經過該 port 的伺服器與玩家有遺失 不符合的跡象 沒有 CRC 錯誤、只有輸出丟棄增加時是壅塞(「交換器 microburst」、「資料中心線路飽和」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID dc-mtu · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發)
中途區段的 MTU(一次能傳送的大小)變小,而大小超過的通知又被擋掉時,只有大封包會一直消失。
為什麼 在通道或 VPN 區段中 MTU 變小 → 於是 大小超過的通知(ICMP)被防火牆擋下,傳送端不知道 → 畫面上 只有打開背包、角色清單這類大畫面時,畫面會停住,接著斷線
症狀 定格 , 斷線 , 連不上/無限讀取
因素 遺失
誰會遇到 特定地區/電信業者, 只有我
何時 做特定動作時, 剛登入/維護剛結束
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 要在伺服器端直接調低,須設定 socket 的最大區段大小 TCP_MAXSEG(光在遊戲程式碼裡把訊息切小是擋不住的),UDP 封包維持在 1,200 位元組以下。
基礎設施團隊要做的事 網路:在通道區段縮小 TCP 封包大小(MSS 調整),在防火牆與雲端網路 ACL 允許大小超過的通知(ICMP)。伺服器設備/OS:在伺服器防火牆與雲端安全群組也允許大小超過的通知(ICMP),開啟伺服器 kernel 的 MTU 探索 tcp_mtu_probing=1(這是要停住幾秒後才會作動的最後一道防線)。
數值參考 一般為 1,500 位元組,經過通道後會縮小到 1,400 左右。
圖表上 只有部分偏高 · 各地區/電信業者的斷線、大型回應失敗
查看位置 從問題玩家的電腦對伺服器送出開啟禁止分段旗標(DF)的 ping,並改變大小。Windows 用 ping /f /l 1472 SERVER_IP,Linux 用 ping -M do -s 1472 SERVER_IP(1,472 是 MTU 1,500 減去 IP 標頭 20 位元組與 ICMP 標頭 8 位元組的值)。逐步縮小大小找出能通過的最大值,並確認伺服器端安全群組與防火牆是否允許 ICMP 大小超過通知(Fragmentation Needed) 符合的跡象 小的 ping 能通,1,472 位元組的 DF ping 卻失敗(沒有回應,或出現需要分段的錯誤),能通過的最大值只有 1,400 左右。同一地區的玩家只有在打開大畫面時畫面停住 不符合的跡象 1,472 位元組的 DF ping 也能順利通過時,就不是路徑 MTU 的問題。連小的 ping 都不通時,是 ICMP 本身被擋,無法用這個方法判斷 確認方式 在玩家端環境確認
出處 5 筆
L6 伺服器網路卡
9 個原因 · 完整版章節
ID nic-irq · 主要負責 基礎設施團隊(伺服器基礎設施)
NIC 只把封包到達的中斷(interrupt)送給一個 CPU 核心時,那個核心就會成為瓶頸。
為什麼 只有一個接收佇列,或是負責分散到多個核心的 RSS 被關閉 → 於是 單一核心達到 100%,無法及時取出封包 → 畫面上 人潮湧入時,整個伺服器出現封包遺失與延遲(瞬移、輸入延遲)
症狀 瞬移 , 拉回 , 輸入延遲
因素 遺失, 延遲
誰會遇到 整個伺服器
何時 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 設定 RSS(由 NIC 分散)與 RPS(由 kernel 分散),把中斷分散到多個核心;讓 UDP 連同 port 一起計算來分配佇列(ethtool -N 的 rx-flow-hash udp4 sdfn);把處理中斷的核心與遊戲 tick 執行緒的核心分開;監看各核心的 %soft。
數值參考 一個核心經由 kernel 能處理的量,依封包大小與設定而定,大約是每秒數十萬個封包。如果各核心的使用率中,接收處理所占的比例(mpstat 的 %soft)只集中在一個核心,就是這種情況。
圖表上 碰到上限後持平 · 各核心 %soft、每秒接收封包數
查看位置 用 mpstat -P ALL 1 查看各核心的 %soft(軟體中斷處理比例),用 /proc/interrupts 確認各 NIC 佇列的中斷送往哪個核心,用 ethtool -l 確認佇列數,用 ethtool -S 確認各佇列的封包數(名稱依驅動程式而異) 符合的跡象 只有一個核心的 %soft 貼近 100%,其餘核心很閒,中斷與封包集中在單一佇列。從那時起每秒接收封包數無法再往上 不符合的跡象 %soft 平均分散在多個核心時,就不是這個原因。CPU 很閒卻有封包遺失時,是「超過雲端 PPS 上限」或「Ring buffer 不足」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 即使有多個佇列,如果大部分流量來自閘道、proxy 這類少數幾個位址,還是會集中到同一個佇列。部分 NIC 的預設設定只看位址來分配 UDP 的佇列,要改成連同 port 一起看,才會平均分散。
出處 4 筆
ID nic-ring · 主要負責 基礎設施團隊(伺服器基礎設施)
NIC 暫存封包的 ring buffer 太小時,封包瞬間湧入就會讓緩衝區滿溢而被丟棄。
為什麼 ring buffer 仍是預設值(依驅動程式為 256~2,048 個 slot),容量偏小 → 於是 突發流量來時,CPU 還沒取走封包,緩衝區就滿了 → 畫面上 只在突發流量的瞬間出現封包遺失(瞬移、技能被吃)。遊戲伺服器 log 中看不到任何痕跡
症狀 瞬移 , 吃指令/回檔
因素 遺失
誰會遇到 整個伺服器
何時 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 加大 ring buffer(ethtool -G),監看丟棄(drop)計數器(ethtool -S 的 rx_missed_errors 等,名稱依驅動程式而異)。
數值參考 每秒湧入 100 萬個封包時,1,024 個 slot 約 1ms 就會填滿。這段期間 CPU 只要晚來一次就會滿溢。大部分 NIC 可以加大到數千個。
圖表上 偶爾隨機飆高 · NIC 接收丟棄計數器
查看位置 以短間隔收集 ethtool -S 的接收丟棄計數器(rx_missed_errors、rx_fifo_errors 等,名稱依驅動程式而異)與 ip -s -s link 的 missed,並用 ethtool -g 確認目前的 ring 大小與最大值 符合的跡象 突發流量的瞬間丟棄計數器增加,目前的 ring 大小遠小於最大值。加大 ring 後丟棄減少 不符合的跡象 丟棄計數器沒有變化卻仍有封包遺失時,問題在 kernel 的下一個階段(「Kernel socket 緩衝區不足」)或網路區段。單一核心的 %soft 達到 100% 時是「NIC 中斷集中在單一核心」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
中斷合併過度 Interrupt coalescing
ID nic-coalesce · 主要負責 基礎設施團隊(伺服器基礎設施)
為了減輕 CPU 負擔,NIC 把封包累積起來再一次通知 CPU(中斷合併,interrupt coalescing)時,累積多久就會晚多久。
為什麼 NIC 累積一定時間或一定數量的封包後才通知 → 於是 累積期間,封包只能等待 → 畫面上 延遲些微增加。通常很小,設定過度時會達到 ms 等級
症狀 輸入延遲
因素 延遲
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 使用自適應合併,調整成適合遊戲伺服器的數值(ethtool -C)。
數值參考 通常為數十~數百 µs。對遊戲來說大多可以忽略,但設定過度時會放大到 ms 等級。
圖表上 一開始就一直偏高 · 同一資料中心內的往返時間
查看位置 用 ethtool -c 查看目前的合併設定(adaptive-rx、rx-usecs、rx-frames),並在修改設定前後,比較與同一資料中心其他伺服器之間的 ping 往返時間 符合的跡象 rx-usecs 設得很大(數百 µs 以上),調小後同一資料中心內的往返時間也縮短相同幅度 不符合的跡象 調小後往返時間仍沒有變化時,就不是這個原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
超過雲端 PPS 上限 Cloud PPS / bandwidth allowance
ID nic-cloud-pps · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
雲端伺服器依類型各有每秒封包數與頻寬的上限,超過時會默默丟棄。
為什麼 同時上線人數增加,每秒封包數超過執行個體上限 → 於是 雲端網路丟棄超出的部分 → 畫面上 找不出原因的封包遺失造成瞬移、技能被吃。伺服器 CPU 還有餘裕
症狀 瞬移 , 吃指令/回檔
因素 遺失
誰會遇到 整個伺服器
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
遊戲開發團隊要做的事 合併封包(把一個 tick 的訊息放進一個封包),避免頻繁送出很小的封包。
基礎設施團隊要做的事 確認超過上限的計數器(AWS 為 pps_allowance_exceeded、conntrack_allowance_exceeded 等)並設定警示,改用更大的執行個體,連線追蹤上限則用不會產生追蹤的安全群組配置來避開。
外部要做的事 向雲端供應商詢問各執行個體類型的每秒封包數與連線追蹤上限。
數值參考 上限依執行個體大小而異,每秒封包數的上限多半不公開。小型執行個體的「最高 10Gbps」只是額度(credit)還有剩時(通常 5~60 分鐘)才能使用的突發速度,平時的基準速度低得多。
圖表上 碰到上限後持平 · 每秒封包數、allowance 超限計數器
查看位置 以短間隔收集 ethtool -S 的 ENA 計數器 pps_allowance_exceeded、bw_in_allowance_exceeded、bw_out_allowance_exceeded、conntrack_allowance_exceeded,與每秒封包數一起看。也可以用 CloudWatch agent 上傳這些計數器並設定警示 符合的跡象 遺失發生的時間點 allowance 超限計數器增加,每秒封包數卡在某個數值上不去。伺服器 CPU 還有餘裕 不符合的跡象 超限計數器沒有變化時,就不是這個原因。單一核心的 %soft 達到 100% 時是「NIC 中斷集中在單一核心」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 conntrack_allowance_exceeded 表示連線追蹤表已滿、新連線被丟棄。如果追蹤表還有餘裕,只是閒置連線的追蹤過期而斷線,請參考「雲端安全群組的連線追蹤過期」。
出處 2 筆
NIC 頻寬飽和 NIC bandwidth saturation
ID nic-saturate · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
把 1Gbps、10Gbps 網路卡用到極限時,傳送佇列會變長,最後封包被丟棄。
為什麼 廣播增加,使傳輸量達到網路卡的極限 → 於是 傳送佇列變長,滿了就丟棄 → 畫面上 整個伺服器出現延遲與封包遺失(輸入延遲、瞬移)
症狀 輸入延遲 , 瞬移
因素 延遲, 遺失
誰會遇到 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 減少傳輸量(AOI、壓縮、只送變更的部分)。
基礎設施團隊要做的事 升級網路卡(更快的 NIC,雲端則換更大的執行個體),設定 NIC 使用率警示。
圖表上 碰到上限後持平 · NIC 傳送量、傳送丟棄
查看位置 把 sar -n DEV 1 的 txkB/s 與 %ifutil(相對於介面速度的使用率)和 NIC 速度、執行個體頻寬比較,並一起查看 ip -s link 的 TX dropped 符合的跡象 傳送量在 NIC 或執行個體頻寬附近持平,從那時起傳送丟棄與整個伺服器的延遲增加 不符合的跡象 頻寬還有餘裕時,就不是這個原因。小封包很多且有遺失時,是「超過雲端 PPS 上限」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID nic-noisy · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 外部(外部)
同一台實體伺服器上的其他虛擬機器大量使用網路或 CPU 時,自己伺服器的處理會不規則地被延後。
為什麼 同一台實體伺服器上的其他虛擬機器大量使用資源 → 於是 自己虛擬機器的封包處理不規則地延遲 → 畫面上 沒有明顯原因,偶爾出現抖動(封包抵達間隔忽長忽短)而卡頓
症狀 卡頓
因素 抖動
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 外部(外部)
基礎設施團隊要做的事 使用專用主機或效能有保障的執行個體;抖動持續的執行個體,先停止再啟動,以搬到其他主機。
外部要做的事 向雲端供應商回報有問題的主機。
圖表上 偶爾隨機飆高 · 同一資料中心內往返時間的抖動、%steal
查看位置 持續對同一資料中心的其他伺服器送出 ping,記錄往返時間的抖動,並連同 mpstat 的 %steal 與相同配置的其他執行個體比較 符合的跡象 只有這台執行個體的往返時間抖動或 %steal 不規則地飆高,相同配置的其他執行個體很平穩。先停止再啟動、搬到其他主機後就消失 不符合的跡象 相同配置的執行個體都一樣飆高時,就不是主機的問題。改查遊戲伺服器端的負載或網路區段 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 2 筆
雲端主機維護與即時遷移 Cloud host maintenance / live migration
ID nic-host-maintenance · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
雲端供應商維護實體伺服器(主機)時,會把虛擬機器搬到其他主機(即時遷移),或暫時停住。這段期間整台伺服器都會停住,停住的時間一長,連線就會中斷。
為什麼 供應商因主機維護或故障預測,把虛擬機器搬到其他主機,或短暫暫停 → 於是 搬移期間 CPU、記憶體、網路變慢,最後虛擬機器會短暫完全停住(依供應商與方式,從不到 1 秒到 30 秒左右) → 畫面上 伺服器上所有人的畫面同時停住,接著快轉、瞬移;停住的時間比逾時長時,會大量斷線
症狀 定格 , 快轉 , 瞬移 , 斷線
因素 停滯, 遺失
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
遊戲開發團隊要做的事 設定能撐過數秒停頓的逾時,停住後追趕的 tick 數要設上限,經過時間用 monotonic clock 計算,收到維護通知時要有儲存進度並把玩家移到其他伺服器的流程。
基礎設施團隊要做的事 訂閱維護通知並設定警示(Google Cloud maintenance-event、AWS 排程事件與 AWS Health、Azure Scheduled Events);收到通知後,趁玩家少的時段先替換伺服器;供應商允許時調整維護時間(Azure Maintenance Configuration,AWS 排程事件依類型而定);把維護紀錄與事故紀錄對照。
外部要做的事 向雲端供應商確認維護時程與影響範圍,同一執行個體反覆停頓時提出回報。
數值參考 Google Compute Engine 表示即時遷移的停頓通常遠短於 1 秒,停頓期間系統時鐘最多可能往前跳 5 秒。中繼資料的 maintenance-event 值會在搬移前 60 秒改變(前提是之前至少查詢過一次這個值)。Azure 表示不需重新開機的維護幾乎都在 10 秒以內,少數情況(一般 VM 大小每 18 個月不超過一次)會停頓約 30 秒,即時遷移通常不超過 5 秒。Azure Scheduled Events 至少會在 15 分鐘前通知這類停頓(Freeze)。不過主機硬體突然故障時,會不經通知直接開始復原。
圖表上 中斷後一次湧入 · 伺服器收發封包數、tick 間隔
查看位置 把停住的時間點與供應商紀錄對照。Google Cloud 看稽核 log 中的 compute.instances.migrateOnHostMaintenance,AWS 看 describe-instance-status 與 AWS Health 的排程事件,Azure 看活動 log(Activity Log)中的 Microsoft.Compute/virtualMachines/liveMigration/action,以及 VM 可用性指標(VmAvailabilityMetric)降為 0 的時間點。在伺服器內部查看停住期間指標與 log 是否出現空白,以及之後時鐘是否跳動(時間同步 log) 符合的跡象 整台伺服器停住的時間點與供應商記錄的維護或遷移時間重疊,且那幾秒內伺服器內部的指標與 log 全部空白 不符合的跡象 供應商紀錄中沒有、短暫停頓頻繁反覆時是「CPU steal(虛擬機器)」。kernel log 中有 NIC 重設紀錄時是「NIC 驅動程式/韌體問題」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 AWS 以排程事件通知。system-reboot 表示會重新開機並搬到新主機,system-maintenance 表示可能因網路、電源維護而短暫受影響。即使只停住幾秒,這段期間對伺服器送出封包卻沒收到 ACK 的用戶端,會把重傳等待時間一次次加倍,所以恢復之後 TCP 連線可能停住更久(「TCP RTO 與指數退避」)。停住後醒來時時鐘會跳動,有時會引發「系統時鐘跳動(NTP step)」,負載平衡器的健康檢查也可能失敗,把這台伺服器暫時移出。無法搬移的執行個體(Google Cloud 的裸機執行個體等)在維護時會被停止或重新啟動。
出處 6 筆
ID nic-reset · 主要負責 基礎設施團隊(伺服器基礎設施)
驅動程式 bug 或功能異常讓網路卡停住並重新啟動,這段期間所有收發都會中斷。
為什麼 驅動程式 bug、offload 功能異常 → 於是 NIC 停住後重新啟動(數秒) → 畫面上 那台伺服器上所有人的畫面一起停住,接著瞬移或斷線
症狀 定格 , 斷線
因素 遺失
誰會遇到 整個伺服器
何時 偶爾隨機發生, 開越久越嚴重
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 確認 kernel log 中的「transmit queue … timed out」、「Link is Down」紀錄並設定警示,更新驅動程式與韌體,關閉有問題的功能(offload 等)。
圖表上 中斷後一次湧入 · 伺服器收發封包數
查看位置 用 dmesg 在 kernel log 中找「NETDEV WATCHDOG … transmit queue N timed out」、驅動程式的重設,以及「Link is Down」、「Link is Up」紀錄,並查看該時間點伺服器的收發封包數 符合的跡象 停住的時間點 kernel log 中有傳送佇列逾時或鏈路 down/up 紀錄,且那幾秒內收發封包數為 0 不符合的跡象 kernel log 很乾淨、交換器端的 port 也正常時,是遊戲伺服器處理程序的停頓(「伺服器 GC 全面暫停」、「死結」)或「網路設備容錯移轉(failover)」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID nic-offload · 主要負責 基礎設施團隊(伺服器基礎設施)
這是把多個封包合併成一個來減輕 CPU 負擔的功能。依設定不同,小型遊戲封包有時會短暫等待下一個可以一起合併的封包。
為什麼 NIC 或 kernel 把到達的封包合併後處理 → 於是 開啟硬體合併(LRO)或合併等待時間設定時,會短暫等待下一個封包 → 畫面上 延遲些微增加(大多在數十 µs 以下)
症狀 輸入延遲
因素 延遲
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 依遊戲流量調整(關閉 LRO,確認合併等待時間設定),效果通常很小,排在其他原因之後確認。
圖表上 一開始就一直偏高 · 同一資料中心內的往返時間
查看位置 用 ethtool -k 確認 lro、gro 狀態,確認裝置的 sysfs 設定 gro_flush_timeout 值,並比較修改前後同一資料中心內小封包的往返時間 符合的跡象 LRO 為開啟或 gro_flush_timeout 大於 0,關閉或設為 0 後小封包的往返時間縮短 不符合的跡象 修改後差距在數 µs 以內時,就不是這個原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
L7 伺服器 OS(kernel)
14 個原因 · 完整版章節
連線等待佇列(backlog)溢位 Listen backlog / SYN queue overflow
ID so-backlog · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
維護剛結束時數萬人同時連線,kernel 的連線等待佇列(backlog)會溢位,連線請求因此被丟棄。
為什麼 維護一結束,連線湧入的速度就超過遊戲伺服器用 accept 處理連線的速度 → 於是 kernel 的連線等待佇列(backlog,取伺服器程式碼傳給 listen 的值與 kernel 上限中較小者)已滿 → 畫面上 連線請求被丟棄後不斷重試,結果連不上/無限讀取
症狀 連不上/無限讀取
因素 遺失
誰會遇到 整個伺服器
何時 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:調高程式碼傳給 listen 的值、避免負責接受連線的執行緒被其他工作卡住、導入登入排隊系統。用戶端:拉長重試間隔(加上隨機值分散重試)。
基礎設施團隊要做的事 調高 kernel 的 somaxconn(要和伺服器程式碼的 listen 值一起調高才有效)、保持 SYN cookie 開啟、監控溢位次數(nstat 的 TcpExtListenOverflows)。
數值參考 Linux kernel 的上限(somaxconn)從 5.4 起預設為 4,096(之前是 128),但伺服器程式碼傳給 listen 的值較小時,就以該值為上限。佇列滿了之後,Linux 會默默丟棄連線請求,不回傳任何錯誤。用戶端 OS 會從 1 秒後開始重送幾次,所以玩家看到的是遲遲跑不完的讀取畫面,很少直接看到「連線失敗」。Windows 伺服器則會回傳拒絕回應,用戶端馬上就會看到「連線失敗」。
圖表上 剛開服或維護結束後暴增 · 連線等待佇列溢位次數(ListenOverflows)、連線嘗試次數
查看位置 看 nstat -az 的 TcpExtListenOverflows、TcpExtListenDrops 增加量,並用 ss -ltn 比較 listen socket 的 Recv-Q(等待 accept 的連線數)與 Send-Q(backlog 上限) 符合的跡象 連線湧入的時間點 ListenOverflows 增加,listen socket 的 Recv-Q 貼齊 Send-Q 的值 不符合的跡象 ListenOverflows 沒有變化就不是這個原因。連線已建立但讀取跑不完時是「登入暴增與 N+1 查詢」;剛好卡在固定人數時是「檔案描述子上限」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆 listen(2) — Linux manual page Linux man-pages listen 的 backlog 超過 somaxconn 時會被默默截斷;somaxconn 預設 4,096(5.4 起,之前是 128);佇列滿時可以忽略請求,交給用戶端重試 IP Sysctl Linux kernel tcp_syn_retries:連線請求(SYN)會重送多次,第一次重傳前等待 1 秒;tcp_abort_on_overflow 預設關閉(溢位也不回傳拒絕回應);tcp_syncookies 預設開啟 listen function (winsock2.h) Microsoft Windows 在佇列滿時,用戶端會收到 WSAECONNREFUSED 錯誤 SNMP counter Linux kernel TcpExtListenOverflows:因 accept 佇列已滿而丟棄連線請求(SYN)的次數,此時 TcpExtListenDrops 也會一起增加 net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel ss 的 Recv-Q、Send-Q 值:listen socket 是等待 accept 的連線數與 backlog 上限;已連線的 socket 是應用程式尚未讀取的位元組數與尚未收到 ACK 的已送出位元組數
檔案描述子上限 File descriptor limit (ulimit)
ID so-fd · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
每個連線都需要一個檔案描述子(fd,OS 為開啟的檔案或 socket 指定的編號),而一個處理程序能開啟的 fd 數量有上限。
為什麼 同時上線人數達到處理程序的檔案描述子上限 → 於是 伺服器無法接受新連線(Too many open files),開啟 log 檔與 DB 連線也跟著失敗 → 畫面上 從某個固定人數起誰都進不來,出現連不上/無限讀取
症狀 連不上/無限讀取
因素 遺失
誰會遇到 整個伺服器
何時 剛登入/維護剛結束, 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 結束連線時確實關閉 socket(防止 fd 洩漏);accept 因 EMFILE(fd 不足)失敗時,暫停接受連線一段時間,或用事先保留的備用 fd 接受後立刻關閉(避免反覆處理同一個連線通知而浪費 CPU)。
基礎設施團隊要做的事 確認 ulimit 與服務設定(systemd 的 LimitNOFILE),接近上限時發出警示。
數值參考 Linux 若沒有另外設定服務,上限仍常是 1,024。遊戲伺服器通常會調高到數萬~數十萬。Windows 沒有這麼低的預設上限。
圖表上 碰到上限後持平 · 處理程序開啟的 fd 數、同時上線人數
查看位置 用 pidstat -v 看遊戲伺服器處理程序的 fd-nr(開啟的檔案描述子數),用 /proc/PID/limits 看開啟檔案數上限,並在伺服器 log 中找 accept 失敗(EMFILE, Too many open files) 符合的跡象 fd 數在上限值持平,從那個時間點起 accept 以 EMFILE 失敗 不符合的跡象 fd 數遠低於上限就不是這個原因。連線請求在 kernel 被丟棄時是「連線等待佇列(backlog)溢位」;問題出在連線追蹤時是「伺服器 conntrack 表飽和」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 沒被接受的連線會一直留在 kernel 的連線等待佇列(backlog)裡,依伺服器程式碼的寫法,可能會不斷收到「有新連線」的通知而浪費 CPU。
出處 5 筆
ID so-sockbuf · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
傳送與接收緩衝區太小時,一遇到突發流量,UDP 收到的封包就會被丟棄,TCP 則因緩衝區沒有空間而無法傳送。
為什麼 SO_SNDBUF、SO_RCVBUF 維持預設值或設得太小 → 於是 突發流量或接收執行緒短暫停住時,UDP 接收緩衝區溢位而丟棄封包;TCP 則因傳送緩衝區沒有空間而等待 → 畫面上 瞬移(UDP 遺失)或快轉(TCP 等待)
症狀 瞬移 , 快轉
因素 遺失, 停滯
誰會遇到 整個伺服器
何時 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 在程式碼中依流量設定緩衝區大小(SO_SNDBUF、SO_RCVBUF);注意 TCP 一旦直接指定大小,Linux 的自動調整(autotuning)就會關閉;設得太大會讓舊資料堆在緩衝區裡、延遲增加,所以大小要適中;避免接收執行緒停住。
基礎設施團隊要做的事 調整 kernel 上限(rmem_max、wmem_max,程式碼設定的緩衝區大小也不能超過這個值)與預設值(rmem_default),監控緩衝區溢位計數器(RcvbufErrors)。
數值參考 Linux 的 UDP 接收緩衝區預設值約 208KB。即使是小封包,每個在 kernel 記憶體中占用的空間也遠大於實際大小,數十~數百個就會塞滿。每秒接收 10 萬個封包的伺服器,接收執行緒只要停住幾 ms 就會溢位。
圖表上 偶爾隨機飆高 · UDP 接收緩衝區溢位(UdpRcvbufErrors)
查看位置 看 nstat -az 的 UdpRcvbufErrors 增加量與 ss -uamn 的 skmem(rb 是接收緩衝區大小,d 是無法放進 socket 而丟棄的封包數);TCP 則看 ss -tm 的 skmem 中,傳送等待記憶體(w)是否碰到傳送緩衝區大小(tb) 符合的跡象 突發流量或接收執行緒停住的時間點 UdpRcvbufErrors(或 socket 的 d)增加,rb 在預設值(約 208KB)附近。TCP 則是 w 貼齊 tb,send 卡住 不符合的跡象 計數器沒有變化卻有遺失時,問題在 NIC 階段(「Ring buffer 不足」)或網路區段 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 6 筆
執行緒過多與 context switch Thread oversubscription, context switching
ID so-context · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
執行緒數量遠多於 CPU 核心時,OS 會把 CPU 花在輪流切換執行緒上。
為什麼 例如每個連線各開一個執行緒,讓執行緒多達數百~數千個 → 於是 context switch(切換執行中的執行緒)的成本與快取未命中增加 → 畫面上 CPU 很忙,處理量卻很低,tick 忽長忽短,出現卡頓、慢動作
症狀 卡頓 , 慢動作
因素 停滯, 抖動
誰會遇到 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 執行緒數對應 CPU 核心數,使用非同步 I/O(epoll、IOCP)。
基礎設施團隊要做的事 監控 context switch 次數與等待執行的執行緒數(vmstat 的 cs、r)。
數值參考 一次 context switch 要數 µs,再加上之後的快取未命中成本會更高。
圖表上 隨人數/負載上升 · 每秒 context switch 次數、等待執行的執行緒數
查看位置 將 vmstat 1 的 cs(每秒 context switch 次數)、r(正在執行或等待 CPU 的數量)與 CPU 核心數比較,並用 pidstat -w -t 看遊戲伺服器各執行緒的自願(cswch/s)與非自願(nvcswch/s)context switch 符合的跡象 同時上線人數增加時,r 遠高於核心數,cs 也跟著往上衝,有數百個執行緒出現大量非自願 context switch 不符合的跡象 r 維持在核心數以下就不是這個原因。只有自願切換偏多時,是執行緒在等鎖或 I/O(「鎖競爭」、「阻塞式 I/O 架構」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
ID so-steal · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 外部(外部)
實體伺服器(hypervisor)把虛擬機器的 CPU 時間暫時讓給其他虛擬機器(CPU steal)時,遊戲伺服器會停住。
為什麼 同一台主機上的其他虛擬機器大量使用 CPU → 於是 自己的虛擬機器每次失去數 ms~數十 ms 的執行機會 → 畫面上 tick 時間莫名暴增,出現卡頓、定格
症狀 卡頓 , 定格
因素 停滯
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 外部(外部)
基礎設施團隊要做的事 監控 steal 指標(top、vmstat 的 st);使用專用核心或專用主機;避免 CPU 額度用完就變慢的突發型(burstable)執行個體;steal 持續偏高的執行個體先停止再啟動,移到其他主機。
外部要做的事 向雲端供應商回報 steal 持續偏高的主機。
圖表上 偶爾隨機飆高 · %steal、伺服器 tick 時間
查看位置 把 mpstat -P ALL 1 的 %steal 和伺服器 tick 時間放在同一條時間軸上看 符合的跡象 tick 飆高的時間點 %steal 也一起飆高,停止再啟動移到其他主機後就減少 不符合的跡象 %steal 接近 0 但 tick 仍飆高時,是遊戲伺服器內部的原因(「伺服器 GC 全面暫停」、「鎖競爭」)。在容器上時是「容器 CPU 節流(CFS 配額)」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
容器 CPU 節流(CFS 配額) Container CPU throttling (CFS quota)
ID so-cpu-quota · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
容器設了 CPU 上限時,只要在固定週期(通常是 100ms)內用完配額,剩下的時間就會被強制暫停(節流)。
為什麼 在 Kubernetes 等平台上為遊戲伺服器容器設定 CPU 上限(limit) → 於是 tick 計算集中的瞬間用完配額,暫停數十 ms 直到下一個週期 → 畫面上 平均 CPU 很低,tick 卻週期性飆高,出現卡頓、慢動作
症狀 卡頓 , 慢動作
因素 停滯, 抖動
誰會遇到 整個伺服器
何時 人潮湧入時, 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 讓工作執行緒數符合 CPU 上限(避免 runtime 依主機的全部核心數建立執行緒)。
基礎設施團隊要做的事 把 CPU 上限設得寬鬆一些,或拿掉上限改配置專用核心;監控被節流的次數(nr_throttled)。
數值參考 上限 2 核心的伺服器若有 8 個執行緒同時工作,會在 25ms 內用完 100ms 週期的配額,然後暫停 75ms。
圖表上 隨人數/負載上升 · 節流次數(nr_throttled)、伺服器 tick 時間
查看位置 將容器 cgroup 的 cpu.stat 中 nr_throttled、throttled_usec(cgroup v1 為 nr_throttled、throttled_time)的增加量與伺服器 tick 時間一起看 符合的跡象 平均 CPU 使用率低於上限,nr_throttled、throttled_usec 卻持續增加,且與 tick 飆高的時間點重疊 不符合的跡象 nr_throttled 沒有增加就不是這個原因。虛擬機器本身分不到 CPU 時是「CPU steal(虛擬機器)」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
伺服器電源管理(C-state、頻率調整)造成延遲飆高 CPU power management latency (C-states, frequency scaling)
ID so-cstate · 主要負責 基礎設施團隊(伺服器基礎設施)
閒置的 CPU 核心為了省電,會進入深層省電狀態(C-state)並降低頻率。封包或計時器到來時,喚醒核心並拉高頻率需要時間,處理小封包時就會多出延遲。
為什麼 OS 的頻率調整策略(governor)或 BIOS 電源設定允許深層 C-state 與低頻率 → 於是 閒置核心每次從深層省電狀態喚醒都會慢上最多數百 µs;頻率被鎖在低檔時,tick 計算本身也會變慢 → 畫面上 通常很難察覺,但伺服器之間的呼叫一多就會累積起來,變成人少時回應反而變慢的輸入延遲。頻率被鎖在低檔時,人潮湧入就會讓 tick 延後,出現慢動作
症狀 輸入延遲 , 慢動作
因素 延遲, 抖動, 停滯
誰會遇到 整個伺服器
何時 一直都有, 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 BIOS 電源設定改為效能優先,OS governor 設為 performance(cpufreq 的 scaling_governor);對延遲敏感的伺服器限制深層 C-state(tuned latency-performance 設定檔、PM QoS 的 /dev/cpu_dma_latency、kernel 參數 intel_idle.max_cstate);變更後一併比較同一資料中心內的往返時間、tick 時間抖動與耗電量。
數值參考 依 Linux 6.12 的 intel_idle 驅動程式表格,Intel 伺服器 CPU 從淺層 C1 喚醒需要 1~2µs,從深層 C6 需要 133µs(Skylake-SP)~290µs(Sapphire Rapids)。單次很短,但一個請求經過好幾台伺服器時就會跟著累積。kernel 預期的閒置時間越長,就越會選擇深層狀態,所以在封包零星到來的冷清伺服器上更常出現。通用 cpufreq 的 powersave governor 會把頻率固定在允許範圍內的最低值(intel_pstate 中同名的演算法則會依負載調整)。
圖表上 一開始就一直偏高 · 同一資料中心內的往返時間、核心頻率
查看位置 用 cpupower monitor 看各核心停留在各 C-state 的比例與實際頻率,確認 /sys/devices/system/cpu/cpu0/cpuidle/ 底下每個 state 的 name、latency(喚醒所需的 µs)、usage 與 cpufreq 的 scaling_governor,並用 tuned-adm active 確認目前的設定檔 符合的跡象 核心閒置時長時間停在最深的 C-state,或頻率被鎖在最低值附近;改用 performance governor 與淺層 C-state 後,小請求的往返時間與抖動減少 不符合的跡象 變更後差異在數十 µs 以內,這個原因可以忽略。以 ms 為單位飆高時是「CPU steal(虛擬機器)」或其他層 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 IDC 機房的裸機(bare metal)伺服器要同時檢查 BIOS(韌體)的電源設定與 OS 設定。在雲端上,只有部分執行個體類型能讓 OS 變更 C-state 與頻率,而 AWS 的預設設定偏向最高效能,大多維持原樣即可。Red Hat 系列的 tuned latency-performance 設定檔會把 governor 設為 performance,並透過 PM QoS 只使用淺層 C-state。關閉省電會增加耗電,所以只套用在對延遲敏感的伺服器上。
出處 7 筆
OOM killer Out-of-memory killer
ID so-oom · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
Linux 在記憶體耗盡時,會挑出使用最多記憶體的處理程序強制終止,通常就是遊戲伺服器。
為什麼 洩漏或用量暴增導致記憶體耗盡,或容器達到記憶體上限 → 於是 kernel 強制終止遊戲伺服器處理程序 → 畫面上 該伺服器上的所有人同時斷線,最近的進度可能回檔
症狀 斷線 , 吃指令/回檔
因素 停滯
誰會遇到 整個伺服器
何時 開越久越嚴重, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 修正洩漏;設定記憶體用量上限,並建立接近上限時先存檔再正常關閉的流程。
基礎設施團隊要做的事 設定記憶體警示、依實際用量設定容器記憶體上限、調整優先終止的順序(oom_score_adj)。
數值參考 kernel log(dmesg)會留下「Out of memory: Killed process」,在 Kubernetes 上則顯示為 OOMKilled。Windows 沒有 OOM killer,多半是記憶體配置失敗,伺服器因錯誤而當掉。
圖表上 連線同時大量中斷 · 連線數、記憶體用量
查看位置 將 dmesg 的「Out of memory: Killed process」紀錄、Kubernetes 上 Pod 狀態的 OOMKilled、cgroup v2 上 memory.events 的 oom_kill 增加,與斷線的時間點對照 符合的跡象 連線同時大量中斷的時間點,有終止遊戲伺服器處理程序的紀錄,而且在那之前記憶體用量一路升到上限 不符合的跡象 沒有 OOM 紀錄但處理程序死掉時,要查「伺服器當機」的當機 log 與 core dump 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
ID so-reclaim · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
OS 為了組出大分頁(huge page)而壓縮記憶體,或回收可用記憶體時,處理程序會停住。
為什麼 可用記憶體減少,或大分頁功能(THP)執行記憶體壓縮 → 於是 要求記憶體的執行緒一直等到回收或壓縮結束 → 畫面上 不規則的伺服器暫停(數 ms~數百 ms)
症狀 定格 , 卡頓
因素 停滯
誰會遇到 整個伺服器
何時 開越久越嚴重, 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 減少執行中的大型記憶體配置(啟動時預先配置並重複使用)。
基礎設施團隊要做的事 將大分頁(THP)設為只在需要的地方使用(madvise),調高可用記憶體的門檻(vm.min_free_kbytes 等)。
圖表上 偶爾隨機飆高 · 伺服器 tick 時間、記憶體 PSI
查看位置 將 /proc/pressure/memory 的 some、full(為等待記憶體而停住的時間比例)與 /proc/vmstat 的 compact_stall 增加量和伺服器 tick 時間一起看,並確認 /sys/kernel/mm/transparent_hugepage/defrag 設定 符合的跡象 tick 飆高的時間點記憶體 PSI 上升、compact_stall 增加。defrag 為 always 不符合的跡象 PSI 與 compact_stall 沒有變化就不是這個原因。swap 用量增加時是「Swap」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID so-timejump · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
伺服器時鐘一次被往前或往後調整幾秒時,依賴系統時鐘的計時器會同時觸發或停住。
為什麼 時間同步一次大幅調整時鐘 → 於是 計時器集中觸發或停住,逾時判定出錯 → 畫面上 buff 與冷卻時間異常、大家同時斷線、快轉
症狀 快轉 , 斷線 , 吃指令/回檔
因素 停滯
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 經過時間、逾時、冷卻時間都用不會跳動也不會倒退的單調時鐘(monotonic clock)計算,wall clock 只用於顯示與記錄。
基礎設施團隊要做的事 時鐘採漸進調整(chrony 的 makestep 只在剛啟動時使用),監控時間同步狀態(時鐘誤差)。
數值參考 ntpd 在差距超過 0.128 秒時會一次校正,差距較小時則慢慢校正,速度是消除 1 秒差距要花 30 多分鐘。現在常用的 chrony 在建議設定(makestep)下,只在剛啟動時一次校正幾次,之後就慢慢校正。虛擬機器短暫暫停後恢復時,時鐘也會跳動。
圖表上 偶爾隨機飆高 · 計時器觸發次數與斷線次數、時鐘調整紀錄
查看位置 在時間同步服務的 log 中找出一次大幅調整時鐘的紀錄,與發生異常的時間點對照。chrony 調整幅度超過 logchange 設定值(預設 1 秒)時會寫入 syslog 符合的跡象 buff 與冷卻時間異常、同時斷線、快轉發生的時間點有時鐘調整紀錄,且調整幅度與異常的大小相近 不符合的跡象 沒有時鐘調整紀錄就不是這個原因。在虛擬機器上時,也要查是否暫停後恢復(「雲端主機維護與即時遷移」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
排程工作 Cron jobs (log rotation, backup, scans)
ID so-cron · 主要負責 基礎設施團隊(伺服器基礎設施)
每天固定時間執行的 log 壓縮、備份、安全掃描會占用 CPU 與磁碟。
為什麼 OS 工作在排定的時間執行 → 於是 與遊戲伺服器共用 CPU 與磁碟 → 畫面上 像每天凌晨 4 點這樣的固定時間出現卡頓、慢動作
症狀 卡頓 , 慢動作
因素 停滯
誰會遇到 整個伺服器
何時 固定週期
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 錯開工作時間、降低優先順序(nice、ionice)、與遊戲伺服器分開(在另一台伺服器上執行)。
圖表上 固定週期飆高 · CPU 使用率、磁碟佇列、伺服器 tick 時間
查看位置 用 crontab 與 systemctl list-timers 整理排程工作的執行時間,並在 tick 飆高的時間點用 pidstat -u -d 看是哪個處理程序在使用 CPU 與磁碟 符合的跡象 tick 每天(或每小時)在同一時間飆高,那個時間點排程工作的處理程序占用 CPU 與磁碟 不符合的跡象 飆高的時間點和每天的固定時間對不上就不是這個原因。每隔幾秒或幾分鐘飆高時是「伺服器 GC 全面暫停」、「計時器集中同時觸發」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
OS、kernel、驅動程式、韌體更新後的效能變化 Performance regression after OS / kernel / driver / firmware update
ID so-os-update · 主要負責 基礎設施團隊(伺服器基礎設施)
遊戲程式碼沒變,但伺服器 OS、kernel、驅動程式、韌體更新後就變慢。更新有時會改變預設值、排程器、CPU 漏洞緩解措施(mitigations)與驅動程式的行為。
為什麼 定期安全性更新或新的伺服器映像檔讓 kernel、驅動程式、韌體有所改變 → 於是 預設值或排程器改變,或啟用了新的漏洞緩解措施,同樣的工作要花更多 CPU 時間,執行緒分配到 CPU 的順序也跟著改變 → 畫面上 原本正常的伺服器從更新那天起一直都慢一點,出現輸入延遲;人潮湧入時出現卡頓、慢動作
症狀 輸入延遲 , 卡頓 , 慢動作
因素 延遲, 停滯, 抖動
誰會遇到 整個伺服器
何時 一直都有, 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 更新先套用在部分伺服器上,將 tick 時間、延遲、CPU 使用率與前一版比較後再擴大範圍;與遊戲更新錯開日期部署;記錄更新前後的 kernel、驅動程式、韌體版本與主要 sysctl 值;出問題時改用前一版 kernel 開機確認;是否關閉緩解措施(mitigations=off)要評估資安風險後再決定。
數值參考 kernel 版本改變,預設行為也會跟著改變。例如 Linux 從 6.6 起開始把排程器從 CFS 換成 EEVDF,連線等待佇列上限(somaxconn)的預設值也從 5.4 起由 128 改為 4,096。CPU 漏洞緩解措施會增加額外工作,例如從 kernel 返回程式時(每次系統呼叫結束時)以及 context switch、虛擬機器切換時清空 CPU 內部緩衝區,所以每個封包都要發出系統呼叫的網路伺服器受到的影響更大。有些漏洞要完全防堵就必須關閉 SMT(讓一個核心當成兩個執行緒使用的功能),而關閉 SMT 後,依工作性質效能可能大幅下降。kernel 參數 mitigations=off 會關閉所有緩解措施、找回效能,但系統會暴露在漏洞之下。
圖表上 從某個時間點起階梯式上升 · 伺服器 tick 時間、CPU 使用率、相同負載下的延遲
查看位置 將套件管理工具的更新紀錄與重新開機時間、uname -r 顯示的 kernel 版本、ethtool -i 顯示的 NIC 驅動程式資訊,與延遲上升的時間點對照。在相同負載下用 mpstat、pidstat 比較已更新與未更新的伺服器,也比較 /sys/devices/system/cpu/vulnerabilities/ 的緩解狀態 符合的跡象 延遲與 CPU 使用率從更新後重新開機的時間點起上升一階並維持不變,在相同負載下只有已更新的伺服器偏高。改用前一版 kernel 或驅動程式開機就恢復 不符合的跡象 在相同負載下已更新與未更新的伺服器一樣慢就不是這個原因。同一天也部署了遊戲更新,且每位玩家的封包數或大小有變時是「更新改變了流量模式」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 緩解狀態可在 /sys/devices/system/cpu/vulnerabilities/ 底下的檔案確認。預設值(mitigations=auto)會在保持 SMT 開啟的情況下進行緩解;設為 auto,nosmt 時,會在有漏洞的 CPU 上關閉 SMT,升級 kernel 後邏輯核心數可能減半。在遊戲更新的同一天更新 OS 會難以分辨原因,所以要分開部署。
出處 6 筆
ID so-conntrack · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
Linux 防火牆會把每條連線記錄在連線追蹤(conntrack)表中,這個表碰到上限時就會丟棄新封包。
為什麼 連線暴增或反覆建立短連線,讓連線紀錄增加 → 於是 表已滿,新連線與部分封包被丟棄 → 畫面上 連不上,或因原因不明的遺失出現瞬移
症狀 連不上/無限讀取 , 瞬移
因素 遺失
誰會遇到 整個伺服器
何時 剛登入/維護剛結束, 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:減少短連線(伺服器之間的呼叫重複使用連線)。用戶端:連線失敗或中斷時,逐步拉長重試間隔並加上隨機值分散。
基礎設施團隊要做的事 加大表的大小(nf_conntrack_max)、讓遊戲 port 不做追蹤(raw 表的 NOTRACK)、設定用量警示。
數值參考 預設上限依伺服器記憶體約為 6 萬~26 萬筆。溢位時 kernel log 會出現「nf_conntrack: table full, dropping packet」。
圖表上 碰到上限後持平 · conntrack 項目數(nf_conntrack_count)
查看位置 把 sysctl 的 net.netfilter.nf_conntrack_count(目前項目數)與 nf_conntrack_max 放在同一張圖表上,並在 dmesg 中找「nf_conntrack: table full, dropping packet」 符合的跡象 nf_conntrack_count 在 max 持平,從那個時間點起 kernel log 出現 table full 不符合的跡象 項目數遠低於 max 就不是這個原因。AWS 執行個體本身的連線追蹤上限,要看「超過雲端 PPS 上限」中提到的 conntrack_allowance_exceeded 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
伺服器間連線的臨時 port 耗盡 Ephemeral port exhaustion (TIME_WAIT)
ID so-ports · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲伺服器頻繁地對 DB 或其他伺服器建立又關閉短連線時,已關閉的連線會占用 port 一段時間,導致無法開啟新連線。
為什麼 每個請求都開啟再關閉一條新連線 → 於是 先關閉的一方會以 TIME_WAIT 狀態占用 port 約 60 秒(Linux),可用的 port 因此耗盡 → 畫面上 內部請求失敗,導致存檔失敗、功能異常
症狀 吃指令/回檔 , 連不上/無限讀取
因素 遺失
誰會遇到 整個伺服器, 只有特定功能
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 重複使用連線(連線池),不要每個請求都重新開關連線。
基礎設施團隊要做的事 擴大 port 範圍(ip_local_port_range)、評估對外連線重複使用 TIME_WAIT(Linux 的 tcp_tw_reuse)、監控 TIME_WAIT 數量。
數值參考 Linux 的預設 port 範圍(32768~60999)約有 2 萬 8 千個。對同一個目的位址每秒建立超過 470 次新連線就會耗盡。Windows 的預設 port 約 1 萬 6 千個(49152~65535),TIME_WAIT 也更長,所以更快耗盡。
圖表上 碰到上限後持平 · TIME_WAIT socket 數、內部連線失敗次數
查看位置 用 ss -tan state time-wait 依目的位址計算 TIME_WAIT socket 數,並在遊戲伺服器 log 中找 connect 失敗(EADDRNOTAVAIL) 符合的跡象 連往同一目的地(DB 等)的 TIME_WAIT 在臨時 port 範圍(預設約 2 萬 8 千個)附近持平,connect 以 EADDRNOTAVAIL 失敗 不符合的跡象 TIME_WAIT 不多,卻只有連往外部的連線失敗時是「雲端 NAT 閘道的連線與 port 上限」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 Linux 的 TIME_WAIT 60 秒是寫死在 kernel 裡的值。調低名稱相似的 tcp_fin_timeout 並不會縮短 TIME_WAIT。
出處 5 筆
L8 Socket 與協定
14 個原因 · 完整版章節
TCP HOL 阻塞 Head-of-line blocking
ID sk-hol · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
TCP 為了維持順序,在重新收到遺失的那一個封包之前,不會把之後到達的封包交給遊戲。
為什麼 一個封包遺失 → 於是 後面的封包都已抵達,卻只能在接收緩衝區等待 → 畫面上 停住之後一口氣全部放行,出現快轉
症狀 定格 , 快轉
因素 遺失, 停滯
誰會遇到 只有我
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:即時位置改用 UDP,只有真正必要的資料才用可靠傳輸,並拆成多條串流。用戶端:網路處理改成與伺服器相同的方式(UDP、分開通道)。
數值參考 遺失一個封包至少會停住一個往返時間再多一點,連重傳的封包也遺失時會停住數百 ms~數秒。
圖表上 中斷後一次湧入 · 每條連線的接收量、重傳次數
查看位置 用伺服器端的封包擷取(tcpdump、Wireshark)看該玩家連線上的重傳封包及其前後的空白;整個伺服器則看 nstat -az 的 TcpRetransSegs 增加量 符合的跡象 停住的區間從某一個封包的重傳開始,重傳封包一抵達,積壓的資料就一口氣處理完(接收量先是 0,接著暴增) 不符合的跡象 用 UDP 通訊的遊戲不適用。沒有重傳卻停住時,要查伺服器 tick(「超出 tick 預算」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
TCP RTO 與指數退避 RTO and exponential backoff
ID sk-rto · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
每次重傳又失敗,等待時間就加倍,於是線路短暫中斷會變成長時間停住。
為什麼 線路短暫中斷,重傳也接連失敗 → 於是 到下一次嘗試的等待時間以 0.3 → 0.6 → 1.2 → 2.4 秒逐次加倍(以 ping 100ms 計) → 畫面上 線路只斷了 1 秒,遊戲卻停住 2 秒以上。斷得更久最後就會斷線
症狀 定格 , 斷線
因素 遺失, 停滯
誰會遇到 只有我
何時 偶爾隨機發生, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:回應心跳封包,一段時間沒收到就主動清理連線(用 TCP_USER_TIMEOUT 縮短放棄連線前的等待時間),用 session token 接續連線,採用可靠 UDP。用戶端:以短間隔送出心跳封包,沒有回應時不要等 TCP 重傳,儘快重新連線。
數值參考 Linux 的 RTO(重傳等待時間)最小為「ping + 200ms」,建立連線時從 1 秒開始。預設設定(tcp_retries2=15)下,即使重傳一直失敗,也要約 15 分鐘後才會放棄連線。
圖表上 中斷後一次湧入 · 每條連線的 RTO 與 backoff、RTO 到期次數
查看位置 用 ss -ti 看停住的連線的 rto(重傳等待 ms)與 backoff(連續到期次數);整個伺服器則看 nstat -az 的 TcpExtTCPTimeouts(重傳計時器到期次數)增加量 符合的跡象 停住的連線 backoff 為 1 以上,rto 已變大到以秒計,那個時間點 TCPTimeouts 增加 不符合的跡象 重傳以快速重傳完成、沒有 RTO 到期時,停住的時間很短。這時是「TCP HOL 阻塞」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 6 筆
Nagle 演算法 + 延遲 ACK Nagle + delayed ACK (TCP_NODELAY off)
ID sk-nagle · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
把小封包集中起來送的 Nagle 演算法,與延後送出 ACK 的延遲 ACK 互相牽制,每次把訊息分段寫入就會延遲 40~200ms。
為什麼 沒有開啟 TCP_NODELAY 就分段寫入小訊息 → 於是 傳送端在等 ACK,接收端卻延後送出 ACK → 畫面上 線路 ping 很低,每個動作卻都固定慢半拍,出現輸入延遲
症狀 輸入延遲
因素 延遲
誰會遇到 整個伺服器, 只有我
何時 一直都有, 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:開啟 TCP_NODELAY;把一個 tick 內的訊息集中起來一次寫入;關閉接收端延遲 ACK 的方法(Linux 的 TCP_QUICKACK 只維持一小段時間,Windows 要逐台電腦修改登錄檔)遊戲無法確實掌控,不要依賴。用戶端:開啟 TCP_NODELAY,把一個畫格內的訊息集中起來一次寫入。
數值參考 Linux 的延遲 ACK 通常是 40ms(視情況最多 200ms)。Windows 舊版是 200ms,現在的版本是 40ms(Windows Server 2019 預設範本為 40ms)。延遲 ACK 由接收端 OS 決定,所以伺服器在 Nagle 開啟的狀態下分段送出訊息時,依接收端電腦不同,每次可能延遲 40~200ms。
圖表上 一開始就一直偏高 · 動作回應時間(遊戲內 RTT)
查看位置 在伺服器端的封包擷取(tcpdump、Wireshark)中看請求與回應之間的間隔,並確認伺服器與用戶端程式碼是否開啟 TCP_NODELAY 符合的跡象 線路 ping 很低,小封包之間卻反覆出現 40ms(Windows 舊版為 200ms)左右的空白,且空白在對方的 ACK 到達後隨即結束。開啟 TCP_NODELAY 後消失 不符合的跡象 回應間隔與線路 ping 相近就不是這個原因。遊戲伺服器產生回應太慢時,問題在伺服器處理(「訊息佇列積壓」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
慢速用戶端造成的阻塞式傳送 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 呼叫)等待時是「鎖競爭」、「遊戲執行緒上的同步呼叫」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
ID sk-slow-client · 主要負責 遊戲開發團隊(伺服器開發)
對於待傳送資料不斷累積的用戶端,伺服器會丟棄過時的狀態更新,或直接切斷連線。
為什麼 用戶端的線路跟不上伺服器送出的資料量 → 於是 伺服器丟棄過時的狀態更新,或在超過上限時切斷連線 → 畫面上 只有那個人出現瞬移或斷線
症狀 瞬移 , 斷線
因素 遺失
誰會遇到 只有我
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 減少傳送量(依距離調整更新頻率)、降低品質但持續傳送、減少堆在 kernel 裡的資料量(Linux 的 TCP_NOTSENT_LOWAT)。
數值參考 傳送緩衝區為 256KB 時,在 30KB/s 的線路上會累積超過 8 秒的積壓資料。Linux 有時還會自動把這個緩衝區放大到數 MB。
圖表上 只有部分偏高 · 每條連線的 Send-Q、每個用戶端丟棄的狀態更新數
查看位置 看遊戲伺服器記錄的各用戶端傳送佇列長度、丟棄的狀態更新數與斷線原因,並在伺服器上用 ss -tni 一併確認該連線的 Send-Q 與 cwnd 符合的跡象 只有瞬移或斷線的人的連線 Send-Q 一直是滿的,遊戲 log 中記錄了該玩家的狀態更新遭丟棄,或因超過傳送佇列上限而斷線 不符合的跡象 Send-Q 是空的卻仍瞬移時,問題不在伺服器傳送端。要查該玩家線路的封包遺失(「無線區段的封包遺失」)或畫面內插 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆 IP Sysctl Linux kernel tcp_wmem:自動調整的傳送緩衝區上限預設為 64KB~4MB(依記憶體而定);以 tcp_notsent_lowat、TCP_NOTSENT_LOWAT 限制尚未送出的資料量 net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel ss 的 Recv-Q、Send-Q 值:listen socket 是等待 accept 的連線數與 backlog 上限;已連線的 socket 是應用程式尚未讀取的位元組數與尚未收到 ACK 的已送出位元組數
ID sk-keepalive · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
對方沒有送出關閉訊號就消失時,TCP 要過很久才會察覺。keepalive(確認閒置連線是否仍存活的 TCP 功能)預設是關閉的,即使開啟,也要閒置 2 小時才開始確認。
為什麼 用戶端因斷電或線路中斷,沒有送出關閉訊號就消失 → 於是 伺服器認為連線仍存活(keepalive 預設 7,200 秒;若有正在傳送的資料,約 15 分鐘後才放棄重傳) → 畫面上 留下幽靈角色,重新連線時出現「帳號已登入」錯誤
症狀 連不上/無限讀取 , 看不見/幽靈物件
因素 遺失
誰會遇到 只有我
何時 閒置一段時間後, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 伺服器:回應心跳封包,一段時間沒收到就主動清理連線(調整 TCP_KEEPIDLE、TCP_USER_TIMEOUT);重新連線時用 session token 取代既有 session 並接續。用戶端:以數秒~數十秒的間隔(最短閒置逾時的一半以下)送出遊戲層級的心跳封包,斷線時自動重新連線。
基礎設施團隊要做的事 針對程式碼沒有自行設定的 socket,調低 kernel 預設值(tcp_keepalive_time 等)。只對開啟 SO_KEEPALIVE 的 socket 有效。
數值參考 Linux 的預設值是閒置 7,200 秒後開始確認,每隔 75 秒送出一次探測封包(probe),共 9 次,始終沒有回應就切斷連線。加起來約 2 小時 11 分鐘。Windows 預設也要閒置 2 小時才開始確認。
圖表上 只有部分偏高 · 每條連線距上次接收的經過時間
查看位置 用 ss -tnoi 看每條連線的 lastrcv(距上次接收的經過 ms)與 keepalive 計時器(timer:(keepalive,…)),並與遊戲伺服器「帳號已登入」的拒絕紀錄對照 符合的跡象 仍留有 lastrcv 達數分鐘~數小時的 ESTABLISHED 連線,且該帳號重新連線時以「帳號已登入」遭拒 不符合的跡象 沒有長時間沉寂的連線卻仍出現「帳號已登入」時,要查遊戲伺服器清理 session 的程式碼 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
UDP 封包的 IP 分段 IP fragmentation of large UDP
ID sk-fragment · 主要負責 遊戲開發團隊(伺服器開發)
超過 MTU(一次能傳送的最大大小)的 UDP 封包會在 IP 層被分段(fragmentation),只要遺失其中一個分段,整個封包就會被丟棄。
為什麼 人多之處的快照超過 1,500 位元組 → 於是 拆成多個分段傳送,只要遺失一個就整個丟棄 → 畫面上 封包越大,遺失率高出好幾倍。只在人多的地方出現瞬移
症狀 瞬移
因素 遺失
誰會遇到 特定地點/頻道, 特定地區/電信業者
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 自行把封包切成 1,200 位元組以下、只傳送變更的部分。
數值參考 在遺失率 2% 的線路上,拆成 4 個分段的封包約有 8% 會消失。也有防火牆或電信業者會直接丟棄分段的封包,這些玩家就完全收不到大封包。
圖表上 隨人數/負載上升 · IP 分段數(IpFragCreates)、快照大小
查看位置 在伺服器上看 nstat -az 的 IpFragCreates(傳送時產生的分段數)增加量,接收端則看 IpReasmFails(重組失敗次數)。用遊戲伺服器 log 或封包擷取確認 UDP 封包大小的分布 符合的跡象 人潮聚集的地方 IpFragCreates 增加,出現超過 1,500 位元組的 UDP 封包,同時瞬移的回報也變多 不符合的跡象 IpFragCreates 沒有增加時,伺服器傳送端沒有發生分段 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
可靠 UDP 的重傳設定 Reliable-UDP tuning (KCP, ENet…)
ID sk-reliable-udp · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
在 UDP 上自行實作的重傳規則太保守時復原會變慢,太積極時反而讓線路更壅塞。
為什麼 重傳間隔、次數、視窗大小的設定與線路不相符 → 於是 復原太慢,或重複傳送讓壅塞惡化 → 畫面上 技能被吃、快轉、壅塞時 lag 更嚴重
症狀 吃指令/回檔 , 快轉
因素 遺失, 延遲
誰會遇到 只有我
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:依實測的往返時間決定重傳時機,並依重要程度分開通道。用戶端:套用與伺服器相同的重傳與通道設定。
圖表上 偶爾隨機飆高 · 可靠 UDP 的重傳比例、遊戲內 RTT
查看位置 在伺服器與用戶端記錄所用函式庫的每條連線統計(重傳次數、估計往返時間、重傳等待時間),並與同一玩家實際的線路遺失率(用 mtr 測得的值)比較 符合的跡象 重傳比例比實際線路遺失率高出好幾倍時是設定太積極;重傳等待時間是實測往返時間的好幾倍時是設定太保守 不符合的跡象 重傳比例與線路遺失率相近、等待時間也符合往返時間時,就不是設定問題。要查線路遺失本身 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 1 筆
ID sk-slowstart · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
連線閒置一段時間後,TCP 會再次縮小壅塞視窗(一次能送出的量),所以突然要送大量資料時,得分成好幾次送出。
為什麼 透過原本閒置的連線送出進入城鎮等大量資料 → 於是 壅塞視窗已縮小,只能分成多個往返傳送 → 畫面上 剛進入時,周圍的角色與 NPC 晚了好幾個往返才出現(伺服器越遠越明顯)
症狀 輸入延遲 , 看不見/幽靈物件
因素 延遲
誰會遇到 只有我
何時 移動中/切換地圖時, 閒置一段時間後
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 減少進入時的資料量(先送真正必要的部分)。
基礎設施團隊要做的事 關閉 tcp_slow_start_after_idle(Linux,整台伺服器的設定)。
數值參考 閒置超過 RTO 時壅塞視窗就開始縮小,閒置很久的話會降到約 14KB(10 個封包)。這時 100KB 無法一次送出,要分成 3 個往返傳送。
圖表上 只有部分偏高 · 剛進入時的傳送時間(RTT 較長的玩家)
查看位置 確認 sysctl net.ipv4.tcp_slow_start_after_idle 的值,並在玩家閒置後進入某個區域的瞬間,看該連線 ss -ti 中的 cwnd(壅塞視窗)是否變小 符合的跡象 設定為 1(預設),閒置後進入的瞬間 cwnd 降到 10 左右,傳送被拆成多個往返。RTT 越長的玩家,周圍物件出現得越晚,改成 0 後就不再發生 不符合的跡象 cwnd 維持在高檔仍然很晚出現時,要查伺服器端的進入處理(「進入密集區域時的生成暴增」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
壅塞控制造成傳送量驟降 Congestion control backoff
ID sk-congestion · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
TCP 把封包遺失視為壅塞的訊號,會把傳送速率降低 30~50%。對 Wi-Fi 造成的遺失也會做出同樣的反應。
為什麼 要送的資料量大時,Wi-Fi 或線路上發生少量封包遺失 → 於是 TCP 大幅降低傳送速率後慢慢回升(Linux、Windows 預設的 CUBIC 會降低 30%) → 畫面上 人多的地方狀態更新積壓,出現快轉、輸入延遲
症狀 快轉 , 輸入延遲
因素 延遲, 停滯
誰會遇到 只有我
何時 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 減少傳送量(只送 AOI 內、只送變更部分),分散傳送,避免一次全部送出。
基礎設施團隊要做的事 改用 BBR 等壅塞控制演算法(tcp_congestion_control)。
圖表上 緩慢爬升後驟降 · 每條連線的壅塞視窗(cwnd)與傳送速率
查看位置 對狀態更新積壓的玩家連線多次執行 ss -ti,看 cwnd、ssthresh 的變化與壅塞控制演算法名稱(cubic、bbr),並一併看 Send-Q 是否累積 符合的跡象 每次遺失後 cwnd 大幅縮小再慢慢回升,反覆發生;縮小期間 Send-Q 累積,與快轉、輸入延遲的回報時間重疊 不符合的跡象 cwnd 很充足仍然積壓時,要查接收端視窗(「Zero window(看起來像重傳的停頓)」)或伺服器傳送端 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
ID sk-linger · 主要負責 遊戲開發團隊(伺服器開發)
伺服器倉促切斷連線時,最後送出的通知或存檔完成訊號會消失。
為什麼 伺服器以強制關閉(RST)結束連線。把 SO_LINGER 設為 0 秒,或沒讀完收到的資料就關閉時會發生 → 於是 仍在傳送中的踢出原因與最後的資料被丟棄 → 畫面上 沒來由地出現「因不明錯誤中斷連線」
症狀 斷線
因素 遺失
誰會遇到 只有我
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 送出原因後先只關閉傳送方向(shutdown),把收到的資料一直讀到對方關閉為止再關閉 socket;避免把 SO_LINGER 設為 0 秒。
圖表上 偶爾隨機飆高 · 以 RST 結束的連線數
查看位置 看 nstat -az 的 TcpExtTCPAbortOnData(還有資料要送就以 RST 關閉,SO_LINGER 0 秒)、TcpExtTCPAbortOnClose(還有未讀資料就關閉)增加量,並在斷線瞬間的伺服器端封包擷取中,看原本該送 FIN 的地方是否送出了 RST 符合的跡象 在「因不明錯誤中斷連線」的回報時間,伺服器送出 RST,且 AbortOnData、AbortOnClose 增加 不符合的跡象 伺服器以 FIN 正常關閉,原因卻沒有顯示時,要查用戶端的關閉處理 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
ID sk-blocking-io · 主要負責 遊戲開發團隊(伺服器開發)
執行緒在等待某個 socket 時無法做其他事的架構,玩家越多整體就越慢。
為什麼 每條連線各自等待讀寫的方式 → 於是 一條連線的延遲擴散到同一執行緒的其他連線 → 畫面上 同時上線人數越多,所有人都出現慢動作、輸入延遲
症狀 慢動作 , 輸入延遲
因素 停滯
誰會遇到 整個伺服器
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 改用以 epoll、IOCP、io_uring 為基礎的非同步 I/O。
圖表上 隨人數/負載上升 · 回應時間、執行緒數
查看位置 用 pidstat -w -t 看遊戲伺服器的執行緒數與各執行緒的自願 context switch(cswch/s,為等待資源而停下的次數),並與隨同時上線人數變化的回應時間比較 符合的跡象 同時上線人數越多,回應時間上升得越陡;隨連線數增加的執行緒大多只有自願切換很多,幾乎不使用 CPU(在等 socket) 不符合的跡象 執行緒沒有等待、持續使用 CPU 時,是運算過載(「超出 tick 預算」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
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)溢位」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
ID sk-udp-connreset · 主要負責 遊戲開發團隊(伺服器開發)
Windows 伺服器向已經離開的用戶端送出 UDP 時,會收到「port 無法到達」(ICMP)的通知。這個通知會讓下一次接收呼叫以錯誤結束;如果伺服器程式碼把這個錯誤當成 socket 本身故障來處理,所有使用該 socket 的人都會受到影響。
為什麼 持續向剛離開的用戶端位址送出 UDP,收到「port 無法到達」(ICMP)通知 → 於是 Windows 讓下一次接收呼叫以 WSAECONNRESET(10054)錯誤結束,伺服器程式碼因此停止接收或關閉 socket → 畫面上 使用該 socket 的所有人同時定格、斷線
症狀 斷線 , 定格
因素 遺失, 停滯
誰會遇到 整個伺服器
何時 偶爾隨機發生, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用 WSAIoctl 關閉 SIO_UDP_CONNRESET,不再接收這個通知;發生接收錯誤時只記 log,繼續接收。
圖表上 連線同時大量中斷 · 連線數、接收錯誤 log
查看位置 在遊戲伺服器 log 中找 UDP 接收錯誤碼(WSAECONNRESET,10054),以及接收迴圈停止或關閉 socket 的紀錄,並用伺服器端的封包擷取看之前是否剛收到 ICMP Port Unreachable 符合的跡象 連線同時大量中斷前剛好記錄到 WSAECONNRESET 接收錯誤,更早之前有 ICMP Port Unreachable 從剛離開的用戶端位址傳來 不符合的跡象 Linux 伺服器,或程式碼已關閉 SIO_UDP_CONNRESET 時不適用 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
L9 伺服器遊戲程式
18 個原因 · 完整版章節
ID sp-tick-overrun · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
一個 tick 內要做的事超出預算時,伺服器的 tick 週期會拉長,整個區域的遊戲進行變慢,或出現卡頓。
為什麼 一個 tick(例如 50ms)要處理的事超出預算 → 於是 每秒應計算 20 次的遊戲狀態只算了 8 次 → 畫面上 整個區域出現慢動作(依伺服器設計也可能是卡頓),技能反應變慢
症狀 慢動作 , 輸入延遲 , 卡頓
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 減少昂貴的運算、把 tick 拆給多個執行緒處理、分散人數(頻道)、把 tick 處理時間記錄為指標。
基礎設施團隊要做的事 把 tick 時間與各核心的 CPU 使用率加入監控與警示;評估單核心效能(時脈)較高的 CPU 或執行個體。
數值參考 20 tick 伺服器的預算是 50ms,30 tick 是 33ms,60 tick 是 16.7ms。為了因應人潮突然湧入,平時保留餘裕、只用到預算的一半左右比較安全。
圖表上 隨人數/負載上升 · 伺服器 tick 時間、各 zone/頻道的人數、遊戲執行緒 CPU
查看位置 把伺服器記錄的 tick 處理時間(p99)、tick 超出預算的次數與各 zone/頻道的人數放在同一張圖表上看。沒有 tick 指標時,用 pidstat -t 1 看單一遊戲執行緒的 CPU 使用率 符合的跡象 人潮湧入時 tick 時間超出預算(20 tick 時為 50ms),這段期間遊戲執行緒的 CPU 使用率一直貼近 100% 不符合的跡象 tick 超出預算但遊戲執行緒 CPU 偏低時,是等待類的原因(GC 暫停、鎖、同步呼叫)。bcc runqlat 的 run queue 延遲很長時,表示執行緒分配不到 CPU,是 CPU 不足或執行緒過多 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 伺服器 tick 延遲時呈現的樣子依伺服器設計而不同。每個 tick 讓遊戲狀態前進固定時間(例如 50ms)的伺服器,遊戲時間本身會變慢,形成慢動作。依實際經過的時間一次移動到位的伺服器能維持遊戲進行的速度,但封包變得稀疏、每次移動幅度很大,看起來就是卡頓或瞬移。無論哪一種,輸入反應都會變慢。一個遊戲執行緒負責整台伺服器時,整台伺服器都會變慢;每個區域各有執行緒時,只有那個區域變慢。也有像 EVE Online 這樣的遊戲,在大規模戰鬥中刻意把遊戲時間放慢到最多 10 倍(Time Dilation),讓運算跟得上。
實際案例 CCP Games 2014: EVE Online HED-GP 大規模艦隊戰的伺服器過載
出處 5 筆
ID sp-aoi · 主要負責 遊戲開發團隊(伺服器開發)
若要判斷誰能看到誰而讓所有人兩兩比較,人數變成 10 倍時,運算量會變成 100 倍。
為什麼 所有角色兩兩比較距離,或即使切成格狀(grid),一個格子附近仍擠了數百人 → 於是 100 人約比較 1 萬次,1,000 人約 100 萬次 → 畫面上 在世界王、攻城戰等人潮聚集的地方 tick 時間暴增,出現慢動作、卡頓
症狀 慢動作 , 卡頓
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 以格狀或區塊切分、只比較附近的對象;遠處的對象降低更新頻率;限制一個人能看到的人數上限。
數值參考 假設距離比較加上「看得見/看不見」清單的更新,每兩人一對要花 0.1µs(千萬分之一秒),1,000 人(約 100 萬對)時一個 tick 要花 100ms。這是 20 tick 預算(50ms)的 2 倍。
圖表上 隨人數/負載上升 · 伺服器 tick 時間、聚集在同一處的人數
查看位置 把各 zone/頻道的人數與 tick 時間放在同一張圖表上,並看 tick 中視野計算所花時間的單獨量測值。沒有單獨量測時,用 perf top -p 看遊戲處理程序各函式的 CPU 占比 符合的跡象 同一處的人數變成 2 倍時 tick 時間增加將近 4 倍,視野與距離計算函式占了大部分 CPU 時間 不符合的跡象 tick 時間與人數成正比增加,或傳送、序列化函式的占比很大時,是「廣播量暴增」或「序列化與壓縮的成本」 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
廣播量暴增 Broadcast fan-out (N×N)
ID sp-broadcast · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
把一個人的移動送給所有看得到他的人時,要送出的狀態更新數量會是聚集人數的平方。
為什麼 把一個人的變化傳送給所有看得到的人 → 於是 1,000 人互相看得到時,每個 tick 有 100 萬筆狀態更新 → 畫面上 傳送佇列與頻寬飽和,造成延遲與遺失(輸入延遲、快轉、瞬移)
症狀 輸入延遲 , 瞬移 , 快轉
因素 延遲, 遺失
誰會遇到 特定地點/頻道, 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 依距離與重要程度降低更新頻率(近處的敵人每個 tick 更新,遠處的人每秒幾次);為送給每個人的資料量設上限,從重要的開始填入;把多筆狀態更新打包進一個封包;限制顯示人數上限。
基礎設施團隊要做的事 將各伺服器的傳送頻寬與每秒封包數與 NIC、執行個體的網路上限比較並設警示;大型活動前確認餘裕。
數值參考 1,000 人 × 1,000 人 × 20 tick = 每秒 2,000 萬筆。每筆 40 位元組時,整台伺服器約 6.4Gbps,每位接收者約 6.4Mbps。把可見人數限制在 150 人時,整體約 1Gbps,每人約 1Mbps。
圖表上 隨人數/負載上升 · 伺服器傳送的封包數與位元組數、聚集在同一處的人數
查看位置 把 sar -n DEV 1 的 txpck/s、txkB/s(伺服器 NIC 每秒送出的封包數、KB)與人數圖表一起看。雲端執行個體則看 ethtool -S 的超過上限計數器(AWS ENA 為 bw_out_allowance_exceeded、pps_allowance_exceeded) 符合的跡象 聚集人數增加時,傳送的封包數與位元組數比人數增加得更陡(接近平方),從碰到上限的時間點起,超過上限計數器或傳送丟棄數增加 不符合的跡象 傳送量不變、只有 tick 時間增加時,問題在視野計算或遊戲邏輯 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 CCP Games 2014: EVE Online HED-GP 大規模艦隊戰的伺服器過載
出處 5 筆
單執行緒區域過載(熱點) Single-threaded hot zone
ID sp-hotzone · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
在每個區域由一個執行緒負責的架構中,人潮擠到同一處時,只有那一個核心會到 100%。
為什麼 一個區域(頻道)由一個執行緒負責 → 於是 人潮擠到同一處時只有那個核心飽和,其餘核心還有餘裕 → 畫面上 只有那個區域 lag,其他區域正常
症狀 慢動作 , 輸入延遲
因素 停滯
誰會遇到 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 分散到多個頻道、區域內部平行化、設定人數上限。
基礎設施團隊要做的事 把各核心的 CPU 使用率加入監控與警示(單一核心的飽和會被整台伺服器的平均值掩蓋)。
數值參考 在 16 核心的伺服器上,即使一個核心達到 100%,整台伺服器的 CPU 使用率看起來也只有約 6%。要看各核心的使用率才找得到。
圖表上 隨人數/負載上升 · 各核心的 CPU 使用率、各執行緒的 CPU
查看位置 用 mpstat -P ALL 1 看各核心的使用率、用 pidstat -t 1 看遊戲處理程序各執行緒的 CPU,並與最忙的執行緒所負責 zone 的人數比較 符合的跡象 整台伺服器的 CPU 很低,只有一個執行緒(一個核心)貼近 100%,而當時該執行緒負責的 zone 擠滿了人 不符合的跡象 多個核心平均偏高時是整台伺服器過載。只有一個核心的 %soft(接收處理)偏高時,是「NIC 中斷集中在單一核心」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 其他區域正常,前提是每個區域各自執行 tick。如果各區域的執行緒每個 tick 都要互相等待、再一起進入下一個 tick,最忙的那個區域就會拖慢整台伺服器的 tick。
實際案例 CCP Games 2014: EVE Online HED-GP 大規模艦隊戰的伺服器過載
出處 3 筆
鎖競爭 Lock contention
ID sp-lock · 主要負責 遊戲開發團隊(伺服器開發)
多個執行緒為了寫入同一份資料而等待同一個鎖時,執行緒再多也只能一次執行一個。
為什麼 拍賣場、公會倉庫這類共用資料由多個執行緒同時使用 → 於是 拿到鎖的執行緒完成之前,其餘執行緒都在等待 → 畫面上 只有特定功能變慢,嚴重時整個 tick 延遲
症狀 輸入延遲 , 定格
因素 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把鎖切得更細、減少在鎖內做的事、改用訊息導向的架構(每份資料指定負責的執行緒,其他執行緒只透過訊息送出請求)。
數值參考 鎖內的工作占整體的 20% 時,執行緒再怎麼增加,處理量最多也只有單一執行緒的 5 倍;占 40% 時停在 2.5 倍。
圖表上 隨人數/負載上升 · 請求處理時間、各執行緒的 CPU 與 context switch
查看位置 用 pidstat -w -t 1 看各執行緒的自願 context switch(cswch/s,為等待資源而停下的次數),用 bcc offcputime -p 看執行緒離開 CPU 後在哪裡等待(各呼叫堆疊的等待時間)。.NET 則看 dotnet-counters 的鎖競爭次數(.NET 9 以後為 dotnet.monitor.lock_contentions,8 以前為 Monitor Lock Contention Count) 符合的跡象 負載增加時 CPU 使用率仍維持在低檔,處理時間卻變長;大部分等待時間集中在嘗試取得鎖的呼叫堆疊,鎖競爭次數也一起上升 不符合的跡象 CPU 滿載時是運算量問題(超出 tick 預算、單執行緒區域過載)。等待的地方是 DB 或檔案呼叫時,是遊戲執行緒上的同步呼叫 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 這發生在多個執行緒共同修改遊戲資料的架構中。每個區域或功能由一個執行緒負責、只透過訊息溝通的架構幾乎沒有鎖,但要留意工作集中在單一執行緒的問題(單執行緒區域過載)。遊戲執行緒若在等待緩慢的存檔作業所持有的鎖,那整個 tick 都會停住。
實際案例 Roblox 2021: Roblox 73 小時事故:服務探索(Consul)叢集的資源競爭
出處 6 筆
死結 Deadlock
ID sp-deadlock · 主要負責 遊戲開發團隊(伺服器開發)
兩個執行緒各自等待對方持有的鎖時,就會永遠停住。
為什麼 執行緒 A 持有鎖 1 並等待鎖 2,B 持有鎖 2 並等待鎖 1 → 於是 兩者都永遠停住,相關的執行緒也接連停住 → 畫面上 整台伺服器停止運作,看門狗(watchdog)重新啟動時所有人斷線
症狀 定格 , 斷線
因素 停滯
誰會遇到 整個伺服器, 只有特定功能
何時 偶爾隨機發生, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 制定取鎖順序規則、使用有逾時的鎖、加入看門狗並在停住的瞬間留下 thread dump。
圖表上 連線同時大量中斷 · 連線數、伺服器傳送量
查看位置 停住期間擷取所有執行緒的呼叫堆疊。JVM 用 jstack(會自動找出並標示死結),.NET 用 dotnet-stack,原生伺服器用 gdb 的 thread apply all bt,或先用 gcore 擷取 core 檔案,重新啟動後再分析 符合的跡象 兩個以上的執行緒停在等待對方所持有鎖的堆疊上,這段期間處理程序的 CPU 使用率接近 0 不符合的跡象 停住期間有一個執行緒以 CPU 100% 在跑時是無窮迴圈。執行緒都在等 DB 或外部回應時,是同步呼叫或執行緒池耗盡 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 6 筆
遊戲執行緒上的同步呼叫 Synchronous DB / file I/O on the game loop
ID sp-sync-call · 主要負責 遊戲開發團隊(伺服器開發)
在 tick 進行中等待 DB 回應或檔案寫入時,伺服器上整個遊戲進行就會停住同樣長的時間。
為什麼 在 tick 內等待 DB 查詢與儲存、log 寫入、外部 API 呼叫 → 於是 DB 花 100ms,tick 也停住 100ms → 畫面上 每當 DB 或磁碟變慢,整個野外就頓一下
症狀 定格 , 卡頓
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 做特定動作時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把慢的工作(DB 查詢與儲存、log 寫入、外部 API 呼叫)全部改成非同步,結果在下一個 tick 反映(只設逾時的話,等待期間仍會停住)。
數值參考 即使同一資料中心內的 DB 往返只要 0.5ms,一個 tick 呼叫 100 次就是 50ms,單靠這一項就用光 20 tick 的預算。
圖表上 偶爾隨機飆高 · 伺服器 tick 時間、DB 查詢延遲
查看位置 把 tick 時間圖表與 DB 查詢延遲(slow query log 等)、磁碟延遲放在同一條時間軸上看。沒有 tick 指標時,用 bcc offcputime -p 看遊戲執行緒在哪裡等待 符合的跡象 tick 飆高的時間點與 DB、檔案延遲飆高的時間點重疊,遊戲執行緒的等待時間集中在接收 DB 回應、寫入檔案的呼叫堆疊 不符合的跡象 DB 與磁碟延遲平穩、tick 卻飆高時,是 GC 暫停或鎖競爭 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
訊息佇列積壓 Mailbox / job queue backlog
ID sp-queue · 主要負責 遊戲開發團隊(伺服器開發)
請求進來的速度比處理速度快而在佇列中累積時,排在後面的請求要幾秒後才會處理,或被丟棄。
為什麼 請求抵達的速度比處理速度快 → 於是 佇列變長,超過上限就丟棄 → 畫面上 技能、交易反應變慢或被吃掉
症狀 輸入延遲 , 吃指令/回檔
因素 延遲, 遺失
誰會遇到 特定地點/頻道, 只有特定功能
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 監控佇列長度、採用優先丟棄舊請求的策略、平行化處理。
圖表上 碰到上限後持平 · 佇列長度與最舊訊息的停留時間、每秒處理數
查看位置 伺服器記錄的各佇列長度、最舊訊息的停留時間,以及每秒進入數、處理數、丟棄數。沒有程式碼指標時,用 ss(或 netstat)看遊戲 socket 的 Recv-Q(kernel 已收下但處理程序尚未讀取的量) 符合的跡象 進入數超過處理數的期間,處理數卡在某個值上不去,佇列長度、停留時間與丟棄數持續增加 不符合的跡象 佇列很短、停留時間也很短,反應卻很慢時,是線路延遲或 tick 本身的延遲 確認方式 需要遊戲伺服器/用戶端的 log 與指標
實際案例 CCP Games 2014: EVE Online HED-GP 大規模艦隊戰的伺服器過載
出處 4 筆
計時器集中同時觸發 Synchronized timers
ID sp-timer-burst · 主要負責 遊戲開發團隊(伺服器開發)
所有怪物重生、所有 buff 到期、整點獎勵都擠在同一個 tick 時,那一個 tick 的負擔會變成平常的數十倍。
為什麼 重生、到期、獎勵、自動存檔的計時器都設在同一時刻 → 於是 那一個 tick 的工作量是平常的數十倍 → 畫面上 每到固定時刻就頓一下
症狀 定格 , 卡頓
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 固定週期
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 讓計時器時刻隨機錯開一些,並分散到多個 tick 處理。
圖表上 固定週期飆高 · 伺服器 tick 時間
查看位置 收集 tick 時間飆高的時間點並看其間隔(整點、每 5 分鐘等)。與同一時刻執行的重生、buff 到期、獎勵、自動存檔計時器清單對照 符合的跡象 tick 每次都在相同時刻或以相同間隔飆高,且那個時刻有同時觸發的遊戲計時器工作 不符合的跡象 有週期性,但與 GC log 的暫停時間點或伺服器 cron、備份的時間重疊時,是伺服器 GC 全面暫停或排程工作 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 1 筆
尋路運算暴增 Pathfinding storms
ID sp-pathfinding · 主要負責 遊戲開發團隊(伺服器開發)
數百隻怪物同時追擊玩家並計算路徑時,會耗用大量 CPU。
為什麼 拉一大群怪或大量生成時,許多怪物同時追擊玩家 → 於是 每隻怪物各自計算尋路 → 畫面上 只有那個練功區出現慢動作
症狀 慢動作
因素 停滯
誰會遇到 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 快取路徑、限制計算次數上限、分散到多個 tick 處理。
圖表上 隨人數/負載上升 · 伺服器 tick 時間、各 zone 的怪物數
查看位置 各 zone 正在追擊玩家的怪物數與 tick 時間。沒有另外計數時,用 perf top -p 看遊戲處理程序各函式的 CPU 占比 符合的跡象 拉一大群怪或大量生成時 tick 時間增加,尋路(路徑搜尋)函式占了很大比例的 CPU 時間 不符合的跡象 怪物少、只有玩家多時 tick 增加,是視野計算或廣播 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
序列化與壓縮的成本 Serialization / compression cost
ID sp-serialize · 主要負責 遊戲開發團隊(伺服器開發)
把要送出的資料轉成位元組並壓縮也要耗用 CPU,人多時這項成本會暴增。
為什麼 每筆狀態更新都要把結構轉成位元組並壓縮 → 於是 成本與人數的平方成正比增加 → 畫面上 傳送變慢,出現輸入延遲
症狀 輸入延遲
因素 停滯, 延遲
誰會遇到 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把做好一次的封包重複用於多人、改用輕量格式。
圖表上 隨人數/負載上升 · 伺服器 CPU 使用率、產生封包的執行緒的 CPU
查看位置 用 perf top -p 看遊戲處理程序的 CPU 時間中,序列化、壓縮、加密函式(包含 zlib、LZ4、OpenSSL 等函式庫的函式)所占的比例,並比較人少與人多時的差異 符合的跡象 人越多,序列化、壓縮、加密函式的占比越大,產生封包的執行緒 CPU 最先飽和 不符合的跡象 這些函式的占比很小時,問題在視野計算或遊戲邏輯 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 如果連線會加密封包(TLS、DTLS 等),加密與解密也要耗用 CPU。加密是每條連線分別進行,所以即使把做好一次的封包重複用於多人,加密成本仍與接收人數成正比。AES-GCM 這類對稱加密快到一個核心每秒能處理數 GB,平時占比很小,但速度會隨一次加密的單位(record)大小而有很大差異,像遊戲這樣小封包很多時,每位元組的成本就會變高。每次連線進行一次的交握(handshake)中,伺服器要用憑證金鑰簽章並計算金鑰交換(ECDHE)。一個核心每秒的簽章次數約 1,100 次(RSA 2048)到 1 萬 8 千次(ECDSA P-256),金鑰交換約 9 千次,登入湧入時會形成負擔。
出處 4 筆
伺服器當機 Server process crash
ID sp-crash · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
伺服器處理程序因未處理的錯誤而終止時,該伺服器上所有人會同時斷線。
為什麼 指向不存在對象的錯誤(null 參照)、錯誤的資料、記憶體不足等致命錯誤 → 於是 伺服器(或 zone)處理程序結束 → 畫面上 所有人同時斷線,上次存檔後的進度可能回檔
症狀 斷線 , 吃指令/回檔
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 偶爾隨機發生, 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 分析 crash dump 並修正原因、提高存檔頻率。
基礎設施團隊要做的事 處理程序自動重新啟動、建置 crash dump 的收集與保存環境、伺服器停機時立即警示。
圖表上 連線同時大量中斷 · 連線數、處理程序重新啟動次數
查看位置 coredumpctl list 的 core dump 紀錄(時間、PID、終止訊號)與服務管理器(systemd)的異常結束、重新啟動紀錄。Windows 伺服器則看 WER 留下的 dump 檔案 符合的跡象 連線數瞬間掉到接近 0 的時間點,遊戲伺服器處理程序有異常結束與 core dump 不符合的跡象 處理程序一直存活、連線卻中斷時,是網路設備或閒置逾時。若是長時間停住後由看門狗重新啟動的紀錄,是無窮迴圈或死結 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
執行緒池耗盡 Thread pool starvation
ID sp-threadpool · 主要負責 遊戲開發團隊(伺服器開發)
負責處理工作的工作執行緒全被慢的工作綁住時,新請求只能無止盡地等待。
為什麼 工作執行緒都被綁在等待外部 API 或 DB 回應上 → 於是 沒有執行緒可以接新請求 → 畫面上 登入、商城等特定功能出現無限讀取
症狀 連不上/無限讀取 , 輸入延遲 , 定格
因素 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 人潮湧入時, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 為慢的呼叫設逾時、依功能分開執行緒池、改為非同步。
圖表上 碰到上限後持平 · 執行緒池的執行緒數與佇列長度、請求處理時間
查看位置 .NET 看 dotnet-counters monitor 的執行緒池執行緒數與佇列長度(.NET 9 以後為 dotnet.thread_pool.thread.count、dotnet.thread_pool.queue.length,8 以前為 ThreadPool Thread Count、ThreadPool Queue Length),並用 dotnet-stack 確認工作執行緒在哪裡等待。JVM 與原生伺服器則用 thread dump 確認同樣的內容 符合的跡象 CPU 使用率遠低於 100%,執行緒數卻緩慢持續增加或卡在上限,佇列不斷累積,大部分 worker 都在等同一個外部呼叫(DB、HTTP)的回應 不符合的跡象 佇列是空的卻仍然很慢時,是被呼叫的對象本身慢,要查連鎖故障或依賴外部服務 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 若封包接收與遊戲邏輯共用同一個工作執行緒池,只要幾個慢的工作占滿所有 worker,整台伺服器的封包處理就會停住。
實際案例 Riot Games 2021: League of Legends EUW 5 小時事故:一個附屬 DB 讓整個伺服器停擺
出處 5 筆 Debug ThreadPool Starvation Microsoft 池中沒有剩餘執行緒、新工作只能等待時,回應就會變慢,原因是占住執行緒的阻塞程式碼。在 dotnet-counters 中,CPU 遠低於 100%,dotnet.thread_pool.thread.count 卻緩慢持續增加,就是耗盡的訊號(dotnet.thread_pool.queue.length 通常也很大);用 dotnet-stack 確認執行緒等待的位置 Avoiding insurmountable queue backlogs AWS 同時處理數 = 抵達率 × 延遲(利特爾法則,Little's law)。每秒 100 筆時,延遲從 100ms 增加到 10 秒,執行緒就從 10 個增加到 1,000 個,池因此耗盡 Bulkhead Pattern Microsoft Azure 為每個被呼叫的對象分別建立連線池與執行緒池,一個對象故障時只會卡住它自己的池 .NET runtime metrics .NET dotnet.thread_pool.thread.count(執行緒池執行緒數)、dotnet.thread_pool.queue.length(等待中的工作數)自 .NET 9 起提供 Well-known EventCounters in .NET Microsoft .NET 8 以前的 ThreadPool Thread Count(threadpool-thread-count)、ThreadPool Queue Length(threadpool-queue-length)
無窮迴圈、邏輯失控 Infinite loop / runaway logic
ID sp-infinite-loop · 主要負責 遊戲開發團隊(伺服器開發)
因 bug 導致一個 tick 結束不了時,伺服器就會停住,看門狗會強制重新啟動。
為什麼 條件寫錯導致迴圈結束不了,或遞迴失控 → 於是 tick 結束不了,伺服器停止 → 畫面上 定格後所有人斷線
症狀 定格 , 斷線
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 做特定動作時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 設定迴圈次數上限、看門狗、撰寫重現問題輸入的測試。
圖表上 連線同時大量中斷 · 連線數、各執行緒的 CPU
查看位置 停住期間用 pidstat -t 1 看各執行緒的 CPU,並用 perf top -t(執行緒 ID)或 gdb 確認以 100% 在跑的執行緒卡在哪個函式。已經重新啟動時,看看門狗逾時紀錄(systemd 的 WatchdogSec、Kubernetes liveness probe 失敗) 符合的跡象 伺服器停住期間,一個遊戲執行緒 CPU 貼在 100%,堆疊一直在同一個函式或迴圈內打轉 不符合的跡象 停住期間 CPU 接近 0 時,是死結或在等外部回應 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
集中在單一目標的戰鬥(世界王) Hot entity / combat event fan-out
ID sp-hot-entity · 主要負責 遊戲開發團隊(伺服器開發)
數百人同時攻擊同一隻王時,這隻王的運算全集中在一處,打擊資訊也要傳送給所有看得到的人。
為什麼 數百人不停地對同一隻王施放技能、buff、debuff → 於是 王的血量、仇恨列表、debuff 計算集中在一處,每次打擊都要把傷害數字與特效封包傳送給所有看得到的人 → 畫面上 技能延遲命中,傷害數字一口氣跳出來,只有王的周圍出現慢動作
症狀 輸入延遲 , 快轉 , 慢動作
因素 停滯, 延遲
誰會遇到 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 其他玩家的傷害數字與特效合併或省略、限制單一目標身上的 debuff 數量上限、把打擊處理分散到多個 tick。
數值參考 800 人每秒各打 2 下,就是每秒 1,600 次打擊。全部通知給看著的 800 人,就是每秒 128 萬則訊息。
圖表上 隨人數/負載上升 · 伺服器 tick 時間、傳送訊息數
查看位置 把打王時段的 tick 時間與傳送封包數,和王周圍的人數一起看;可以的話再看各目標每秒的事件數(打擊、buff、debuff) 符合的跡象 王周圍的人數增加時,tick 時間與傳送量急遽上升,這隻王每秒的事件數是其他目標的數十倍 不符合的跡象 與王無關,只要人聚在一處就同樣變慢時,是視野計算或廣播量暴增 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 1 筆
進入密集區域時的生成暴增 Spawn burst when entering a crowd
ID sp-spawn-burst · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
用傳送移動到擠滿人的城鎮時,伺服器必須一次送出數百位新進入視野者的外觀、裝備與狀態。
為什麼 因傳送移動、登入或切換頻道,突然出現在人多的地方 → 於是 伺服器一次產生並送出數百人份的完整資訊,自己的電腦也要一次載入 → 畫面上 剛抵達時畫面短暫停住,角色一個一個慢慢出現,輸入也有延遲
症狀 定格 , 輸入延遲 , 快轉
因素 停滯, 延遲
誰會遇到 只有我, 特定地點/頻道
何時 移動中/切換地圖時, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:依距離由近到遠分成多個 tick 送出、快取外觀資訊。用戶端:在讀取畫面期間預先接收,把收到的角色分散到多個畫格生成。
數值參考 一個人的外觀、裝備、buff 資訊若為 300 位元組,500 人就約 150KB。相當於平常一個 tick 傳送量(數 KB)的數十倍在一瞬間湧入。
圖表上 剛開服或維護結束後暴增 · 每條連線的傳送位元組數、用戶端畫格時間
查看位置 抵達人多的地方後幾秒內,透過該連線送出的位元組數與封包數(伺服器 log),以及用戶端畫格時間(net graph、用戶端 log) 符合的跡象 剛抵達時該連線的傳送量衝到平常一個 tick 的數十倍後回落,同一時間用戶端畫格時間也飆高 不符合的跡象 移動到人少的地方也一樣停住時,是切換 zone(跨伺服器轉移)或用戶端載入 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
物件累積(未清理的道具、召喚物) Entity / timer buildup over uptime
ID sp-entity-buildup · 主要負責 遊戲開發團隊(伺服器開發)
該消失的地上道具、召喚物、已結束的計時器沒有清理而不斷累積時,伺服器開得越久,每個 tick 要做的事就越多。
為什麼 地上道具、召喚物、已到期的計時器、空隊伍資訊沒有及時刪除 → 於是 每個 tick 要走訪的清單一天比一天長 → 畫面上 維護剛結束時正常,過了幾天後只有那台伺服器或那個區域越來越遲鈍
症狀 慢動作 , 卡頓 , 輸入延遲
因素 停滯
誰會遇到 整個伺服器, 特定地點/頻道
何時 開越久越嚴重
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把各區域的物件數記錄為指標並觀察趨勢、為每種物件設定存活時間與數量上限、定期清理。
數值參考 每個 tick 都把所有物件走訪一遍的伺服器,物件數變成 2 倍時,那部分的 tick 時間也會變成 2 倍。
圖表上 緩慢爬升後驟降 · 各 zone 的物件數、伺服器 tick 時間
查看位置 以比維護週期更長的期間(幾週)看各 zone/伺服器的物件數(地上道具、召喚物、計時器)與 tick 時間 符合的跡象 物件數與 tick 時間在維護後從低點開始逐日上升,到維護或重新啟動時驟降,反覆發生,這段期間記憶體仍很充足 不符合的跡象 tick 不變、只有記憶體持續上升時,是記憶體洩漏 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 和記憶體洩漏一樣開越久越嚴重,差別在於記憶體還很充足,只有 tick 時間增加。物件數圖表隨每次維護週期呈鋸齒狀時,就是這個情況。
出處 2 筆
更新改變了流量模式 Patch changes traffic pattern
ID sp-patch-traffic · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(網路基礎設施)
新內容、特效、同步項目讓封包變大、變頻繁時,原本運作正常的伺服器在更新後就會碰到 MTU、頻寬、封包數上限。
為什麼 更新增加了新的技能特效、同步項目、道具資訊,封包變大或變頻繁 → 於是 大封包超過 MTU 而被分段,增加的流量碰到頻寬、雲端 PPS 上限與傳送緩衝區的限制 → 畫面上 更新後人多的地方開始出現瞬移、技能被吃、輸入延遲。基礎設施沒有任何變更,封包遺失卻增加
症狀 瞬移 , 吃指令/回檔 , 輸入延遲
因素 遺失, 延遲
誰會遇到 整個伺服器, 特定地點/頻道, 特定地區/電信業者
何時 人潮湧入時, 晚間尖峰時段, 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 自行把封包切成 1,200 位元組以下;新的同步項目只送變更部分,並依距離與重要程度降低頻率;部署前在測試伺服器上將每位玩家每秒的封包數、位元組數與最大封包大小和前一個 build 比較;在流量指標中記錄 build 版本。
基礎設施團隊要做的事 伺服器設備/OS:在圖表上標示部署時間,比較部署前後每位玩家每秒的封包數、位元組數與平均封包大小;為執行個體的超過上限計數器設警示;必要時改用更大的執行個體。網路:檢查防火牆、負載平衡器、DDoS 防護設備的處理上限,以及是否會阻擋分段。
數值參考 UDP 封包在 1,200 位元組以下比較安全;網際網路的路徑 MTU 通常是 1,500 位元組,經過通道時更小(GRE 通道為 1,476 位元組)。超過路徑 MTU 的封包會被分段或丟棄,而分段的封包只要遺失一個分段就整個遺失。每位玩家每秒的封包數增加 20%,整台伺服器也會增加 20%,原本就接近上限的執行個體會立刻超出。
圖表上 從某個時間點起階梯式上升 · 每位玩家每秒的封包數與位元組數、平均封包大小
查看位置 把部署前後伺服器 NIC 每秒的封包數與位元組數(sar -n DEV 的 rxpck/s、txpck/s、rxkB/s、txkB/s,EC2 為 NetworkPacketsOut、NetworkOut)除以同時上線人數後比較。平均封包大小為位元組數 ÷ 封包數,大小分布則用 Wireshark 的 Packet Lengths 統計分析封包擷取 符合的跡象 部署後每位玩家的封包數、位元組數或平均封包大小階梯式上升並維持在高檔,同一時間起伺服器產生的分段數(sar -n IP 的 fragcrt/s)或執行個體超過上限計數器(AWS ENA 的 pps_allowance_exceeded、bw_out_allowance_exceeded)增加 不符合的跡象 部署前後流量模式相同,只有延遲與封包遺失增加時,要查同一時間的基礎設施變更(設定、路由、設備、OS/kernel 更新) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 收到「更新前都很正常」的回報時,這是要和基礎設施變更一起優先確認的遊戲端原因。即使更新說明裡沒有網路方面的變更,一個新特效或同步項目在人多的地方也會被乘上數百人份。增加的流量實際卡在哪裡,在「UDP 封包的 IP 分段」、「超過雲端 PPS 上限」、「NIC 頻寬飽和」、「Kernel socket 緩衝區不足」、「中間設備超過處理上限(防火牆、IPS、DDoS 防護)」等項目中說明。本項目處理的是讓流量碰到這些上限的起點為遊戲更新的情況,所以在提高上限之前,要先減少更新所增加的流量。如果同一時間也更新了 OS 或 kernel,就以每位玩家的流量是否改變,來和「OS、kernel、驅動程式、韌體更新後的效能變化」區分。
出處 7 筆
L10 記憶體
9 個原因 · 完整版章節
伺服器 GC 全面暫停 Stop-the-world GC pause
ID mem-gc · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
Java、C# 伺服器為了回收垃圾而暫停所有執行緒(stop-the-world)的期間,整個伺服器都會停住。
為什麼 heap 滿了,開始 GC → 於是 暫停所有遊戲執行緒進行回收(存活資料越多,暫停越久) → 畫面上 伺服器上的所有人同時定格,接著出現快轉
症狀 定格 , 快轉
因素 停滯
誰會遇到 整個伺服器
何時 固定週期, 開越久越嚴重
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 在啟動選項中明確指定暫停較短的 GC(ZGC、Shenandoah、調低暫停目標的 G1)、減少記憶體配置、調整 heap 大小。
基礎設施團隊要做的事 選用記憶體足以讓 heap 保有充裕空間的執行個體;容器至少配置 2 個 CPU 與約 1.8GB 記憶體(JDK 26 以下若低於此值,會預設選用 Serial GC);監控 GC 暫停時間。
數值參考 只回收新物件(Young 區)的 Minor GC 約需數~數十 ms。回收整個 heap(存活資料達數 GB)的 Full GC 有時會超過 1 秒。ZGC 的暫停幾乎與 heap 大小無關,不到 1ms;Shenandoah 的暫停也不會隨 heap 大小成比例增加,因此同樣很短。
圖表上 固定週期飆高 · 伺服器 tick 時間、GC 暫停時間
查看位置 開啟 GC log,把暫停的時間點與長度疊在伺服器 tick 時間圖表上。Java 看啟動選項 -Xlog:gc*(JDK 8 以下為 -XX:+PrintGCDetails)輸出的 Pause 行;.NET 看 dotnet-counters 的 GC 暫停指標(.NET 9 以後為 dotnet.gc.pause.time,8 以下為 % Time in GC since last GC);Go 看 GODEBUG=gctrace=1 每次 GC 輸出的一行 符合的跡象 tick 飆高的時間點與 GC 暫停重疊,暫停長度與飆高長度相近。伺服器所有 zone、頻道在同一瞬間飆高 不符合的跡象 GC log 沒有長暫停、tick 仍飆高時,是鎖、同步呼叫、磁碟寫入等其他原因。只有一個 zone 飆高時,是腳本引擎的 GC(mem-script-gc)或該 zone 的負載 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 Java 的 G1 預設單次暫停目標為 200ms,在 20 tick 伺服器上相當於 4 個 tick。容器若只分到不到 2 個 CPU 或不到約 1.8GB 記憶體,JDK 26 以下的 Java 會預設選用以單一執行緒回收的 Serial GC,暫停時間會長得多。C#(.NET)伺服器通常會開啟伺服器 GC 與背景 GC,但存放新物件的第 0、1 代(Gen0、1)回收,以及伴隨壓縮的 Full GC,仍會暫停所有執行緒。Go 的暫停通常不到 1ms,但配置量大時,要求記憶體的一方必須分擔 GC 工作,tick 因此變慢。不論哪種方式,只要配置速度快過回收速度,遊戲執行緒最後都會停住。G1 會轉為 Full GC,ZGC 則會讓要求記憶體的執行緒停住,直到回收結束。
實際案例 Riot Games 2021: League of Legends EUW 5 小時事故:一個附屬 DB 讓整個伺服器停擺
出處 10 筆
腳本引擎的 GC 暫停 Scripting VM GC (Lua, etc.)
ID mem-script-gc · 主要負責 遊戲開發團隊(伺服器開發)
即使是 C++ 伺服器,只要任務、AI、技能是用 Lua 等腳本執行,腳本引擎進行 GC 的期間,該 zone 就會停住。
為什麼 每個 zone 的腳本引擎執行任務、AI、事件時,大量產生暫時物件 → 於是 腳本引擎的 GC 一次回收大量物件時,該 zone 的 tick 會停住 → 畫面上 只在特定 zone 或特定活動期間週期性地頓一下
症狀 卡頓 , 定格
因素 停滯
誰會遇到 特定地點/頻道
何時 人潮湧入時, 固定週期
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 設定漸進式或分代 GC、每個 tick 只推進一小段 GC、減少腳本產生的暫時物件。
數值參考 腳本 heap 長到數百 MB 時,一次集中進行的回收(關閉漸進式回收,或分代模式下的完整回收)有時要花數十~數百 ms。
圖表上 固定週期飆高 · 各 zone 的 tick 時間、腳本引擎記憶體
查看位置 每個 tick 記錄各 zone 的 tick 時間與該 zone 腳本引擎的記憶體用量(Lua 用 collectgarbage("count")),疊在同一張圖表上看 符合的跡象 腳本記憶體驟降的瞬間(一次集中回收)與該 zone 的 tick 飆高重疊,其他 zone 正常 不符合的跡象 腳本記憶體沒有變化卻飆高時,是該 zone 的負載或鎖。伺服器所有 zone 同時飆高時,是伺服器 GC(mem-gc)或 swap(mem-swap) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 1 筆 Lua 5.4 Reference Manual Lua.org 漸進式模式把回收拆成小步驟,穿插在程式執行之間(步驟設得太大就會全面暫停);分代模式的 major 回收會走訪所有物件,屬於全面暫停;collectgarbage("count") 回傳 Lua 使用的記憶體總量(KB)
記憶體配置暴增 Allocation storms
ID mem-alloc · 主要負責 遊戲開發團隊(伺服器開發)
活動期間大量產生暫時物件時,GC 執行的頻率會比平常高出許多。
為什麼 道具掉落、戰鬥 log、活動獎勵讓暫時物件暴增 → 於是 GC 頻率增加數倍,還沒來得及變成垃圾的物件被移到 Old 區,Full GC 也跟著提早發生 → 畫面上 只在活動期間週期性地頓一下
症狀 卡頓 , 定格
因素 停滯
誰會遇到 整個伺服器, 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 物件池、可重複使用的緩衝區、記憶體配置剖析(profiling)。
圖表上 隨人數/負載上升 · GC 次數、配置速度
查看位置 用 GC log(Java -Xlog:gc、Go GODEBUG=gctrace=1)計算每分鐘 GC 次數;.NET 看 dotnet-counters 的配置量與 GC 次數(.NET 9 以後為 dotnet.gc.heap.total_allocated、dotnet.gc.collections,8 以下為 Allocation Rate、Gen 0 GC Count)。與同時上線人數、活動時間疊在一起看 符合的跡象 活動開始後,配置速度與 GC 次數增加得比人數還快,短暫的暫停變得頻繁。活動結束後恢復原狀 不符合的跡象 GC 次數不變、單次暫停變長時,是存活資料增加(mem-gc-thrash、mem-leak) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
記憶體洩漏 Memory leak
ID mem-leak · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
沒有釋放的記憶體一點一點累積,幾天後演變成 GC 暴增、swap 或處理程序被強制終止。
為什麼 已登出角色的資料、事件處理常式(event handler)沒有被釋放 → 於是 可用記憶體在幾天內逐漸減少 → 畫面上 維護剛結束時一切正常,之後一天比一天 lag,最後伺服器當機
症狀 慢動作 , 定格 , 斷線
因素 停滯
誰會遇到 整個伺服器
何時 開越久越嚴重, 晚間尖峰時段
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 分析 heap dump、進行長時間負載測試。
基礎設施團隊要做的事 監控各處理程序記憶體用量的趨勢並設定警示。
圖表上 緩慢爬升 · 處理程序記憶體(RSS)、GC 後的 heap
查看位置 以數天為單位觀察遊戲伺服器處理程序的記憶體(pidstat -r 的 RSS);有 GC 的伺服器則看 GC 剛結束時剩下的 heap。Java 看 -Xlog:gc 行中 GC 前後用量裡的 GC 後數值;.NET 看 dotnet-counters 的 GC 後 heap 大小(.NET 9 以後為 dotnet.gc.last_collection.heap.size,8 以下為 GC Heap Size) 符合的跡象 GC 剛結束時剩下的 heap(基線)在重新啟動後每天上升,人少的凌晨也不會降下來 不符合的跡象 heap 基線持平、只有 RSS 上升時,是碎片化(mem-fragment)或原生記憶體(native memory)的問題。隨人數起伏時是正常用量 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 如果每週定期維護都會重新啟動,洩漏就會被掩蓋,很久都不會被發現。常見的情況是某次維護延後,或活動讓人數增加時,問題才突然浮現。
出處 5 筆
ID mem-gc-thrash · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
存活資料逼近 heap 上限時,每次 GC 幾乎回收不到東西,GC 就會不停反覆執行。
為什麼 活動湧入的人潮或記憶體洩漏,讓存活資料逼近 heap 上限 → 於是 GC 只能回收一點點,馬上又進行 Full GC,CPU 大部分都被 GC 占用 → 畫面上 整個伺服器在幾分鐘內反覆出現慢動作與定格,最後因記憶體不足而終止
症狀 慢動作 , 定格 , 斷線
因素 停滯
誰會遇到 整個伺服器
何時 晚間尖峰時段, 人潮湧入時, 開越久越嚴重
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 把 heap 設得比尖峰時的存活資料寬裕(通常 2 倍以上)、減少長期被參考的資料與洩漏。
基礎設施團隊要做的事 設定 GC 時間比例警示;發生時不要硬撐,儘快重新啟動;選用記憶體充裕、可以加大 heap 的執行個體。
數值參考 GC 占用超過 10% 的執行時間,通常就視為危險訊號。Java 的部分 GC 若花了 98% 的時間做 GC 卻幾乎回收不到記憶體,就會丟出記憶體不足錯誤。
圖表上 碰到上限後持平 · GC 後的 heap、GC 時間比例
查看位置 看 GC 剛結束時剩下的 heap 有多接近最大 heap,以及花在 GC 的時間比例。Java 看 -Xlog:gc 行的「GC 後(heap 大小)」與 Pause Full 行出現的頻率;.NET 看 dotnet-counters(.NET 8 以下為 % Time in GC since last GC,.NET 9 以後為 dotnet.gc.pause.time 的增加量);Go 看 GODEBUG=gctrace=1 各行之間的間隔 符合的跡象 GC 剛結束時 heap 仍接近上限,Full GC 接連執行,GC 時間比例明顯高於平常(通常超過 10%)。這段期間整個伺服器的 tick 一起變慢 不符合的跡象 GC 後 heap 仍有餘裕、只有暫停很長時,是 GC 種類或設定的問題(mem-gc) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
Swap Swapping
ID mem-swap · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
記憶體不足、OS 把部分內容移到磁碟後,每次用到那塊記憶體,都得等待慢上 1,000 倍以上的磁碟。
為什麼 使用中的記憶體超過實體 RAM → 於是 OS 把一部分移到磁碟,需要時再讀回來 → 畫面上 tick 暴增到數百 ms,伺服器上所有玩家都遇到慢動作與定格
症狀 慢動作 , 定格
因素 停滯
誰會遇到 整個伺服器
何時 開越久越嚴重, 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 為處理程序的記憶體用量設定上限(heap 大小等),並檢查洩漏。
基礎設施團隊要做的事 將遊戲伺服器設定為不使用 swap,並以記憶體警示因應;關閉 swap 後,記憶體一不足就會被強制終止(OOM),因此要準備比尖峰用量更充裕的 RAM。
數值參考 讀取 RAM 約 100ns,從 SSD 讀回約 100µs(1,000 倍),透過網路存取的雲端磁碟約 1ms(1 萬倍),HDD 則是 10ms(10 萬倍)。
圖表上 緩慢爬升 · swap 用量、swap in/out
查看位置 把 vmstat 1 的 si、so 欄(每秒從 swap 讀回、移出到 swap 的量)、/proc/pressure/memory 的 some、full(因等待記憶體而停住的時間比例)、遊戲伺服器處理程序的 pidstat -r majflt/s(必須從磁碟讀入的分頁錯誤)與 tick 時間疊在一起看 符合的跡象 lag 發生時 si 大於 0,遊戲伺服器的 majflt/s 與 memory 的 full 值一起上升 不符合的跡象 si、so 為 0 且 memory 壓力(PSI)也接近 0 時,原因不在 swap。沒有 swap 但 majflt/s 與 PSI 上升時,代表記憶體耗盡、正在重新讀入程式碼分頁,要先確保有足夠的記憶體 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 使用 GC 的伺服器在回收時會讀遍整個 heap,因此只要 heap 有一部分被 swap 出去,單次 GC 就可能拉長到數秒~數十秒。關閉 swap 後,不會經過因 swap 而變慢的階段,會直接進入強制終止(OOM),所以必須先確保有足夠的可用記憶體。即使沒有 swap,記憶體快用完時,OS 也會把執行檔的程式碼分頁移出記憶體再重新讀入,因此在被強制終止前,整個伺服器可能會有一段時間嚴重變慢。
出處 8 筆
快取未命中 CPU cache misses
ID mem-cache-miss · 主要負責 遊戲開發團隊(伺服器開發)
資料散落在記憶體各處時,CPU 每次都必須到較慢的 RAM 讀取並等待資料。
為什麼 物件透過指標散落各處,存取順序雜亂 → 於是 CPU 快取裡沒有,每次都要從 RAM 讀取(慢 100 倍左右) → 畫面上 做同樣的事,tick 成本卻高出數倍,嚴重時出現慢動作
症狀 慢動作
因素 停滯
誰會遇到 整個伺服器
何時 一直都有, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把經常一起使用的資料連續排列(資料導向設計)。
圖表上 一開始就一直偏高 · tick 時間、CPU 使用率
查看位置 對遊戲伺服器處理程序執行 perf stat -d -p PID,量測每週期指令數(insn per cycle)與 L1、LLC 快取未命中,並與 tick 時間、CPU 使用率一起看 符合的跡象 CPU 一直很忙,但 insn per cycle 偏低、LLC 未命中很多。改變資料布局的 build 在相同人數下 tick 時間大幅縮短,即可確定 不符合的跡象 CPU 使用率低但 tick 很慢時,是鎖、I/O 等待這類在 CPU 之外等待的原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 2 筆
記憶體碎片化 Heap fragmentation
ID mem-fragment · 主要負責 遊戲開發團隊(伺服器開發)
反覆配置與釋放,讓閒置空間被切得零碎時,占用的記憶體會遠多於實際使用量。
為什麼 多個執行緒長時間配置、釋放大小不一的記憶體 → 於是 閒置空間零散分布,無法歸還給 OS,用量像洩漏一樣持續增加 → 畫面上 開越久越會因 swap 與記憶體不足而變慢,最後被強制終止
症狀 慢動作 , 斷線
因素 停滯
誰會遇到 整個伺服器
何時 開越久越嚴重
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 依大小分類的記憶體池、不易碎片化的記憶體配置器(jemalloc、mimalloc 等)。
圖表上 緩慢爬升 · 處理程序記憶體(RSS)
查看位置 用同一個 build 啟動兩台伺服器,只在其中一台以環境變數 MALLOC_ARENA_MAX 減少 glibc arena 數量,或換成 jemalloc 等其他配置器,比較數天內 pidstat -r 的 RSS 符合的跡象 人數與物件數相近,只有調整過的伺服器 RSS 停止增加或增幅大減 不符合的跡象 換了配置器仍同樣上升時,是沒有釋放的記憶體(mem-leak) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 表現和洩漏一模一樣,但分析 heap 找不到洩漏點。Linux 的預設配置器(glibc)在執行緒多的伺服器上特別嚴重,有時光是換掉配置器,用量就會大幅下降。
出處 3 筆
ID mem-numa · 主要負責 基礎設施團隊(伺服器基礎設施)
在有兩顆 CPU 的伺服器上,使用接在另一顆 CPU 上的記憶體時,存取會變慢。
為什麼 執行緒與記憶體位於不同的 CPU 插槽(socket) → 於是 記憶體存取變慢(依設備不同,約慢 1.5~2 倍) → 畫面上 規格相同,各處理程序的效能卻有落差
症狀 慢動作
因素 停滯
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 把處理程序與記憶體綁定在同一個插槽(numactl);有兩個插槽時,每個插槽各自執行遊戲伺服器處理程序。
圖表上 只有部分偏高 · 各處理程序的 tick 時間、各節點的記憶體
查看位置 用 numastat -p PID 查看遊戲伺服器處理程序的記憶體位於哪個 NUMA 節點、numastat 的 numa_miss、other_node 是否增加,並與該處理程序執行所在 CPU 的節點比較 符合的跡象 只有慢的處理程序大部分記憶體位於與其執行 CPU 不同的節點,用 numactl 把 CPU 與記憶體綁定在同一節點重新啟動後,差距消失 不符合的跡象 節點分布與快的處理程序相同卻仍然慢時,是 noisy neighbor、CPU 節流、該處理程序本身的負載等其他原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
L11 磁碟
9 個原因 · 完整版章節
同步寫入 log Synchronous logging
ID dk-sync-log · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲執行緒每寫一行 log 都要等磁碟寫完的話,磁碟一忙,遊戲進行也會跟著停住。
為什麼 在遊戲執行緒上直接把戰鬥、交易 log 寫入檔案 → 於是 要求確實寫入(fsync),或 OS 的寫入緩衝區(頁面快取)達到上限時,磁碟一忙,一次寫入就要數十 ms → 畫面上 log 量大的戰鬥中會頓一下
症狀 卡頓 , 定格
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 改用非同步 log(記憶體緩衝區 + 獨立執行緒)、減少 log 量、不在遊戲執行緒上呼叫 fsync。
基礎設施團隊要做的事 以較低的 I/O 優先順序執行 log 輪替(rotation)與壓縮、把 log 放在與資料不同的磁碟、監控磁碟寫入延遲。
圖表上 偶爾隨機飆高 · 伺服器 tick 時間、磁碟寫入延遲
查看位置 把 iostat -x 1 的 w_await、aqu-sz 與 tick 時間疊在一起看,再用 perf trace -p PID --duration 10 找出遊戲伺服器中耗時超過 10ms 的 write、fsync 呼叫及其執行緒 符合的跡象 tick 飆高的時間點,遊戲執行緒的 write、fsync 呼叫耗時數十 ms,同一時刻磁碟寫入延遲也往上衝。常與 log 輪替、壓縮的時間重疊 不符合的跡象 遊戲執行緒上沒有耗時很久的系統呼叫、tick 卻飆高時,是 GC、鎖、超出 tick 預算等其他原因。只有 log 專用執行緒耗時很久時,不影響遊戲進行 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 OS 通常會先把寫入的資料收進記憶體(頁面快取),之後再寫回磁碟,所以寫一行 log 大多會立刻完成。會停住的情況有三種:用 fsync 要求確實寫入時、積壓的寫入超過上限而使 OS 阻塞(block)寫入呼叫時、輪替或壓縮 log 檔時。因此平常一切正常,只在磁碟忙碌的瞬間飆高。
出處 5 筆
ID dk-fsync · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(DB 基礎設施)
要求把資料「確實」寫入磁碟時,依磁碟不同,每次需要 0.1ms~數十 ms;請求一多,佇列就會變長。
為什麼 定期存檔、登出潮使確實寫入的請求大量湧入 → 於是 磁碟佇列變長 → 畫面上 每到存檔時間就 lag,登出、切換頻道變慢
症狀 卡頓 , 輸入延遲
因素 停滯, 延遲
誰會遇到 整個伺服器
何時 固定週期, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 把多次存檔合併成一次(多筆存檔只呼叫一次 fsync)、分散存檔時間。
基礎設施團隊要做的事 伺服器設備/OS:採用具斷電保護的伺服器用 SSD,監控磁碟佇列長度與 fsync 延遲。DB 設備:存檔寫入 DB 時,DB 的 log 磁碟也換成同類 SSD,並監控 commit 延遲。
數值參考 每次所需時間依設備而異,大致是:伺服器用 SSD(具斷電保護)0.1ms、一般 SSD 1~數 ms、雲端磁碟 1~2ms、HDD 10ms 以上。由單一執行緒一個一個等待的話,HDD 每秒連 100 次都做不到。
圖表上 固定週期飆高 · 磁碟佇列長度、flush 與寫入延遲
查看位置 把 iostat -x 1 的 f/s、f_await(磁碟處理的 flush 次數與耗時)以及 w/s、aqu-sz、w_await,與定期存檔、登出的時間疊在一起看。舊版 sysstat 把 aqu-sz 顯示為 avgqu-sz。雲端磁碟則看 EBS 的 VolumeQueueLength、VolumeAvgWriteLatency 符合的跡象 每到存檔時間或登出潮,flush 次數與佇列長度一起往上衝,w_await、f_await 變成平常的好幾倍。此時存檔、切換頻道變慢 不符合的跡象 在與存檔、登出無關的時間佇列往上衝時,是備份、壓縮(dk-backup)或 IOPS 上限(dk-iops)。flush 次數不變卻變慢時,是 burst credit 耗盡的問題(dk-burst) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 6 筆
ID dk-burst · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施)
部分雲端磁碟與小規格伺服器有 burst credit(突發額度),可以短時間跑得比基準效能快;忙碌時段一拉長、額度用完,速度就會突然下降。
為什麼 長時間以高於基準效能的速度使用 → 於是 burst credit 用完,效能驟降回基準值 → 畫面上 每天晚上過了幾個小時後開始 lag
症狀 卡頓 , 慢動作 , 輸入延遲
因素 停滯, 延遲
誰會遇到 整個伺服器
何時 晚間尖峰時段, 開越久越嚴重
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施)
基礎設施團隊要做的事 伺服器設備/OS:改用保證效能的磁碟(gp3、佈建 IOPS 型),設定額度剩餘量警示,並一併確認執行個體的磁碟頻寬突發上限與 CPU 額度。DB 設備:包含受管 DB 在內的 DB 磁碟也改為保證效能型,並設定額度剩餘量警示。
數值參考 AWS gp2 100GB 磁碟平常為 300 IOPS,突發時可達 3,000 IOPS,額度全滿時約可撐 30 分鐘。gp3 沒有額度機制,一直都是 3,000 IOPS。Azure 的小容量 Premium SSD 也能靠額度突發,最多 30 分鐘。
圖表上 碰到上限後持平 · IOPS、burst credit 剩餘量
查看位置 看 CloudWatch 的 EBS BurstBalance(gp2、st1、sc1)、執行個體的 EBSIOBalance%、EBSByteBalance%(部分會突發的執行個體)、突發型(burstable)執行個體的 CPUCreditBalance。Azure 則看 Data Disk Used Burst IO Credits Percentage 等 burst credit 使用率指標 符合的跡象 從剩餘量降到接近 0 的時間點起,IOPS(VolumeReadOps、VolumeWriteOps)在基準效能處持平,VolumeQueueLength 與 lag 一起增加。在尖峰持續幾個小時後才開始 不符合的跡象 各項剩餘量都很充足、IOPS 卻持平時,是磁碟區或執行個體的固定上限(dk-iops) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 即使磁碟本身正常,小規格的虛擬伺服器在執行個體的磁碟頻寬上也有突發上限(例如每天至少 30 分鐘),會出現同樣的圖形。使用 CPU 額度的低價伺服器,額度用完時也會慢到只剩基準效能。
出處 7 筆
IOPS 上限與佇列飽和 IOPS limit / queue saturation
ID dk-iops · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(DB 基礎設施)
請求數超過磁碟每秒能處理的數量時,佇列會變長,延遲急遽增加。
為什麼 讀寫請求接近磁碟的處理能力 → 於是 佇列變長(通常在使用率 90% 以上時急遽增加) → 畫面上 存檔、載入變慢;若是同步呼叫則會定格
症狀 輸入延遲 , 定格
因素 延遲, 停滯
誰會遇到 整個伺服器
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 合併請求、經常讀取的資料放進快取、改為非同步,讓遊戲執行緒不必等待磁碟。
基礎設施團隊要做的事 伺服器設備/OS:換用更快的磁碟、確認各執行個體類型的磁碟頻寬與 IOPS 上限、設定磁碟使用率與佇列警示、大檔案複製排在離峰時段。DB 設備:DB 磁碟也設定 IOPS 與處理量使用率警示,確認 DB 執行個體規格的磁碟上限。
數值參考 HDD 約 150 IOPS、SATA SSD 數萬、NVMe 數十萬 IOPS。雲端預設磁碟(AWS gp3)為 3,000 IOPS、每秒 125MiB;每秒傳輸量上限與 IOPS 是分開的,大檔案複製把它占滿時,連小筆寫入也會被卡住。
圖表上 碰到上限後持平 · IOPS、磁碟佇列長度
查看位置 看 iostat -x 1 的 r/s、w/s、rkB/s、wkB/s、aqu-sz、r_await、w_await。雲端則看 EBS 的 VolumeReadOps、VolumeWriteOps、VolumeQueueLength,是否超過上限的 VolumeIOPSExceededCheck、VolumeThroughputExceededCheck,以及執行個體端的 InstanceEBSIOPSExceededCheck、InstanceEBSThroughputExceededCheck 符合的跡象 每秒請求數或傳輸量在上限值處持平,aqu-sz 與 await 一起暴衝。雲端上超限檢查指標為 1 不符合的跡象 %util 即使是 100%,await 低時可能仍有餘裕。在平行處理請求的 SSD、RAID 上,%util 不代表已達上限。未達上限、只有 await 偏高時,是磁碟本身的延遲(dk-hdd)或 fsync(dk-fsync) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 在雲端上,除了磁碟本身的上限,每種伺服器規格(執行個體類型)也各有磁碟頻寬與 IOPS 上限。即使掛上昂貴的磁碟,伺服器規格太小時,仍會卡在執行個體的上限。
出處 8 筆
磁碟已滿 Disk full
ID dk-full · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施), 遊戲開發團隊(伺服器開發)
log 與 dump 越積越多、把磁碟塞滿時,寫入會失敗;沒有防範措施的話,伺服器會當機。
為什麼 log、dump、暫存檔累積到 100% → 於是 寫入失敗。沒有錯誤處理就當機,有的話則存檔失敗 → 畫面上 斷線、進度回檔
症狀 斷線 , 吃指令/回檔
因素 停滯
誰會遇到 整個伺服器
何時 開越久越嚴重
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 處理寫入失敗,改為重試存檔並發出警示,避免當機;減少不必要的 log 與 dump。
基礎設施團隊要做的事 伺服器設備/OS:log 輪替、容量警示、log 與資料分放不同磁碟。DB 設備:監看 DB 的 transaction log(WAL、binlog)是否因複寫中斷或漏做 log 備份而持續累積。
圖表上 緩慢爬升 · 磁碟使用率
查看位置 看 df -h 的使用率與 df -i 的 inode 使用率,並在伺服器與 DB 的 log 中找 ENOSPC 錯誤。DB 方面,看 PostgreSQL pg_replication_slots 中 active 為 false 的複寫槽、MySQL SHOW BINARY LOGS 的檔案數與大小、SQL Server sys.databases 的 log_reuse_wait_desc,RDS 則看 FreeStorageSpace 符合的跡象 使用率在幾天內持續上升,達到 100% 的時間點與當機、存檔失敗的時間重疊,log 中留有 ENOSPC 不符合的跡象 空間充足但寫入仍失敗時,是權限、檔案大小上限等其他原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 複本停止或漏做 log 備份時,DB 的 transaction log(WAL、binlog 等)不會被刪除,會一直累積。這顆磁碟滿了以後,DB 的所有寫入都會停止,存檔與交易同時失敗。
出處 8 筆
備份、壓縮、掃描作業 Backup / compression / scans
ID dk-backup · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施)
凌晨的備份、log 壓縮、安全掃描獨占磁碟時,遊戲伺服器的讀寫就會被擠到後面。
為什麼 排定的備份、壓縮作業開始 → 於是 占用大部分的磁碟頻寬與 IOPS → 畫面上 每天同一時間 lag
症狀 卡頓 , 輸入延遲
因素 停滯, 延遲
誰會遇到 整個伺服器
何時 固定週期
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施)
基礎設施團隊要做的事 伺服器設備/OS:調低備份、壓縮、掃描作業的 I/O 優先順序,並錯開執行時間。DB 設備:從複本進行備份。
圖表上 固定週期飆高 · 磁碟使用率、磁碟等待時間
查看位置 用 sar -d 把過去幾天紀錄(/var/log/sa 的每日檔案,sadc 須以 -S DISK 一併收集磁碟項目)的 %util、await、aqu-sz 按日期疊在一起看,在那個時間點用 pidstat -d 1 找出 kB_rd/s、kB_wr/s 最大的處理程序,再與 cron、systemd timer 的排程比對 符合的跡象 每天同一時間 await 與 %util 往上衝,此時備份、壓縮、掃描處理程序占了大部分的磁碟讀寫 不符合的跡象 往上衝的時間每天不同時,不太可能是排程工作。那個時間的 I/O 大多來自遊戲伺服器本身時,是存檔或 log 的問題(dk-fsync、dk-sync-log) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
伺服器端的延遲載入 Lazy loading on the server
ID dk-lazy-load · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
伺服器在副本、地圖資料第一次被請求時才從磁碟讀取的話,那個 tick 期間所有人都會停住。
為什麼 有人第一次進入副本或地圖 → 於是 伺服器在遊戲執行緒上從磁碟讀取資料 → 畫面上 那台伺服器上的所有人短暫定格
症狀 定格
因素 停滯
誰會遇到 特定地點/頻道, 整個伺服器
何時 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 在伺服器啟動時預先載入、改為非同步載入。
基礎設施團隊要做的事 剛從快照建立的伺服器,在投入服務前先預熱磁碟(把所有區塊讀過一次),或使用快速快照還原功能。
圖表上 偶爾隨機飆高 · 伺服器 tick 時間、磁碟讀取
查看位置 把停住的時間點與遊戲伺服器 log 中副本、地圖的首次進入紀錄對照,看那個瞬間遊戲伺服器的磁碟讀取(pidstat -d 的 kB_rd/s),並用 perf trace --duration 找耗時很久的 read、open 呼叫。若是新開的雲端伺服器,把 EBS 的 VolumeAvgReadLatency 與舊伺服器比較 符合的跡象 只在第一次進入的瞬間停住,第二次進入同一個地方時不會停住。停住期間遊戲執行緒在等待讀檔 不符合的跡象 已載入的地圖也一樣停住時,是超出 tick 預算、GC 等其他原因 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 在雲端上,剛從快照(磁碟副本)建立的伺服器,每個第一次讀取的區塊都要從遠端儲存裝置取回,比平常慢得多。如果只有自動擴展新開出來的伺服器第一次進入特別久,就要懷疑是這個原因。
出處 5 筆
ID dk-coredump · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
伺服器當機時要把數 GB 的記憶體寫入磁碟,有時會讓重新啟動延後好幾分鐘。
為什麼 伺服器當機,把整個記憶體寫成檔案 → 於是 寫入數 GB 的期間無法重新啟動 → 畫面上 伺服器當機造成斷線後,很長一段時間連不上
症狀 連不上/無限讀取
因素 停滯
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 評估改用只包含必要記憶體的小型 dump(minidump),並修正當機原因。
基礎設施團隊要做的事 限制 dump 大小(OS 的 core dump 設定)、使用快速的磁碟、讓重新啟動與 dump 分開(dump 的壓縮、上傳在重新啟動後另外處理)。
圖表上 連線同時大量中斷 · 連線數、伺服器重新啟動時間
查看位置 把當機時間、core 檔大小(coredumpctl list、info,或 core_pattern 指向位置的檔案)、檔案寫完的時間、服務重新啟動的時間並排對照,並看這段期間 iostat -x 的 wkB/s 符合的跡象 當機後寫入數 GB 的 core 檔期間,磁碟寫入一直貼近上限,寫完之後才開始重新啟動 不符合的跡象 core dump 已關閉或檔案很小,重新啟動卻仍然很慢時,是地圖載入、DB 冷快取(db-cold-cache)等伺服器啟動過程的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
HDD 尋軌延遲 HDD seek latency
ID dk-hdd · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施), 遊戲開發團隊(伺服器開發)
HDD 的讀寫頭必須在碟片上移動(尋軌,seek),所以讀寫分散各處的資料時,每次要花將近 10ms。
為什麼 老舊伺服器或低價儲存裝置使用 HDD → 於是 每次分散的讀寫約 10ms → 畫面上 存檔、載入全面變慢
症狀 輸入延遲
因素 延遲
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 基礎設施團隊(DB 基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 以循序寫入為主進行設計。
基礎設施團隊要做的事 伺服器設備/OS:換成 SSD(從分散讀寫較多的資料磁碟開始)。DB 設備:先把分散讀寫最多的 DB 磁碟換成 SSD。
圖表上 一開始就一直偏高 · 磁碟讀寫延遲(r_await、w_await)
查看位置 用 lsblk -d -o NAME,ROTA 確認是否為旋轉式磁碟(HDD),並看 iostat -x 1 的 r/s、w/s 與 r_await、w_await。虛擬伺服器則在雲端或儲存裝置的規格中確認磁碟種類 符合的跡象 是旋轉式磁碟,每秒請求只有數十~一百多個,r_await、w_await 卻一直在數 ms~數十 ms 不符合的跡象 SSD 卻延遲很高時,是佇列飽和(dk-iops)或 burst credit 耗盡(dk-burst)的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
L12 資料庫
16 個原因 · 完整版章節
沒有索引的查詢 Missing index / full table scan
ID db-no-index · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
沒有索引時,要找出符合條件的資料列,就必須讀完整張資料表(全表掃描)。
為什麼 部署新功能時,加入了沒有索引的條件查詢 → 於是 掃描數百萬筆資料列,一個查詢就要數百 ms~數秒 → 畫面上 信箱、交易紀錄載入變慢,連線被占住,連其他請求也要等待
症狀 輸入延遲 , 連不上/無限讀取
因素 延遲, 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 新查詢在部署前先檢查執行計畫、加上索引,並確認修改資料的查詢(UPDATE、DELETE)也有用到索引。
基礎設施團隊要做的事 監看慢查詢 log,找出全表掃描的查詢並提供給遊戲開發團隊;營運中新增索引時,採用鎖定時間短的線上(online)方式。
數值參考 有索引時只要數 ms;沒有索引時會隨資料量等比例變慢,在大型資料表上會慢到數百~數萬倍。
圖表上 從某個時間點起階梯式上升 · DB 查詢延遲、讀取的資料列數
查看位置 MySQL 看 slow query log(開啟 log_queries_not_using_indexes 後,沒用到索引的查詢也會記錄)的 Rows_examined、Rows_sent,以及 performance_schema events_statements_summary_by_digest 的 SUM_NO_INDEX_USED、SUM_ROWS_EXAMINED,再執行 EXPLAIN。PostgreSQL 看 pg_stat_user_tables 的 seq_scan、seq_tup_read,再執行 EXPLAIN 符合的跡象 部署後新出現的查詢,讀取的資料列(Rows_examined)比回傳的(Rows_sent)多出數千倍,EXPLAIN 顯示全表掃描(MySQL type ALL、PostgreSQL Seq Scan)。大型資料表的 seq_tup_read 從部署時間點起急遽增加 不符合的跡象 有用到索引仍然很慢時,是鎖定等待(db-hot-row、db-ddl-lock)或執行計畫改變(db-plan-flip)。小型資料表的全表掃描可能是正常的 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 受影響的不只是讀取。沒有索引的修改查詢(UPDATE、DELETE)依 DB 不同,可能把掃描過的資料列全都鎖住,連無關玩家的存檔都會被擋住。
出處 8 筆
熱點資料列鎖定競爭 Hot row lock contention
ID db-hot-row · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
所有人都要修改同一筆資料列(公會倉庫、拍賣場熱門道具、全伺服器共用的計數器)時,一次只有一個請求能取得鎖定。
為什麼 活動、熱門道具讓修改集中在同一筆資料列 → 於是 請求一直等到取得鎖定為止 → 畫面上 交易失敗、「請稍後再試」、逾時
症狀 吃指令/回檔 , 輸入延遲
因素 停滯, 延遲
誰會遇到 只有特定功能
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 拆分資料列(分片計數器,sharded counter)、縮短 transaction、先在記憶體中彙總再一次寫入。
基礎設施團隊要做的事 監控資料列鎖定的等待時間與次數,找出競爭集中的資料列並分享結果。
數值參考 一個請求持有鎖定 10ms 的話,這筆資料列每秒最多只能修改 100 次。transaction 中若夾著與其他伺服器的往返,次數還會再減少。
圖表上 隨人數/負載上升 · 資料列鎖定等待次數與時間
查看位置 MySQL 看 Innodb_row_lock_waits、Innodb_row_lock_time 的增加量與 Innodb_row_lock_current_waits,並用 sys.innodb_lock_waits 找出誰在等誰。PostgreSQL 看 pg_stat_activity 中 wait_event_type 為 Lock 的 session、pg_locks 中 granted 為 false 的請求;開啟 log_lock_waits(預設關閉)後,等待很久的鎖定會記錄在 log 中 符合的跡象 鎖定等待隨活動、人數急遽增加,等待中的請求大多指向同一張資料表的同一筆資料列(同一個 key) 不符合的跡象 等待平均分散在多張資料表、多筆資料列時,是磁碟或 CPU 飽和的問題。單一 session 長時間持有鎖定不放時,是長時間未結束的 transaction(db-long-tx) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 7 筆
DB 死結 Database deadlock
ID db-deadlock · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
兩個 transaction(當成一個整體處理的一組 DB 操作)互相等待對方鎖住的資料列時,DB 會強制取消其中一方。
為什麼 交易 A 依道具 → 貨幣的順序鎖定,交易 B 依貨幣 → 道具的順序鎖定 → 於是 DB 偵測到死結,回滾其中一方 → 畫面上 交易、製作偶爾失敗,道具被退回
症狀 吃指令/回檔 , 輸入延遲
因素 遺失, 停滯
誰會遇到 只有特定功能
何時 人潮湧入時, 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 統一鎖定順序、縮短 transaction、失敗時自動重試。
基礎設施團隊要做的事 保持死結偵測開啟,收集並分享死結紀錄;關閉偵測的 MySQL 伺服器要調低鎖定等待上限(預設 50 秒)。
數值參考 偵測所需時間:MySQL(InnoDB)幾乎即時,PostgreSQL 預設 1 秒,SQL Server 最多約 5 秒。這段期間兩個請求都會卡住。如果是因同時請求極多而關閉 MySQL 死結偵測的伺服器,會一直等到鎖定等待上限(預設 50 秒)。
圖表上 偶爾隨機飆高 · 死結次數、交易失敗次數
查看位置 MySQL 看 SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK(只有最近 1 筆)、開啟 innodb_print_all_deadlocks 後寫入錯誤 log 的所有死結,以及 INFORMATION_SCHEMA.INNODB_METRICS 的 lock_deadlocks。PostgreSQL 看 pg_stat_database 的 deadlocks,SQL Server 看預設開啟的 system_health session 的 xml_deadlock_report。遊戲伺服器端的錯誤碼為 MySQL 1213、PostgreSQL 40P01、SQL Server 1205 符合的跡象 交易、製作失敗的時間點死結次數增加,紀錄中的兩個 transaction 以相反的順序鎖定相同的資料表 不符合的跡象 死結次數不變卻仍失敗時,是超過鎖定等待上限(MySQL 錯誤 1205)或熱點資料列(db-hot-row) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 10 筆
連線池耗盡 Connection pool exhaustion
ID db-pool · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
與 DB 建立的連線數是固定的,慢查詢占住連線時,其餘請求只能等待。
為什麼 慢查詢或請求暴增,使所有連線都在使用中 → 於是 新請求要等到有連線空出來 → 畫面上 登入時無限讀取、存檔變慢、逾時
症狀 連不上/無限讀取 , 輸入延遲
因素 停滯, 延遲
誰會遇到 整個伺服器, 只有特定功能
何時 剛登入/維護剛結束, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 消除慢查詢、調整連線池大小與等待逾時(不要一味加大連線池)、依功能拆分連線池。
基礎設施團隊要做的事 確認 DB 的最大連線數與 CPU、IOPS 餘裕;擴充伺服器或自動擴展前,確認伺服器數 × 連線池大小在最大連線數以內;把連線等待與鎖等待指標加入監控。
數值參考 需要的連線數可用「每秒請求數 × 每筆請求占用連線的時間」估算。每秒 2,000 筆、每筆 5ms 時,平均隨時有 10 條連線在忙。考量請求湧入的情況,通常會準備兩三倍。查詢變慢到 150ms 時,同樣的請求量就需要 300 條。
圖表上 碰到上限後持平 · 使用中的 DB 連線數、連線等待時間
查看位置 在 DB 端依遊戲伺服器統計連線狀態。MySQL 看 SHOW PROCESSLIST 的 Host、Command(閒置連線為 Sleep)、Time,以及 Threads_connected、Threads_running 與被拒絕的連線數 Connection_errors_max_connections。PostgreSQL 把 pg_stat_activity 依 client_addr、state 分組統計。遊戲伺服器的連線池函式庫有輸出等待數與等待時間時,一併查看 符合的跡象 某台遊戲伺服器的連線達到連線池大小且全部都在執行查詢、閒置連線為 0 的期間,登入與存檔都在等待。或是 DB 的總連線數碰到 max_connections,新連線被拒絕 不符合的跡象 閒置連線充足卻仍然很慢時,是查詢本身的延遲(db-no-index、db-hot-row)或 DB 資源飽和的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 一味加大連線池,只會增加 DB 的 CPU 負載與鎖定競爭,讓所有人一起變慢。此外,伺服器數 × 連線池大小超過 DB 的最大連線數時,新增或重新啟動的伺服器甚至無法建立連線。這在自動擴展或維護剛結束時很常見。
出處 6 筆
複寫延遲 Replication lag
ID db-replica-lag · 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
寫入走主 DB、讀取走複本的架構下,複本跟得慢時,剛寫入的內容就會看不到。
為什麼 寫入集中湧向主 DB,複本落後數秒 → 於是 從複本讀取剛存檔的內容時,資料還不存在 → 畫面上 剛買的道具看不到、交易所價格還是舊的、重複發放的 bug
症狀 吃指令/回檔
因素 延遲
誰會遇到 只有特定功能
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 剛寫入的資料從主 DB 讀取;確認是否已發放與實際發放,在主 DB 上以同一個 transaction 完成(用唯一鍵或條件式 UPDATE 防止重複)。
基礎設施團隊要做的事 設定複寫延遲警示、讓複本規格不低於主 DB 並啟用平行複寫、大量刪除分成小批執行、管理在複本上長時間執行的彙總查詢。
圖表上 隨人數/負載上升 · 複寫延遲(秒)
查看位置 MySQL 在複本上看 SHOW REPLICA STATUS 的 Seconds_Behind_Source(8.0.22 之前的版本用 SHOW SLAVE STATUS)。PostgreSQL 看主伺服器 pg_stat_replication 的 write_lag、flush_lag、replay_lag,RDS 則看 ReplicaLag 符合的跡象 回報「看不到」的時間點延遲達數秒以上,延遲消除後再看就正常。寫入暴增、大量刪除或複本上執行長時間彙總查詢時,延遲變大 不符合的跡象 延遲接近 0 卻仍看不到時,是遊戲伺服器的快取或同步的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 即使寫入不多也可能落後。在主 DB 上花了 10 分鐘的一次大量刪除,在複本上重新執行的期間,也會讓複本落後同樣的時間;在複本上長時間執行的彙總查詢,也會拖慢複本追上的速度。
出處 6 筆
檢查點與 log flush Checkpoint / log flush stalls
ID db-checkpoint · 主要負責 基礎設施團隊(DB 基礎設施)
DB 定期把記憶體中的變更一次大量寫入磁碟的瞬間,查詢會變慢。
為什麼 變更累積後定期寫入磁碟 → 於是 那一刻磁碟變忙,查詢變慢 → 畫面上 存檔、載入週期性變慢
症狀 輸入延遲 , 卡頓
因素 延遲
誰會遇到 整個伺服器, 只有特定功能
何時 固定週期
負責單位 主要負責 基礎設施團隊(DB 基礎設施)
基礎設施團隊要做的事 把檢查點的寫入切細、平均分散,transaction log(redo log、WAL)配置充足,使用快速的磁碟。
圖表上 固定週期飆高 · DB 查詢延遲、磁碟寫入量
查看位置 PostgreSQL 看 log_checkpoints(新版本預設開啟)log 中的檢查點時間與寫入的緩衝區數、檢查點次數(17 起為 pg_stat_checkpointer 的 num_timed、num_requested,16 以下為 pg_stat_bgwriter 的 checkpoints_timed、checkpoints_req),以及 checkpoint_warning 警告。MySQL 看 SHOW ENGINE INNODB STATUS 的 LOG 區段中 Log sequence number 與 Last checkpoint at 的差距。一併疊上伺服器的磁碟寫入量與寫入延遲 符合的跡象 查詢延遲飆高的時間點與檢查點時間重疊,此時磁碟寫入量與寫入延遲往上衝。PostgreSQL 中由請求觸發的檢查點(num_requested)遠多於定時檢查點(num_timed)時,可判斷是 WAL 經常碰到 max_wal_size,使檢查點提前執行 不符合的跡象 以與檢查點時間無關的週期飆高時,是備份或批次作業(dk-backup、db-batch) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 記錄變更的 transaction log(MySQL 的 redo log、PostgreSQL 的 WAL)設得太小時,每次 log 寫滿,DB 都得匆忙集中執行檢查點,寫入處理量會短暫大幅下降。
出處 7 筆
冷快取(剛重新啟動時) Cold buffer pool after restart
ID db-cold-cache · 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
DB 重新啟動後記憶體快取是空的,有一段時間所有查詢都要從磁碟讀取。
為什麼 因維護而重新啟動 DB → 於是 常用資料不在記憶體中,只能從磁碟讀取 → 畫面上 維護剛結束的一段時間內,登入、載入很慢
症狀 連不上/無限讀取 , 輸入延遲
因素 延遲
誰會遇到 整個伺服器
何時 剛登入/維護剛結束
負責單位 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 逐步開放(用登入排隊分階段增加登入人數)。
基礎設施團隊要做的事 重新啟動後預熱快取(warm-up,確認 buffer pool 的儲存與還原設定),從快照還原的 DB 也要預先讀取磁碟。
圖表上 剛開服或維護結束後暴增 · 磁碟讀取、緩衝快取命中率
查看位置 MySQL 看 Innodb_buffer_pool_reads(不在 buffer pool 中而從磁碟讀取的次數)與 Innodb_buffer_pool_read_requests 的比例,以及預熱進度 Innodb_buffer_pool_load_status。PostgreSQL 看 pg_stat_database 的 blks_read、blks_hit。也一併看 DB 伺服器的磁碟讀取次數 符合的跡象 剛重新啟動時磁碟讀取往上衝、命中率偏低,之後隨時間逐漸恢復,這段期間登入、載入很慢 不符合的跡象 命中率與平常相同、維護剛結束卻很慢時,是登入暴增與 N+1(db-login-storm)或連線池(db-pool) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 MySQL 關閉時會儲存 buffer pool 的頁面清單,啟動時在背景重新讀回,但要全部填滿仍需要時間。在雲端上從快照(磁碟副本)還原的 DB,磁碟本身在每個區塊第一次讀取時也很慢,變慢的時間會拖得更久。
實際案例 Roblox 2021: Roblox 73 小時事故:服務探索(Consul)叢集的資源競爭
出處 5 筆
登入暴增與 N+1 查詢 Login storm, N+1 queries
ID db-login-storm · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
載入一個角色要分開查詢數十次的話,數萬人同時登入就會變成數百萬個查詢。
為什麼 載入角色時,道具、技能、任務各自分開查詢 → 於是 維護剛結束時大量同時登入,查詢暴增 → 畫面上 登入時無限讀取,連正在遊戲中的玩家存檔都被拖慢
症狀 連不上/無限讀取 , 輸入延遲
因素 停滯, 延遲
誰會遇到 整個伺服器
何時 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 合併成一次查詢、登入排隊、快取,並檢查 ORM 延遲載入產生的查詢數。
基礎設施團隊要做的事 列出呼叫次數最多的查詢排行並分享,監控維護剛結束的登入時段的查詢數與連線數。
圖表上 剛開服或維護結束後暴增 · DB 每秒查詢數、登入數
查看位置 把維護剛結束時的登入數與 DB 每秒查詢數(MySQL 為 Questions 的增加量)疊在一起看,計算每次登入的查詢數。呼叫次數最多的查詢,可從 MySQL events_statements_summary_by_digest 的 COUNT_STAR、PostgreSQL pg_stat_statements 的 calls 列出 符合的跡象 每次登入有數十個查詢,排行前面的都是以單一角色 ID 查詢、形式相同的短查詢。更新後每次登入的查詢數增加的話,就從那次更新查起 不符合的跡象 每次登入的查詢數不多、但每個查詢都很慢時,是冷快取(db-cold-cache)或索引(db-no-index) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 ORM(代為產生 DB 查詢的函式庫)的延遲載入,會在開發者沒察覺的情況下產生這類查詢。開發伺服器上只有幾個角色,看不出差異,要到正式環境大量同時登入時才會浮現。
出處 5 筆
大量批次作業 Batch jobs during service
ID db-batch · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
在營運時段執行排行榜彙總、信件批次發送、舊資料清理時,會占用鎖定與磁碟。
為什麼 在營運時段執行大量作業 → 於是 大範圍鎖定,占用磁碟與 CPU → 畫面上 特定時段交易、存檔失敗,載入變慢
症狀 輸入延遲 , 吃指令/回檔
因素 延遲, 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 固定週期
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 切成小批分次執行,彙總改在複本上進行。
基礎設施團隊要做的事 提供彙總用的複本,把批次作業排在離峰時段,監看鎖定擴大與 gap lock 等待。
圖表上 固定週期飆高 · DB 查詢延遲、鎖定等待
查看位置 找出 lag 發生時正在執行的長查詢。MySQL 看 slow query log,PostgreSQL 看 pg_stat_activity 的 query_start、query,再與同一時間的鎖定等待指標及批次排程(cron、DB 事件排程器)比對。SQL Server 用 lock_escalation 擴充事件記錄鎖定擴大 符合的跡象 每次都在同一時間執行大量 UPDATE、DELETE 或彙總查詢,期間鎖定等待與磁碟使用率一起上升 不符合的跡象 那個時間沒有長查詢時,是檢查點(db-checkpoint)或伺服器備份(dk-backup) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 SQL Server 在單一陳述式持有超過約 5,000 個資料列鎖定時,會改成資料表鎖定(鎖定擴大)。那一刻所有使用同一張資料表的請求都會停住。MySQL 在預設設定下,以範圍條件修改資料時,也會連資料列之間的間隙一起鎖住(gap lock),擋住新資料列的新增。
出處 4 筆
DB 容錯移轉 Database failover
ID db-failover · 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
主 DB 故障、切換到備援 DB 的期間無法寫入,最後一批還沒複寫過去的資料可能會遺失。
為什麼 主 DB 故障,備援 DB 升格為主 DB → 於是 切換期間有數秒~幾分鐘無法寫入;若是非同步複寫,尚未複寫的資料可能遺失 → 畫面上 短時間內所有存檔失敗,道具、經驗值回檔
症狀 吃指令/回檔 , 定格 , 斷線 , 連不上/無限讀取
因素 停滯, 遺失
誰會遇到 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 讓存檔可以重試;設定連線池與 DNS 快取,快速捨棄已中斷的連線並以新位址重新建立連線;在容錯移轉演練時確認能重新連線。
基礎設施團隊要做的事 採用同步或半同步複寫(代價是寫入延遲增加)、進行容錯移轉演練、監控切換時間與複寫延遲。
數值參考 受管 DB 的自動容錯移轉通常需要數十秒~2 分鐘。若是非同步複寫,可能會遺失相當於複寫延遲(不到 1 秒~數秒)的最近存檔。
圖表上 連線同時大量中斷 · DB 連線數、寫入錯誤數
查看位置 把 DB 端的容錯移轉紀錄(RDS 為事件 RDS-EVENT-0013 開始切換、RDS-EVENT-0049 切換完成,自行維運的 DB 為升格 log)與遊戲伺服器的 DB 連線數、連線錯誤數放在同一張圖表上。若是非同步複寫,也要看故障前一刻的複寫延遲(RDS ReplicaLag、PostgreSQL pg_stat_replication 的 replay_lag) 符合的跡象 存檔失敗集中在一段期間,且與容錯移轉開始到完成之間重疊。回檔的量與故障前一刻的複寫延遲相近。切換結束後仍持續出錯的遊戲伺服器,是還在使用連到舊位址的連線 不符合的跡象 沒有容錯移轉紀錄的時間發生的連線中斷,是網路或 DB 過載的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 Riot Games 2021: League of Legends EUW 5 小時事故:一個附屬 DB 讓整個伺服器停擺
出處 7 筆
ID db-save-interval · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
為了減輕負載而每隔幾分鐘才存檔一次的話,伺服器在兩次存檔之間當機時,進度就會消失。
為什麼 每隔幾分鐘才儲存一次角色狀態 → 於是 在兩次存檔之間發生伺服器當機或故障 → 畫面上 重新連線後回到幾分鐘前的狀態(回檔)
症狀 吃指令/回檔
因素 遺失
誰會遇到 整個伺服器, 特定地點/頻道
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 重要事件(交易、取得稀有道具)立即存檔,並記錄變更 log。
基礎設施團隊要做的事 確認 DB 的 IOPS 與 CPU 有足夠餘裕,能承受縮短存檔週期後增加的寫入量。
圖表上 連線同時大量中斷 · 連線數、回檔回報數
查看位置 把當機、故障的時間,與回報回檔的角色最後一次存檔的時間(遊戲伺服器的存檔 log 或 DB 的修改時間欄位)並排對照 符合的跡象 回檔回到的時間點與當機前最後一次存檔的時間一致,遺失的時間短於存檔週期 不符合的跡象 遊戲伺服器 log 顯示存檔已完成卻仍回檔時,是 DB 容錯移轉造成的資料遺失(db-failover)或從複本讀到的舊值(db-replica-lag) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
Cache stampede Cache stampede / thundering herd
ID db-cache-stampede · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
熱門資料的快取同時過期時,數千個請求會一口氣湧向 DB。
為什麼 存放在 Redis 等快取中的熱門資料同時過期 → 於是 要重新產生同一筆資料的請求一口氣湧向 DB → 畫面上 DB 過載,多項功能接連變慢甚至停住
症狀 輸入延遲 , 定格 , 連不上/無限讀取
因素 停滯, 延遲
誰會遇到 整個伺服器
何時 固定週期, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 把過期時間隨機分散;只讓一個請求更新,其餘請求繼續使用舊值。
基礎設施團隊要做的事 為 Redis 建置複本與自動容錯移轉,避免重新啟動或故障時整個快取被清空;確認 DB 有足夠餘裕,即使快取全空也撐得住。
圖表上 固定週期飆高 · 快取命中率、DB 每秒查詢數
查看位置 把 Redis INFO 的 keyspace_hits、keyspace_misses(命中率)、expired_keys、是否重新啟動(uptime_in_seconds)與 DB 每秒查詢數疊在一起看,並統計那個瞬間 DB 上同一個查詢同時有幾個在執行(MySQL SHOW PROCESSLIST、PostgreSQL pg_stat_activity) 符合的跡象 快取未命中瞬間暴衝時,DB 查詢數也一起往上衝,同時執行的查詢大多是讀取同一筆資料的同一個查詢。與熱門 key 的過期週期或 Redis 重新啟動時間重疊 不符合的跡象 快取未命中與平常相同、只有 DB 查詢增加時,是登入暴增(db-login-storm)或批次作業(db-batch) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 Redis 重新啟動或因故障導致快取整個清空時,也會發生同樣的事。越是仰賴快取而把 DB 規格壓小的架構,風險越高。
出處 6 筆
長時間未結束的 transaction Long-running transaction / MVCC purge lag
ID db-long-tx · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
一個 transaction 長時間不結束時,會一直持有鎖定,DB 也無法清理(purge)舊版本的資料,整體會越來越慢。
為什麼 開著 transaction 等待其他伺服器的回應,或在營運中於主 DB 上執行長時間的彙總查詢 → 於是 持有的鎖定一直不釋放,待清理的舊版本資料持續累積 → 畫面上 使用那些資料列的功能逾時,存檔與查詢在幾個小時內全面變慢
症狀 輸入延遲 , 吃指令/回檔
因素 延遲, 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 開越久越嚴重, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 不在 transaction 中等待網路呼叫或使用者輸入,彙總查詢改在複本上執行。
基礎設施團隊要做的事 對長時間未結束的 transaction 發出警示並強制終止、提供彙總用的複本、監看 undo log 與失效資料列的增加。
圖表上 緩慢爬升 · undo log 長度(History list length)、失效資料列數
查看位置 MySQL 用 INFORMATION_SCHEMA.INNODB_TRX 的 trx_started 找出最舊的 transaction,並看 SHOW ENGINE INNODB STATUS 的 TRANSACTIONS 區段中的 History list length(尚未清理的 undo log 量)。PostgreSQL 看 pg_stat_activity 的 xact_start、state 為 idle in transaction 的 session,以及 pg_stat_user_tables 的 n_dead_tup 符合的跡象 存在已開啟幾分鐘~幾小時的 transaction,期間 History list length 或 n_dead_tup 持續上升,結束該 transaction 後隨著清理(purge、VACUUM)執行而下降 不符合的跡象 沒有長時間的 transaction 卻全面變慢時,是檢查點(db-checkpoint)或磁碟的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 DB 會保留舊版本,讓讀取端能看到修改前的樣子(MVCC)。這些紀錄要等最舊的 transaction 結束後才能刪除,所以一個 transaction 開著好幾個小時的話,MySQL 會累積 undo log,PostgreSQL 會累積 VACUUM 清不掉的失效資料列(dead tuple)。SQL Server 則可能因 transaction log 無法縮減而塞滿磁碟。
出處 7 筆
Redis 慢指令 Redis blocking commands (single-threaded)
ID db-redis-block · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
Redis 一次只處理一個指令,因此一個慢指令就會擋住後面所有的請求。
為什麼 營運中用 KEYS 搜尋全部 key,或一次讀取、刪除含數百萬個元素的排行榜或清單 → 於是 在該指令結束前,其他所有請求都要等待(數十 ms~數秒) → 畫面上 使用 session、排行榜、快取的功能同時頓一下,登入變慢
症狀 定格 , 輸入延遲 , 連不上/無限讀取
因素 停滯, 延遲
誰會遇到 整個伺服器, 只有特定功能
何時 偶爾隨機發生, 固定週期
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 用 SCAN 取代 KEYS、拆分大型 key、刪除改用 UNLINK(背景刪除)、分散集中在同一秒的過期時間。
基礎設施團隊要做的事 監看慢指令紀錄(SLOWLOG)、在正式環境伺服器上封鎖 KEYS 等危險指令、定期檢查大型 key、關閉 THP 並保留 fork 所需的記憶體餘裕、RDB 與 AOF 持久化改在複本上進行。
數值參考 一般指令不到 1ms。一次處理數百萬個元素時,有時要花數百 ms 到數秒。
圖表上 偶爾隨機飆高 · Redis 回應延遲、慢指令數
查看位置 用 SLOWLOG GET 看超過 slowlog-log-slower-than 的指令;用 CONFIG SET latency-monitor-threshold 開啟延遲監控(預設關閉)後,以 LATENCY LATEST、LATENCY DOCTOR 看 fork、expire-cycle 等各事件的延遲。也用 INFO 的 latest_fork_usec 與 redis-cli --bigkeys 確認 fork 時間與大型 key 符合的跡象 停住的時間點,SLOWLOG 中留有 KEYS 或一次處理整個大型 key 的指令,或 LATENCY 在同一時間記錄到數十 ms 以上的 fork、expire-cycle 事件 不符合的跡象 SLOWLOG、LATENCY 都是空的,只有從遊戲伺服器端看很慢時,是網路或遊戲伺服器內部的等待(SLOWLOG 只量指令執行時間,不含與用戶端往來的時間) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 為了建立持久化檔案(RDB 快照)或重寫 AOF 而複製處理程序(fork)的瞬間也會停住。在現今的伺服器上,每 1GB 記憶體約需 10ms,30GB 就約 300ms。開啟大分頁(THP)時,fork 之後每次寫入都要整個複製一個大分頁(copy-on-write),暫停時間與記憶體用量都會大增,所以通常會關閉 THP,並保留充足的記憶體餘裕。同一秒內過期的 key 非常多時,Redis 也會為了刪除它們而短暫停住。
出處 7 筆 Diagnosing latency issues Redis 由單一執行緒依序處理請求,慢指令會擋住後面所有請求;用 SCAN 取代 KEYS;fork 在實體伺服器與新型 VM 上實測每 1GB 約 9~13ms;THP 會因 fork 後的複製造成延遲與記憶體暴增;同一秒大量過期時會停住 KEYS Redis 在正式環境中務必極度謹慎使用,在大型 DB 上可能嚴重拖垮效能(入門級筆電上 100 萬個 key 需 40ms) UNLINK Redis 立即移除 key、在其他執行緒回收記憶體的非同步刪除 SLOWLOG Redis 記錄超過 slowlog-log-slower-than 之指令的慢指令 log,執行時間不含與用戶端往來的 I/O Redis latency monitoring Redis latency-monitor-threshold 預設為 0(關閉);LATENCY LATEST、LATENCY DOCTOR;記錄 fork、expire-cycle 等各事件的延遲 INFO Redis latest_fork_usec:最後一次 fork 所花的時間(微秒) Redis CLI Redis --bigkeys:掃描 keyspace 找出大型 key
執行計畫改變造成的查詢延遲 Query plan regression (stats, parameter sniffing)
ID db-plan-flip · 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
程式碼沒變,DB 卻改變了處理同一個查詢的方式(執行計畫)時,昨天只要 2ms 的查詢,今天會變成數百 ms。
為什麼 統計資訊自動更新、DB 重新啟動或資料分布改變,使 DB 重新建立執行計畫 → 於是 選中了不走索引的計畫,同一個查詢慢了數十~數百倍,連線被占住 → 畫面上 明明沒有部署,特定功能的載入卻突然變慢,連其他請求也要等待
症狀 輸入延遲 , 連不上/無限讀取
因素 延遲, 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 結果筆數會因參數值而差異很大的查詢,拆開使用或評估加上計畫提示(hint);設計確定會走索引的查詢。
基礎設施團隊要做的事 監看慢查詢與執行計畫的歷史紀錄、固定好的計畫(SQL Server 的查詢存放區等)、管理統計資訊的更新時間。
圖表上 從某個時間點起階梯式上升 · 各查詢的平均執行時間
查看位置 定期收集相同形式查詢的平均時間,觀察變化趨勢。MySQL 為 events_statements_summary_by_digest 的 AVG_TIMER_WAIT,PostgreSQL 為 pg_stat_statements 的 mean_exec_time(12 以下為 mean_time)。變慢前後的執行計畫用 EXPLAIN 或 PostgreSQL auto_explain 比較,SQL Server 則用查詢存放區的「迴歸查詢」(Regressed Queries)畫面比較 符合的跡象 在沒有部署的時間點,某個查詢的平均時間階梯式上升數十倍,該時間點與統計資訊更新或 DB 重新啟動重疊,且執行計畫已經改變 不符合的跡象 執行計畫沒變卻變慢時,是資料量增加、鎖定等待(db-hot-row)或磁碟的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 SQL Server 會重複使用依第一次傳入的值所建立的計畫(參數探查,parameter sniffing)。依只有幾個道具的新角色建立的計畫,用在擁有數萬個道具的老角色上時會大幅變慢,反過來的情況也很常見。重新啟動清掉計畫後會暫時恢復正常,之後又可能再度變差。
出處 7 筆
ID db-ddl-lock · 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
在服務中替資料表新增欄位或索引時,可能因為一個只需要短暫持有的鎖定,讓所有使用該資料表的請求都在等待。
為什麼 以 hotfix 替營運中的資料表新增欄位或索引 → 於是 schema 變更在等待先前開啟的長 transaction,後面進來的所有請求又在等待這個 schema 變更 → 畫面上 使用該資料表的功能(背包、信件等)整個停住並逾時
症狀 輸入延遲 , 吃指令/回檔 , 連不上/無限讀取
因素 停滯
誰會遇到 只有特定功能, 整個伺服器
何時 偶爾隨機發生, 剛登入/維護剛結束
負責單位 主要負責 基礎設施團隊(DB 基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 含 schema 變更的 hotfix 要與 DB 基礎設施協調時程;先部署在沒有新欄位時也能運作的程式碼。
基礎設施團隊要做的事 把鎖定等待上限設短、失敗就重試,在沒有長 transaction 時執行,使用線上 schema 變更工具,大型資料表留到維護時間處理。
圖表上 從某個時間點起階梯式上升 · 等待鎖定的 session 數、該資料表的查詢延遲
查看位置 MySQL 統計 SHOW PROCESSLIST 中 State 為 Waiting for table metadata lock 的 session 數,並用 sys.schema_table_lock_waits 找出造成阻擋的 session(blocking_pid)。PostgreSQL 看 pg_locks 中 granted 為 false 的請求與 AccessExclusiveLock,並用 pg_blocking_pids() 找出造成阻擋的 session 符合的跡象 從開始 schema 變更的時間點起,所有使用該資料表的查詢都卡在鎖定等待,最前面是尚未結束的 transaction 或 schema 變更陳述式 不符合的跡象 等待只集中在特定資料列、同一張資料表的其他資料列處理正常時,是熱點資料列(db-hot-row) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 MySQL 變更 schema 時會短暫取得中繼資料鎖定(metadata lock),PostgreSQL 則會短暫取得最強的資料表鎖定。即使變更本身瞬間就完成,只要前面有一個尚未結束的 transaction,後面所有請求都得等待。
出處 8 筆
L13 伺服器架構與維運
13 個原因 · 完整版章節
ID in-gateway · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
在用戶端與遊戲伺服器之間放一台中介伺服器時,每經過一次就多一段處理時間,而且這台伺服器會成為單點故障。
為什麼 用戶端 ↔ 閘道 ↔ 遊戲伺服器的架構 → 於是 多了中介伺服器的處理與等待時間,過載時影響所有人 → 畫面上 整體 ping 上升;閘道故障時,經過它的玩家全部斷線
症狀 輸入延遲 , 斷線
因素 延遲, 停滯
誰會遇到 整個伺服器
何時 人潮湧入時, 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:做成閘道可以擴充到多台的架構,並讓閘道掛掉時改連另一台閘道後角色能直接接續(session 重新連線)。用戶端:與閘道的連線中斷時自動重新連線。
基礎設施團隊要做的事 閘道水平擴展(增加台數),監控每台閘道的 CPU、連線數與處理延遲。
數值參考 因為在同一個資料中心內,平常每經過一次不到 1ms。閘道過載時會增加到數十~數百 ms。
圖表上 隨人數/負載上升 · 閘道處理延遲、閘道的 CPU 與連線數
查看位置 閘道的 CPU、連線數與閘道 socket 的 Recv-Q(ss、netstat),以及經過閘道前後的延遲差。若是經過 service mesh 的 HTTP、gRPC 呼叫,將 Istio 標準指標 istio_request_duration_milliseconds 分成發送端(reporter=source)與接收端(reporter=destination)比較 符合的跡象 遊戲伺服器的處理時間不變,只有閘道區段的延遲增加,且同一時間閘道 CPU 飽和或 Recv-Q 堆積 不符合的跡象 不經過閘道的路徑(直接連線、其他閘道)也一樣慢時,是線路或遊戲伺服器端的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 使用 service mesh(Istio 等)時,每台伺服器旁邊附掛的 sidecar proxy(Envoy)也會多出一層。服務之間的請求會依序經過發送端的 sidecar 與接收端的 sidecar,proxy 上加的功能(例如收集 log、指標)越多,處理時間與等待時間就越長。
實際案例 Riot Games 2020: League of Legends 歐洲、巴西伺服器的邊緣主機過載
出處 7 筆
ID in-zone-transfer · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
進入其他地圖或副本時,把角色資料交給另一台伺服器的過程中會產生延遲與失敗。
為什麼 進入副本、移動到其他大陸,負責的伺服器因此改變 → 於是 儲存 → 傳遞 → 載入;目標伺服器擁擠或沒有空的副本實例時要等待 → 畫面上 載入很久、進場失敗、移動途中斷線
症狀 連不上/無限讀取 , 定格 , 斷線 , 拉回
因素 延遲, 停滯
誰會遇到 只有我, 特定地點/頻道
何時 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 減少轉移的資料量、預先保留目標伺服器、失敗時回到原位。
基礎設施團隊要做的事 監控副本、zone 伺服器的空實例餘量,尖峰前先備好台數。
圖表上 隨人數/負載上升 · 切換 zone 耗時、失敗次數
查看位置 伺服器記錄的各轉移階段耗時(儲存、傳遞、載入)與失敗原因,以及目標伺服器的人數與空實例數 符合的跡象 回報載入很久、進場失敗的時間點,轉移時間變長或失敗集中,且目標伺服器擁擠或空實例已用完 不符合的跡象 轉移很快完成、抵達後才停住時,是進入密集區域時的生成暴增或用戶端載入的問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 沒有讀取畫面、連成一片的無縫世界,跨越伺服器邊界時負責的伺服器同樣會改變。在邊界附近可能會頓一下,或出現拉回。
出處 1 筆
連鎖故障 Cascading failure
ID in-cascade · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施)
一個服務變慢時,呼叫它的伺服器會卡在等待回應,連不相關的功能也跟著停擺。
為什麼 DB、認證等某一個服務變慢 → 於是 呼叫端伺服器的執行緒與連線卡在等待回應,失敗請求的重試又加重負載 → 畫面上 看似無關的功能也全部變慢或停擺
症狀 定格 , 輸入延遲 , 連不上/無限讀取
因素 停滯
誰會遇到 整個伺服器
何時 人潮湧入時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 所有呼叫都設逾時、斷路器、依功能隔離(bulkhead),重試要逐步拉長間隔並限制次數,健康檢查的回應與忙碌的工作分開處理。
基礎設施團隊要做的事 負載平衡器的健康檢查在失敗次數與間隔上保留餘裕,避免把只是暫時變慢的伺服器立刻移出;限制同時移出的伺服器數量。
圖表上 碰到上限後持平 · 各服務的回應時間與錯誤率、執行緒與連線使用數
查看位置 把各服務的回應時間、錯誤率、重試次數對齊時間軸放在同一個畫面,找出最先變慢的地方。若在負載平衡器後方,看目標回應時間(AWS ALB 為 TargetResponseTime)、目標的 5xx 數(HTTPCode_Target_5XX_Count)、判定異常而移出的目標數(UnHealthyHostCount) 符合的跡象 某個服務的延遲先上升,接著呼叫該服務一方的執行緒、連線使用數貼齊上限,錯誤擴散到其他服務,重試次數與移出的目標數一起增加 不符合的跡象 多個服務在同一瞬間一起變慢時,先查共用資源(DB、網路、主機)的故障 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 健康檢查(確認伺服器是否存活的檢查)也會讓連鎖擴大。忙碌的伺服器太晚回應檢查時,負載平衡器會把其實正常的伺服器移出,它的流量湧向剩下的伺服器,下一台伺服器也跟著變慢。
實際案例 Riot Games 2020: League of Legends 歐洲、巴西伺服器的邊緣主機過載 Riot Games 2021: League of Legends EUW 5 小時事故:一個附屬 DB 讓整個伺服器停擺 Roblox 2021: Roblox 73 小時事故:服務探索(Consul)叢集的資源競爭 AWS 2021: AWS us-east-1 內部網路壅塞 AWS 2025: AWS us-east-1 DynamoDB DNS 事故與漫長的復原
出處 4 筆
附屬伺服器故障 Auxiliary service outage
ID in-subservice · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
聊天、隊伍、拍賣場這類與遊戲伺服器分開運作的伺服器故障時,只有那個功能無法運作。
為什麼 功能專用伺服器變慢或掛掉 → 於是 只有該功能的請求沒有回應 → 畫面上 無法聊天、組隊邀請沒反應、交易所無限讀取(戰鬥正常)
症狀 吃指令/回檔 , 連不上/無限讀取
因素 停滯, 遺失
誰會遇到 只有特定功能
何時 偶爾隨機發生, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 設計成即使失敗遊戲也能繼續、顯示各功能的狀態、不把多個功能集中在一台中央伺服器。
基礎設施團隊要做的事 每台附屬伺服器的健康檢查與警示、備援與自動重新啟動。
圖表上 連線同時大量中斷 · 各功能的請求成功率、附屬伺服器的連線數與健康檢查
查看位置 聊天、隊伍、拍賣場等各附屬伺服器的健康檢查、處理程序狀態與連線數,各功能的請求成功率與回應時間。若在負載平衡器後方,看目標群組的 UnHealthyHostCount 符合的跡象 只有負責被回報功能的伺服器出現健康檢查失敗或連線數驟降,遊戲伺服器的 tick 與戰鬥正常 不符合的跡象 多個功能同時停擺時,是一起轉送這些功能的中央伺服器或連鎖故障的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 如果隊伍、公會、密語、跨伺服器移動全都由一台中央伺服器(world/manager 伺服器)轉送,這台伺服器一變慢,多個功能就會同時停擺。
出處 3 筆
部署與重新啟動 Deploy / rolling restart
ID in-deploy · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
為了更新而重新啟動伺服器時,如果不先把連線移走,原本在那台伺服器上的人就會斷線,關閉前的存檔與重新連線也會同時湧入。
為什麼 部署 hotfix,依序重新啟動伺服器 → 於是 沒有把連線移到其他伺服器就關閉,那台伺服器上所有玩家的存檔同時湧向 DB → 畫面上 沒有公告就斷線、重新連線暴增
症狀 斷線 , 連不上/無限讀取 , 輸入延遲
因素 停滯
誰會遇到 整個伺服器, 特定地點/頻道
何時 偶爾隨機發生, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 drain 功能(只擋新連線,等現有的人離開),把角色移到其他伺服器,關閉前分批存檔,重新啟動後完成快取載入與 JIT 暖機再回報準備完成,熱重載(hot reload)在另一個執行緒先讀好,再於 tick 之間一次替換。
基礎設施團隊要做的事 部署工具逐台等 drain 完成後再重新啟動,重新啟動的伺服器確認準備完成(暖機結束)後才接流量,公告部署時間。
數值參考 一台伺服器有 5,000 人時,關閉前幾秒內會有 5,000 筆存檔湧向 DB。
圖表上 連線同時大量中斷 · 各伺服器連線數、DB 寫入次數
查看位置 把部署工具的作業紀錄(各伺服器重新啟動時間)以垂直線(註記)疊在連線數、斷線次數、DB 寫入、登入請求的圖表上看 符合的跡象 各伺服器的連線數在重新啟動時間點逐台依序驟降,驟降前 DB 寫入往上衝,驟降後登入請求往上衝 不符合的跡象 斷線時間點與部署、重新啟動紀錄不重疊時,是伺服器當機或網路設備的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 剛重新啟動後的幾分鐘也會比較慢。快取是空的,DB 查詢集中湧入;Java、C# 伺服器在執行中最佳化程式碼的過程(JIT 暖機)尚未結束,同樣的工作要花更多時間。不關伺服器、直接重新讀取腳本與資料表的方式(熱重載)也一樣,讀取期間 tick 會停住,造成短暫定格。
出處 3 筆
自動擴展延遲 Autoscaling lag
ID in-autoscale · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
人潮湧入時會自動增加伺服器,但準備要花幾分鐘,這段期間既有的伺服器處於過載。
為什麼 活動開始,連線急增 → 於是 新伺服器從啟動到準備好需要數分鐘 → 畫面上 活動剛開始的幾分鐘內出現慢動作、連不上
症狀 慢動作 , 連不上/無限讀取
因素 停滯
誰會遇到 整個伺服器
何時 人潮湧入時, 剛登入/維護剛結束
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 分散頻道(已在擁擠頻道裡的人無法移到新伺服器),縮短新伺服器的啟動與資料載入時間。
基礎設施團隊要做的事 活動前預先擴展、準備已暖機的備用伺服器,縮減時等留下的人離開後再關閉。
數值參考 偵測到負載要 1~數分鐘(因為指標是取數分鐘的平均來看),啟動新伺服器、讀取遊戲資料、填滿快取又要數分鐘。
圖表上 剛開服或維護結束後暴增 · 執行個體數、CPU 使用率、連線等待
查看位置 把自動擴展的活動紀錄(決定擴展的時間、新執行個體開始服務的時間)疊在 CPU 使用率、連線數圖表上看。AWS 看 Auto Scaling 群組指標(要先啟用才看得到)GroupDesiredCapacity(目標台數)、GroupPendingInstances(準備中)、GroupInServiceInstances(服務中) 符合的跡象 連線急增後幾分鐘內只有目標台數與準備中的執行個體增加,既有伺服器的 CPU 貼齊上限,直到服務中的執行個體增加的時間點才緩解 不符合的跡象 新執行個體加入後仍然很慢時,是伺服器台數以外的原因(DB 等共用資源、連鎖故障) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 自動擴展主要用在登入、閘道、副本這類只要讓新伺服器接新玩家就好的地方。縮減時也會出問題。清晨人少時縮減伺服器,如果沒等留下的人離開就關機,這些人會斷線。
實際案例 AWS 2021: AWS us-east-1 內部網路壅塞 AWS 2025: AWS us-east-1 DynamoDB DNS 事故與漫長的復原
出處 4 筆
log 與監控過載 Logging / monitoring overhead
ID in-monitoring · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
發生故障時 log 會暴增,以同步方式送出 log 的伺服器會因為 log 變得更慢。
為什麼 發生錯誤,log 與指標的傳送量暴增 → 於是 log 收集器消化不及,同步傳送的伺服器只能等待 → 畫面上 故障時的卡頓、定格因為 log 變得更嚴重
症狀 卡頓 , 定格
因素 停滯
誰會遇到 整個伺服器
何時 人潮湧入時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 非同步傳送、取樣、緩衝區滿了就丟棄、相同的錯誤 log 合併後再送。
基礎設施團隊要做的事 以故障時的暴增量為基準準備 log 收集器容量,收集器積壓時發出警示。
圖表上 偶爾隨機飆高 · log 傳送量、log 收集器佇列
查看位置 把伺服器每秒的 log 行數與位元組數、log 收集 agent 的佇列與丟棄數,和 tick 時間一起看。有執行緒停住時,用 bcc offcputime -p 看是否在等寫入或傳送 log 符合的跡象 tick 飆高的時間點 log 量往上衝到平常的數十倍,遊戲執行緒的等待時間集中在寫入、傳送 log 的呼叫堆疊 不符合的跡象 log 量與平常相同,或遊戲執行緒沒有在 log 那邊等待時,log 暴增只是故障的結果,要另外找最先出錯的原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
伺服器之間的時鐘差異 Clock skew between servers
ID in-clock-skew · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
各伺服器的時鐘各差一點時,冷卻時間、buff、活動開始的判定就會在伺服器之間對不上。
為什麼 時間同步停止的伺服器,時鐘與其他伺服器相差數百 ms~數秒 → 於是 在伺服器之間傳遞 buff 結束時間這類絕對時間,判定就會對不上 → 畫面上 一移動 buff 就消失,或冷卻重新開始計算
症狀 吃指令/回檔
因素 延遲
誰會遇到 只有我
何時 移動中/切換地圖時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 伺服器之間以剩餘時間取代絕對時間來傳遞。
基礎設施團隊要做的事 監控時間同步(NTP、chrony),伺服器之間時鐘差異過大時發出警示。
數值參考 時間同步(NTP、chrony)正常時,同一資料中心的伺服器之間通常在數 ms 以內。同步停止,或虛擬機長時間暫停後恢復時,會拉大到數百 ms~數秒。
圖表上 緩慢爬升 · 各伺服器的時鐘偏移(offset)
查看位置 收集各伺服器 chronyc tracking 的 System time(系統時鐘與 NTP 時鐘的差)、Last offset 與 Ref time(最後一次套用時間來源測量值的時間)來比較 符合的跡象 問題伺服器的偏移比其他伺服器大了數百 ms 以上,或 Ref time 停在很久以前,且判定錯亂只發生在進出那台伺服器的移動 不符合的跡象 所有伺服器的偏移都在數 ms 內時,是遊戲端的時間計算或用戶端時鐘同步誤差的問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 單一伺服器的時鐘一下子往前或往後跳的情況,在伺服器 OS 層的「系統時鐘跳動(NTP step)」說明。
出處 4 筆
ID in-bots · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施)
機器人送出請求的頻率遠高於真人,會吃掉伺服器的處理量。
為什麼 大量連線的機器人不停重複打怪、移動、交易 → 於是 伺服器處理量與 DB 負載增加 → 畫面上 特定練功區或整個伺服器變慢(慢動作、輸入延遲)
症狀 慢動作 , 輸入延遲
因素 停滯
誰會遇到 整個伺服器, 特定地點/頻道
何時 一直都有, 晚間尖峰時段
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 偵測機器人,依帳號、角色限制請求頻率。
基礎設施團隊要做的事 依 IP 限制連線與請求頻率(網咖、行動網路是多人共用一個 IP,要放寬),用防火牆、WAF 封鎖機器人的 IP 區段。
圖表上 只有部分偏高 · 各帳號/IP 的每秒請求數
查看位置 用遊戲伺服器 log 查看各帳號、角色每秒請求數的分布與前幾名清單。沒有程式碼指標時,看防火牆、WAF 的各 IP 請求數 符合的跡象 少數帳號、IP 以真人不可能達到的頻率不停送出請求,限制它們之後伺服器負載明顯下降 不符合的跡象 請求平均分散在各帳號時,是正常人數增加的問題(超出 tick 預算、自動擴展延遲) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
依賴外部服務 External dependencies (auth, billing, platform)
ID in-external · 主要負責 外部(外部) · 協同 遊戲開發團隊(伺服器開發)
平台登入、付款、身分驗證這類外部服務變慢或停擺時,會卡在那個步驟。
為什麼 外部認證、付款服務故障或延遲 → 於是 在該步驟等待回應 → 畫面上 無法登入、付款失敗。已在遊戲中的人正常
症狀 連不上/無限讀取 , 吃指令/回檔
因素 停滯
誰會遇到 整個伺服器, 只有特定功能
何時 剛登入/維護剛結束, 做特定動作時
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 外部呼叫設逾時並提供清楚的說明,快取認證結果,建立付款重試與補償流程。
外部要做的事 向認證、付款、平台業者確認故障並要求修復,告知玩家是外部服務故障。
圖表上 從某個時間點起階梯式上升 · 外部呼叫的回應時間與錯誤率、登入成功數
查看位置 平台登入、付款、身分驗證等各外部呼叫的回應時間、錯誤率、逾時次數,以及業者的狀態頁面 符合的跡象 從登入、付款失敗集中的時間點起,只有特定外部呼叫的錯誤與逾時升高一階並維持,業者狀態頁面上同一時間有故障 不符合的跡象 外部呼叫正常但登入卡住時,是登入伺服器本身(執行緒池耗盡、DB)或作業系統的連線等待佇列(backlog)的問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
實際案例 Fastly 2021: Fastly CDN 全球性錯誤 AWS 2021: AWS us-east-1 內部網路壅塞 AWS 2025: AWS us-east-1 DynamoDB DNS 事故與漫長的復原
出處 3 筆
配對與區域分配錯誤 Wrong region assignment (matchmaking / GeoDNS)
ID in-region-match · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(網路基礎設施), 外部(外部)
沒被分到近的區域、卻被分到遠方區域的伺服器時,即使線路正常,也只有那位玩家的 ping 一直偏高。
為什麼 GeoIP 資料錯誤、VPN、以隊友平均 ping 分配整個隊伍、人數不足時擴大到遠方區域的規則、依 DNS 解析器(resolver)位置分配 → 於是 明明有近的區域,卻連到海外區域的伺服器 → 畫面上 在多個區域設有伺服器的遊戲中,只有我(或只有我們隊伍)ping 一直偏高,出現輸入延遲、拉回、技能被吃
症狀 輸入延遲 , 拉回 , 吃指令/回檔
因素 延遲
誰會遇到 只有我, 特定地區/電信業者
何時 一直都有, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(網路基礎設施), 外部(外部)
遊戲開發團隊要做的事 伺服器:以用戶端實測的各區域 ping 取代 GeoIP 來分配,擴大到遠方區域的規則要設 ping 上限,隊伍除了平均值也要看最高的隊友 ping,把分配的區域與當時的 ping 記錄到 log。用戶端:用 UDP 測量各區域 ping 並隨配對請求一起送出,在畫面上顯示連線的區域與 ping,提供自行選擇區域的選項。
基礎設施團隊要做的事 若用 DNS 選擇區域,確認權威 DNS 是否支援 EDNS Client Subnet(玩家使用的解析器不傳送時,會依解析器位置分配),定期更新 GeoIP 資料庫,在各區域伺服器的連線 log 加上 GeoIP 國家與 ASN,找出被導向遠方區域的國家與電信業者。
外部要做的事 請玩家關掉 VPN、遊戲加速器後重新連線看看,請使用公司或海外 DNS 的玩家改用電信業者的 DNS 試試,向 GeoIP 業者申請更正錯誤的位置。
數值參考 首爾玩家沒被分到東京、而被分到美國西部區域時,ping 會從約 30ms 增加到約 130ms。GeoIP 以國家為單位約 99.8% 正確,但以城市為單位,即使在美國,落在 50km 內的比例也只有約 66%;使用 VPN 時,查到的會是 VPN 伺服器的位置。
圖表上 只有部分偏高 · 各玩家的 RTT(ping)、分配到的區域分布
查看位置 在各區域伺服器的連線紀錄(負載平衡器存取 log、VPC Flow Logs)中的用戶端 IP 加上 GeoIP 國家與 ASN,依國家、電信業者統計連到哪個區域。若是單一玩家,比較該玩家實際連線的區域,以及到近的區域實測的 ping(由玩家測量,或從該區域伺服器對玩家 IP 執行 mtr) 符合的跡象 RTT 高的玩家或國家沒連到近的區域、而是連到遠方區域,對近的區域實測的 ping 很低 不符合的跡象 已正確分配到近的區域但 ping 仍高時,是繞遠路的路由或該玩家的線路、Wi-Fi 問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 用 DNS 選擇區域的方式(依地理位置、延遲的 DNS),推測位置時看的是玩家所用 DNS 解析器的位址。解析器若不支援傳遞部分玩家位址的 EDNS Client Subnet,使用公司 DNS 或遠方 DNS 的玩家就會以解析器所在地為準來分配。配對系統也可能以隊友 ping 的平均值判斷整個隊伍,或在等待太久時放寬 ping 標準,分配到遠方區域。AWS GameLift Servers 對隊伍 ping 的預設基準也是平均值,並舉了把 ping 上限從 50ms 放寬到 100ms、200ms 的設定為例。開啟 VPN 的玩家可能同時遇到經過中繼伺服器而增加的延遲(「經由 VPN/遊戲加速器」)與被分配到遠方區域,可以看關掉 VPN 重新連線後分配到的區域是否改變來區分。附近根本沒有區域、只能連到遠方區域的情況,在「傳播延遲(物理距離)」說明。
出處 8 筆
TLS 憑證過期/設定錯誤 TLS certificate expiry / misconfiguration
ID in-cert · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
登入、API、更新伺服器的憑證過期或缺少中繼憑證時,從那一刻起新連線的用戶端 TLS 連線都會失敗。
為什麼 憑證超過有效期限、伺服器送出時少了中繼憑證,或玩家裝置的日期時間錯誤 → 於是 用戶端憑證驗證失敗,中斷 TLS 連線 → 畫面上 在登入、更新階段連不上/無限讀取,只有商城等 HTTPS 功能失敗。已經連線的人大多正常
症狀 連不上/無限讀取 , 吃指令/回檔
因素 停滯
誰會遇到 整個伺服器, 只有特定功能, 只有我
何時 剛登入/維護剛結束, 做特定動作時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 把憑證錯誤記錄成與其他連線失敗區分開的錯誤碼並提示玩家;若是日期錯誤,提示玩家把裝置的日期時間設為自動;使用憑證釘選(pinning)時一併放入備用金鑰,並與基礎設施團隊協調憑證更換時程。
基礎設施團隊要做的事 網路:在負載平衡器、CDN 終止 TLS 時,監控受管憑證的自動續約狀態,剩餘天數不足時發出警示(ACM 為 DaysToExpiry),並保留驗證用的 DNS 記錄。伺服器設備/OS:在伺服器終止 TLS 時,自動化續約並在續約後重新載入設定,設定包含中繼憑證的憑證鏈,從外部定期檢查每個登入、API、更新網址的剩餘有效期並發出警示。
數值參考 Let’s Encrypt 的憑證效期為 90 天,建議每 60 天續約;AWS Certificate Manager 會在到期前 45 天檢查以 DNS 驗證的憑證並自動續約。自動續約默默失敗時,會剛好在到期時間點讓新連線一起被擋。
圖表上 連線同時大量中斷 · 登入成功數、TLS 交握錯誤數
查看位置 用 openssl s_client -connect HOST:443 -showcerts 查看伺服器實際送出的憑證清單,並用 openssl x509 -noout -enddate 確認每張憑證的到期日(notAfter)。若在負載平衡器終止 TLS,看 TLS 協商錯誤數(AWS ALB、NLB 為 ClientTLSNegotiationErrorCount)與登入成功數 符合的跡象 到期日已過,或伺服器送出的清單中缺少中繼憑證,且錯誤開始增加的時間點與到期時間或更換憑證的時間重疊 不符合的跡象 憑證清單與到期日都正常、只有部分玩家失敗時,查看這些玩家裝置的日期時間,或舊版 OS 的根憑證清單 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 缺少中繼憑證的設定,用電腦瀏覽器開啟時可能看起來正常。瀏覽器會記住從其他網站取得的中繼憑證來補上缺口,但像 Android App 這樣沒有這種記憶的用戶端就會失敗。有效期也在縮短。Let’s Encrypt 預計把預設有效期在 2027 年縮短為 64 天、2028 年縮短為 45 天,固定每 60 天續約的設定遇到 64 天的憑證只剩四天餘裕,遇到 45 天的憑證則會超過到期日。AWS Certificate Manager 也不會自動續約匯入(import)的憑證,刪除驗證用的 DNS 記錄也會導致續約失敗。登入被擋的樣子和「DNS 故障與延遲」類似,差別在於憑證問題是找到伺服器位址之後在 TLS 交握(handshake)時失敗,開始時間也與到期時間或更換憑證的時間重疊。
出處 12 筆
登入排隊上限與重新連線寬限不足 Login queue cap / no reconnect grace
ID in-login-queue · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
上市或維護剛結束時連線湧入,登入排隊碰到上限就拒絕新的排隊,正在排隊的玩家只要短暫斷線就會失去位置,回到隊伍最後面。
為什麼 想連線的人比登入伺服器一次能接受的人數多,所以設排隊;排隊太長時,為了保護伺服器會拒絕新的排隊 → 於是 排隊越長等待時間越久,這段期間 Wi-Fi、行動網路只要短暫斷線就會失去排隊位置 → 畫面上 連不上/無限讀取、排隊中出現錯誤並關閉遊戲、又要從最後面重新排隊
症狀 連不上/無限讀取 , 斷線
因素 停滯
誰會遇到 整個伺服器, 只有我
何時 剛登入/維護剛結束, 晚間尖峰時段
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 伺服器:把排隊上限配合登入伺服器實際能處理的量,排隊中斷線的玩家保留位置一段時間(重新連線寬限),顯示順位與預估等待時間,把排隊長度、拒絕數、排隊中斷線次數記為指標。用戶端:排隊中斷線時不關閉遊戲,自動重新連線回到原來的位置,重試間隔以指數退避加上抖動(jitter)打散。
基礎設施團隊要做的事 伺服器設備/OS:上市前以負載測試量出登入、大廳伺服器的處理上限,上市時準備好可隨時加上的備用設備,把排隊指標與連線嘗試數放在同一張圖表上看。
數值參考 2021 年 FINAL FANTASY XIV 資料片上市時,每個邏輯資料中心排隊人數超過 17,000 人就會拒絕新的排隊(Error 2002)。排隊中斷線時,大廳伺服器會等待數十秒~1 分鐘,在這段時間內重新連上就能從排隊中段接續。
圖表上 碰到上限後持平 · 登入排隊長度、因達上限而拒絕的數量、排隊中斷線次數
查看位置 把登入、大廳伺服器記錄的排隊長度、平均等待時間、因達上限而拒絕的數量、排隊中斷線次數,與連線嘗試數放在同一張圖表上看 符合的跡象 上市或維護剛結束時,排隊長度碰到上限而持平,同時拒絕數增加,排隊中斷線集中在 Wi-Fi、行動網路的玩家 不符合的跡象 排隊很短但登入很慢時,是 DB(db-login-storm)或作業系統連線等待佇列(so-backlog)的問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 登入湧入讓 DB 變慢的情況在「登入暴增與 N+1 查詢」說明,作業系統的連線等待佇列滿出來的情況在「連線等待佇列(backlog)溢位」說明。本項談的是遊戲刻意設計的登入排隊在設計上的問題。排隊上限是保護登入伺服器的安全機制,無法拿掉。因為要及早拒絕超出的請求,才能持續處理還處理得了的請求。重點在於減少拒絕與斷線對玩家造成的損失;排隊越長,錯誤就越集中在 Wi-Fi、行動網路這類線路不穩定的玩家身上。
實際案例 Square Enix 2021: FINAL FANTASY XIV 資料片上市的壅塞與登入排隊錯誤
出處 2 筆
同步設計
16 個原因 · 完整版章節
伺服器回應後才演出(請求-回應方式) Request-response (no client-side feedback)
ID sy-request-response · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
按下按鈕後,在伺服器回應之前既沒有動畫也沒有音效。ping 直接就是反應速度。
為什麼 技能、移動、撿取都等伺服器確認後才播放 → 於是 從按下的瞬間起,在往返時間 + tick 等待這段期間毫無反應 → 畫面上 ping 150ms 時,每個動作都慢 0.2 秒
症狀 輸入延遲
因素 延遲
誰會遇到 只有我
何時 一直都有, 做特定動作時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:動畫、音效、特效在按下時立即開始(先行演出),只有結果(傷害、獎勵)等伺服器確定後才顯示;移動與普通攻擊先預測並立即反映;收到伺服器的位置校正時,從該位置重新套用尚未獲得確認的輸入。伺服器:用收到的輸入自行計算移動,只在與用戶端預測位置的差距超過門檻時才送出校正值。
數值參考 反應時間 ≈ ping + tick 間隔的一半 + 一個畫格。20 tick、ping 150ms 時約 190ms。
圖表上 一開始就一直偏高 · 從輸入到開始演出的時間、RTT(ping)
查看位置 在開發版本的用戶端 log 記錄按鈕輸入時間、第一個動畫/音效開始時間、伺服器回應抵達時間,並與遊戲內 RTT 對照。用引擎的網路模擬(Unreal NetEmulation.PktLag)或測試伺服器上 Linux 的 tc netem 加入延遲,改變 ping 反覆測量 符合的跡象 演出開始的時間點總是與伺服器回應抵達同一瞬間,從輸入到演出的時間約為 RTT + tick 等待,且隨加入的延遲等量增加 不符合的跡象 按下立即開始演出、只有傷害數字等結果較晚出現的話,是正常設計。ping 低的地方也慢了 tick 間隔以上時,是雙重 tick 等待或用戶端畫格的問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 回合制、卡牌、放置型這類不需要快速反應的遊戲,用這種方式最簡單也最安全。問題出在有即時操作的遊戲連移動或普通攻擊也這樣做的時候。
出處 5 筆
依序往返過多的協定(chatty) Chatty protocol / sequential round trips
ID sy-chatty · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
一次操作需要依序與伺服器往返好幾次時,ping 會乘上這個次數。
為什麼 開啟商店 → 請求清單 → 確認價格 → 購買 → 更新背包,每一步各自請求 → 於是 收到前一個請求的回應後才送出下一個請求 → 畫面上 ping 150ms 時買一次東西要將近 1 秒。載入特別久
症狀 輸入延遲 , 連不上/無限讀取
因素 延遲
誰會遇到 只有特定功能, 只有我
何時 做特定動作時, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:修改協定,把多個步驟合併成一次請求與回應(例:在購買回應中一併放入更新後的背包)。用戶端:預先取得需要的資料,採用不必等待結果的 UI。
數值參考 耗時 ≈ 往返次數 ×(ping + 伺服器處理 + tick 等待)。5 次的話,ping 150ms 時約 0.85~1 秒。
圖表上 一開始就一直偏高 · 各功能的完成時間、一次操作的往返次數
查看位置 在伺服器端的封包擷取(Wireshark)中,用測試帳號執行一次商店購買、登入之類的操作,計算期間請求與回應交替往返幾次及其間隔。有伺服器請求 log 的話,以 session ID 分組,查看請求數與每個請求的抵達、回應時間 符合的跡象 一次操作中,請求要等前一個回應後才依序往返多次,完成時間約為往返次數 × RTT,且 ping 越高的地區,玩家使用同一功能就越慢,大致成正比 不符合的跡象 往返只有一兩次、卻是某個回應花很久時,是伺服器處理或 DB 端的原因。與 ping 無關、所有玩家都一樣慢時,要查伺服器負載 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 1 筆
沒有技能預輸入 No input/spell queue
ID sy-no-queue · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
必須收到伺服器確認前一個技能已結束才能按下一個技能時,每次連段之間都會夾著一段往返時間。
為什麼 只在「前一個技能確定後」才接受下一個技能的輸入 → 於是 每個技能之間都空出一段 ping 長度的時間 → 畫面上 連段之間出現空檔,ping 越高 DPS 越低
症狀 輸入延遲 , 吃指令/回檔
因素 延遲
誰會遇到 只有我, 只有特定功能
何時 做特定動作時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:設定預輸入容許時間,冷卻結束前一段時間(例:0.3~0.4 秒)內的輸入也接受並立即送給伺服器。伺服器:稍微提早抵達的輸入不要拒絕,在冷卻結束的瞬間執行。
數值參考 冷卻 1 秒的連段在 ping 150ms 時,每個技能之間會空出 0.15 秒以上,同樣時間內施放的技能數減少超過 13%。
圖表上 一開始就一直偏高 · 技能之間的空檔、RTT(ping)
查看位置 在伺服器 log 中依角色記錄技能冷卻結束時間、下一個技能請求抵達時間與執行時間,把中間的空檔與玩家 RTT 比較 符合的跡象 從冷卻結束到下一個技能執行之間總是空出約 RTT 的時間,ping 越高的玩家空檔越長、同樣時間內施放的技能越少 不符合的跡象 空檔與 ping 無關、固定不變時,是公共冷卻或動畫長度的設計。空檔只是偶爾大幅飆高時,要查抖動、封包遺失或超出 tick 預算 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 例如《魔獸世界》設有預輸入容許時間,並讓玩家可以在設定中調整。容許時間比往返時間長的話,連段之間就幾乎不會再夾著 ping 的等待。
出處 1 筆
被 ping 吃掉的短判定區間 Timing window too short for latency + reaction
ID sy-short-window · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
閃避、格擋、防禦這類需要反應的時間很短時,ping 會把這段時間吃掉,出現躲不掉的攻擊。
為什麼 像王的攻擊預兆 0.5 秒、格擋判定 0.2 秒這樣短的判定區間 → 於是 預兆較晚看到(下行延遲 + 內插),自己的輸入也較晚抵達(上行延遲 + tick 等待) → 畫面上 明明躲開了卻被打中,格擋被吃掉
症狀 吃指令/回檔 , 輸入延遲
因素 延遲
誰會遇到 只有我, 只有特定功能
何時 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 伺服器:以伺服器時間排程攻擊預兆並提前送出,把判定區間延長 ping 的長度(延遲補償)。用戶端:把收到的預兆配合排定的伺服器時間播放。
基礎設施團隊要做的事 在玩家多的地區附近部署伺服器(地區伺服器),從根本降低 ping。
數值參考 ping 150ms、內插 100ms 時,預兆出現在自己畫面上約需 0.18 秒,自己的輸入抵達伺服器約需 0.1 秒。再加上人的反應時間 0.25 秒,0.5 秒的預兆幾乎不可能躲開。
圖表上 只有部分偏高 · 閃避、格擋失敗率(依 ping 區間)
查看位置 在伺服器 log 記錄判定區間的開始與結束時間、玩家輸入抵達伺服器的時間、該玩家的 RTT,並把失敗率依 ping 區間(例:每 50ms 一級)分開來看 符合的跡象 ping 越高的區間失敗率明顯越高,失敗的輸入在判定區間結束後不久(RTT 加內插時間以內)才抵達 不符合的跡象 失敗率與 ping 區間無關、差不多時,是招式難度問題。輸入在判定區間內抵達卻仍判定失敗時,要查判定程式碼或伺服器驗證 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
沒有延遲補償的判定 Server-now hit validation
ID sy-no-lagcomp · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
伺服器只用「伺服器上現在的位置」判定命中時,判定會與自己看到的畫面不一致。
為什麼 自己畫面上的對手是約 0.2 秒前的位置(ping 150ms、內插 100ms 時) → 於是 伺服器以目前位置判定,對手早已不在自己瞄準的地方 → 畫面上 明明打中了卻判定落空。射擊移動中的目標要預留提前量
症狀 吃指令/回檔
因素 延遲
誰會遇到 只有我
何時 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:回溯到攻擊者當時看到的時間點再判定(延遲補償),或改成指定目標的方式。用戶端:攻擊時一併送出自己當時看到的時間點(正在內插的伺服器時間)。
圖表上 只有部分偏高 · 移動目標的命中率(依 ping 區間)
查看位置 在伺服器判定 log 中一併記錄攻擊時間、攻擊者畫面上的目標位置(用戶端送來的值)、判定時使用的伺服器端目標位置、攻擊者 RTT。在開發版本中把伺服器判定用的位置疊畫在用戶端畫面上,一眼就能看出 符合的跡象 落空的判定中,兩個位置的差距約為目標速度 ×(攻擊者 RTT + 內插時間),且 ping 越高,只有移動目標的命中率下降 不符合的跡象 靜止的目標也打不中時,是判定框(hitbox)或碰撞檢測的問題。有做回溯卻仍不一致時,要查用戶端是否把內插時間錯誤告知伺服器 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
延遲補償過度 Excessive lag compensation
ID sy-lagcomp-overreach · 主要負責 遊戲開發團隊(伺服器開發)
以攻擊者為準回溯得太遠時,被打的一方明明已經躲好了還是會中彈。
為什麼 為了 ping 高的攻擊者,伺服器大幅回溯後判定 → 於是 在被打的人的畫面上,早已躲進掩體 → 畫面上 「躲在牆後還被打中」,ping 高的人占優勢
症狀 吃指令/回檔
因素 延遲
誰會遇到 只有我, 特定地區/電信業者
何時 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 設定回溯上限(例:200~250ms),ping 比這更高的攻擊者只回溯到上限,其餘由攻擊者自己預留提前量。
圖表上 只有部分偏高 · 每次命中的回溯時間(依攻擊者 ping)
查看位置 在伺服器判定 log 中為每次命中記錄回溯時間、攻擊者 RTT、被打方進入掩體的伺服器時間。在開發版本把回溯後的判定框畫到畫面上(Source 引擎為 sv_showlagcompensation) 符合的跡象 「躲在牆後還被打中」回報中的命中集中在回溯時間長的攻擊者,且回溯時間沒有上限、隨攻擊者 ping 增加 不符合的跡象 回溯時間短的命中也出現牆後中彈時,是判定框或碰撞檢測的問題。被打方 ping 高時,是那個人的移動太晚抵達伺服器造成的 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 回溯判定是「射擊者優先」。也有人提出例外做法:被打的一方在自己畫面上已經進入安全處時就不回溯,也就是「被打者優先」。
出處 3 筆
用戶端權威 Client-authoritative results
ID sy-client-auth · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
各自決定自己的結果時,自己的畫面很順暢,但結果會與其他人的畫面不一致,也容易被外掛利用。
為什麼 位置、命中由用戶端決定,伺服器只負責轉送 → 於是 兩個人都聲稱自己先打中,伺服器無法驗證 → 畫面上 對手瞬移、穿牆,「我明明打中卻沒中」
症狀 瞬移 , 吃指令/回檔
因素 延遲
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:重要的結果(命中等)由伺服器自行驗證,移動要檢查速度與距離。用戶端:收到伺服器拒絕或校正的結果時,改回伺服器給的值。
圖表上 一開始就一直偏高 · 不可能的移動速度、互相矛盾的命中回報數
查看位置 在伺服器端原樣記錄用戶端回報的位置與命中,用連續的位置回報計算移動速度,統計超過最大速度的回報,以及兩人都說自己先打中的回報 符合的跡象 伺服器未經驗證就把回報轉送給其他用戶端,不可能的速度或互相矛盾的命中回報持續出現,與更新、地區無關 不符合的跡象 伺服器自行計算或驗證結果時,就不是這個原因。這時的瞬移要查封包遺失或內插緩衝 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
Lockstep 中等待最慢的玩家 Lockstep waits for the slowest peer
ID sy-lockstep · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
在所有人一起計算同一回合的架構中,只要一個人的輸入晚到,所有人都要等。
為什麼 每回合要收齊所有玩家的輸入才能計算 → 於是 某個人的輸入因抖動或封包遺失而晚到 → 畫面上 所有人同時頓一下,嚴重時跳出「等待玩家中」視窗
症狀 定格 , 卡頓 , 輸入延遲
因素 抖動, 遺失, 停滯
誰會遇到 特定地點/頻道
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:依 ping 自動調整輸入延遲,只讓落後的人暫時脫隊,其他人不必等待、繼續進行。用戶端:套用設定好的輸入延遲;若是沒有中繼伺服器的 P2P,輸入延遲的調整與落後者的處理也由主機用戶端負責。
數值參考 輸入延遲設得比「輸入抵達對方的時間 + 抖動」短時,停頓會變頻繁。抵達時間在雙方直接傳送時約為 ping 的一半,經過中繼伺服器時約為兩人 ping 相加的一半。
圖表上 偶爾隨機飆高 · 回合等待時間、各玩家的輸入抵達延遲
查看位置 每回合記錄各玩家的輸入抵達時間與回合停下等待的時間,查看停住的回合在等誰的輸入。有中繼伺服器的話,也可以從伺服器端封包擷取中各玩家輸入封包的抵達間隔來看 符合的跡象 每次停住的回合,都是同一個人的輸入比輸入延遲還晚抵達,且當時那個人的抖動、封包遺失飆高 不符合的跡象 輸入都準時到卻仍停住時,是最慢那台電腦的計算時間或伺服器處理問題。沒有停住、只有兩邊畫面的結果不同時,是計算結果不一致(desync),要查指令同步的路徑計算不一致 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
ID sy-rollback · 主要負責 遊戲開發團隊(用戶端開發)
先預測對手的輸入並呈現出來,猜錯時就回溯重新計算。ping 越大,回溯的幅度越大。
為什麼 對手改變輸入(與預測不同) → 於是 實際輸入晚了 ping 的一半才抵達,於是回溯這段時間重新計算 → 畫面上 對手的動作跳過幾個畫格或突然改變
症狀 瞬移
因素 延遲, 抖動
誰會遇到 只有我
何時 做特定動作時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 搭配 1~3 個畫格的輸入延遲以縮小回溯幅度,並設定回溯上限。
數值參考 ping 100ms(單向 50ms)時,在 60fps 下約回溯 3 個畫格。加上 2 個畫格的輸入延遲,就減少到 1 個畫格。
圖表上 偶爾隨機飆高 · 回溯的畫格數、RTT(ping)
查看位置 由用戶端在每次回溯時記錄回溯的畫格數、當時的 RTT、輸入延遲設定、回溯與重新計算花費的時間 符合的跡象 回報對手動作亂跳的瞬間,回溯畫格數很大;平均回溯幅度約為(單向延遲 − 輸入延遲)÷ 畫格時間,ping 越大幅度越大 不符合的跡象 回溯幅度小卻仍出現卡頓時,是重新計算超過一個畫格時間的效能問題。回溯後兩邊畫面的結果仍持續不同時,是計算結果不一致(desync) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
沒有時間戳記、一到就播放 Events played on arrival (no timestamps)
ID sy-no-timestamp · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
伺服器事件沒有附上發生時間、一收到就播放時,網路抖動會讓演出時機跟著忽快忽慢。
為什麼 「開始攻擊」、「播放特效」事件一抵達就執行 → 於是 每個封包的抵達時間不同,間隔忽長忽短 → 畫面上 連續攻擊動作忽快忽慢,王的招式時機每次都不一樣
症狀 卡頓 , 快轉
因素 抖動
誰會遇到 只有我
何時 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:依事件附帶的時間播放(事件排程、內插緩衝)。伺服器:在事件上附上發生時間(伺服器時間)再送出。
圖表上 偶爾隨機飆高 · 事件播放間隔、封包抵達間隔
查看位置 用事件編號對齊伺服器 log 的事件發生時間與用戶端 log 的抵達、播放時間,比較間隔。在開發版本加入抖動(tc netem 的抖動值、Unreal 網路模擬的最小/最大延遲)來重現 符合的跡象 伺服器上的發生間隔固定,播放間隔卻完全跟著抵達間隔忽長忽短 不符合的跡象 抵達間隔均勻、播放卻忽快忽慢時,是用戶端畫格的問題(畫格時間尖峰)。伺服器的發生間隔本身就不穩時,是超出 tick 預算 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 5 筆
雙重 tick 等待 Double tick quantization
ID sy-double-tick · 主要負責 遊戲開發團隊(伺服器開發)
請求先累積到下一個 tick 才處理,結果又等到再下一個 tick 才送出時,tick 間隔會被加上兩次。
為什麼 收到的請求在下一個 tick 處理 → 於是 處理結果也累積到下一個傳送 tick 才送出 → 畫面上 線路 ping 很低,反應卻固定慢了約 tick 間隔的 1.5 倍。10 tick 伺服器平均 0.15 秒,最差 0.2 秒
症狀 輸入延遲
因素 延遲
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 在處理的那個 tick 立即送出回應、提高 tick rate、重要的回應立即傳送。
數值參考 10 tick 伺服器一個 tick 是 100ms,光是 tick 等待平均就多出 150ms,最差多出 200ms。只等一次的話平均是 50ms。
圖表上 一開始就一直偏高 · 從請求抵達到送出回應的時間
查看位置 在伺服器端的封包擷取中,讓測試帳號重複做同一個動作(例:使用道具),測量請求封包抵達時間與對應回應封包送出時間的間隔。有伺服器 log 的話,查看請求抵達時間、處理的 tick 編號、送出回應的時間 符合的跡象 伺服器內部花費的時間平均約為 tick 間隔的 1.5 倍、最多約 2 倍,且與 RTT 無關、固定不變 不符合的跡象 伺服器內部時間平均在 tick 間隔的一半左右時,tick 等待只有一次。比 tick 間隔長且忽長忽短時,要查超出 tick 預算 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
過於嚴格的伺服器驗證 Over-strict server validation
ID sy-strict-check · 主要負責 遊戲開發團隊(伺服器開發)
伺服器對移動速度、冷卻時間、射程檢查得太嚴格時,連因抖動而擠在一起抵達的正常輸入也會被拒絕。
為什麼 「一個 tick 內可移動的距離」、「冷卻時間容許誤差 0ms」這類嚴格標準 → 於是 因抖動使兩個指令擠在同一個 tick 抵達時,就被判定為違規 → 畫面上 拉回,冷卻好了技能卻被拒絕
症狀 拉回 , 吃指令/回檔
因素 抖動
誰會遇到 只有我
何時 偶爾隨機發生, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 以累積容許量(token bucket)方式檢查,保留 ping 與抖動的餘裕。
圖表上 偶爾隨機飆高 · 伺服器驗證拒絕、位置校正次數
查看位置 在伺服器 log 中,每次驗證拒絕或位置校正都記錄原因、該 tick 抵達的該玩家指令數、與前一個指令的抵達間隔 符合的跡象 拒絕與校正集中在一個 tick 內擠進 2 個以上指令的時刻,而以數秒為單位加總的移動量、使用次數都在規則範圍內 不符合的跡象 以數秒為單位加總仍超出規則時,可能真的是加速或作弊。拒絕集中在特定電信業者與晚間時段時,是集中在特定電信業者玩家的驗證誤判 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
主機(房主)架構 Listen server / host advantage
ID sy-host · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
由某個玩家的電腦擔任伺服器時,那個人的線路與電腦效能決定了所有人的體感。
為什麼 房主的電腦擔任伺服器(P2P、listen server) → 於是 房主的線路或電腦慢時會影響所有人,房主本人 ping 為 0 → 畫面上 只有房主占優勢,房主離開時所有人定格、斷線
症狀 卡頓 , 定格 , 斷線
因素 延遲, 停滯
誰會遇到 特定地點/頻道
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 伺服器:改用負責判定的專用伺服器;在那之前,配對時選線路與電腦較好的人當房主。用戶端:支援主機轉移(migration),配對時測量與其他參與者之間的 ping、上傳速度與電腦效能並回傳。
基礎設施團隊要做的事 準備專用伺服器用的伺服器設備與執行個體,部署在玩家多的地區附近。
圖表上 只有部分偏高 · 各房主的 lag 回報、斷線次數
查看位置 在對戰 log 記錄房主(主機)的上傳速度、各參與者與房主之間的 RTT、房主電腦的畫格時間、房主離開的時間,並把 lag 與斷線回報依房主分組來看。玩家也可以讓同一批人只換房主再玩一次來確認 符合的跡象 lag 與斷線集中在特定房主的房間,該房主上傳速度低或畫格時間長時所有參與者一起變差;沒有主機轉移時,房主離開的瞬間所有人都斷線 不符合的跡象 與房主無關、只有同一地區的參與者變差時,是線路或路由問題。若是專用伺服器架構,就不是這個原因 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
先行演出後遭伺服器拒絕 Client-side feedback rejected by server
ID sy-optimistic-reject · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
自己畫面上先呈現的打擊、技能,事後沒有被伺服器認可時,明明看到的結果就變成沒發生過。
為什麼 在伺服器確認前先播放打擊特效與技能動作(先行演出) → 於是 伺服器重新檢查射程、目標位置、冷卻與資源後拒絕 → 畫面上 噴血了卻沒有傷害,技能只有動作沒有效果,只有冷卻在跑
症狀 吃指令/回檔 , 拉回
因素 延遲
誰會遇到 只有我, 只有特定功能
何時 做特定動作時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:只有傷害數字、死亡、獎勵這類需要確定的部分才依伺服器結果顯示,常見的拒絕原因先在本地檢查,被拒絕時還原冷卻與資源並顯示原因。伺服器:射程與目標位置檢查保留 ping 的餘裕,在拒絕回應中附上原因,收集各技能的拒絕比例作為指標。
數值參考 拒絕回應會在按下後晚 ping + tick 等待的時間才到。ping 150ms 時,約有 0.2 秒會以為「打中了」。
圖表上 只有部分偏高 · 各技能的伺服器拒絕比例(依 ping 區間)
查看位置 在伺服器端收集各技能的拒絕比例與拒絕原因(射程、目標位置、冷卻、資源),並依玩家 RTT 區間分開。在用戶端記錄先行演出的動作被拒絕的次數 符合的跡象 拒絕集中在特定技能以及射程、目標位置類原因,ping 越高拒絕比例越高 不符合的跡象 拒絕原因是冷卻、資源且與 ping 無關時,要查用戶端與伺服器的資料值(冷卻、消耗)是否不同。沒有拒絕、演出卻在伺服器回應後才開始時,是伺服器回應後才演出(請求-回應方式) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 先行演出是遮蓋 ping 最好的方法。只是用戶端與伺服器用來判斷的資訊(對手位置、剩餘資源)差異越大,拒絕就越頻繁。把各技能的拒絕比例收集成指標,就容易找出判定不一致的地方。
出處 2 筆
指令同步的路徑計算不一致 Command sync with divergent pathing
ID sy-path-mismatch · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
只互傳「走到這裡」、路徑由兩邊各自計算時,計算只要有一點不同,角色或怪物就會走上不同的路徑,再被拉回原位。
為什麼 點擊移動、怪物追擊時只送目的地,路徑由用戶端另外計算 → 於是 因地形資料差異、與其他角色碰撞、計算順序不同,走上與伺服器不同的路徑 → 畫面上 怪物穿牆走到一半一下子被移走,點擊移動的角色像滑行般轉向
症狀 瞬移 , 拉回
因素 延遲
誰會遇到 特定地點/頻道, 只有我
何時 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:連同路徑的中間點(waypoint)一起送出,定期同步位置。用戶端:差異要平滑收斂,使用與伺服器相同的地形資料。
圖表上 偶爾隨機飆高 · 各物件的位置校正次數、距離
查看位置 為每個物件記錄伺服器送來的位置與用戶端計算位置的差距,並把發生校正的座標標在地圖上。把兩邊的路徑結果或位置彙整成檢查碼(checksum)定期比較,就能找出開始出現差異的時間點 符合的跡象 校正集中在特定地形(門檻、狹窄通道、斜坡)或擁擠的地方,網路指標正常的玩家也會在同一個位置反覆發生 不符合的跡象 與地點無關、只在封包遺失或抖動飆高的瞬間才校正時,是線路問題。一隻怪物在多人畫面上同時亂跳時,要查怪物控制權是否在慢速用戶端上 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 點擊移動、Tab 鎖定目標的遊戲對 ping 不敏感,原因之一就是這種方式。代價是無法保證兩邊結果相同,一定要有不時對齊位置的機制。浮點數運算的結果可能依 CPU 種類、編譯器及其最佳化設定(包括 debug 與 release 建置的差異)而有些微不同。在 lockstep、rollback 這類只交換輸入、假設兩邊計算結果完全相同的架構中,這些小差異會累積起來,可能讓兩邊畫面的遊戲狀態分歧,造成不一致(desync)。
出處 6 筆
快照傳送頻率太低 Low snapshot / update rate
ID sy-low-send-rate · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
伺服器每秒只送幾次位置更新(快照)時,內插緩衝就得相應拉長,看到的其他角色會是更久以前的狀態。
為什麼 為了節省傳輸量,每秒只送 5~10 次位置更新 → 於是 要畫得流暢,緩衝就得設成封包間隔的 2 倍(200~400ms);設得短的話,只漏掉一個封包就會停住 → 畫面上 對手轉向較晚才看到,與判定不一致。緩衝短時會卡頓,封包遺失時出現瞬移
症狀 卡頓 , 瞬移 , 吃指令/回檔
因素 延遲, 遺失
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:近距離或戰鬥中的目標送得頻繁、遠處目標送得少;只送有變化的部分(差異壓縮),縮小單次大小並提高頻率。用戶端:依封包間隔自動調整內插緩衝長度。
數值參考 每秒 10 次的話封包間隔 100ms、緩衝 200ms。再加上 ping 150ms 的單向延遲 75ms,看到的對手約是 0.3 秒前的狀態。
圖表上 一開始就一直偏高 · 各用戶端的封包抵達間隔、內插緩衝長度
查看位置 在伺服器端封包擷取中只篩選送往某位玩家的流量,用 Wireshark 的 I/O Graphs 查看每秒封包數與間隔。有遊戲端 log 的話,同時查看各物件的更新間隔與用戶端內插緩衝的餘裕(距離下一個快照抵達的剩餘時間) 符合的跡象 位置更新一直很稀疏,每秒 5~10 次(間隔 100~200ms),內插緩衝設得超過 200ms,或緩衝餘裕經常歸 0 不符合的跡象 更新送得很密、只有抵達間隔不穩時,是抖動或封包遺失。人多擁擠時只有遠處物件收得少,是各連線的傳送預算與優先順序 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 4 筆
只有部分人遇到的問題
24 個原因 · 完整版章節
慢的人在別人畫面上快轉移動 Laggy player seen by others (bursty inputs)
ID pt-slow-burst · 主要負責 遊戲開發團隊(伺服器開發) · 協同 外部(外部)
線路差的人,輸入會忽快忽慢、成批抵達伺服器。伺服器每個 tick 收到多少就套用多少時,在其他人眼中,那個角色會頓一下後一次走好幾步。
為什麼 慢的人的移動指令,有的 tick 抵達 0 個,有的 tick 一次抵達 2~3 個 → 於是 伺服器在收到的 tick 一次全部套用,那個角色的位置呈階梯式變化 → 畫面上 在其他人畫面上,只有那個角色頓一下後一次快轉移動。其他都正常
症狀 快轉 , 瞬移
因素 抖動, 遺失
誰會遇到 只有特定角色看起來怪怪的, 特定地區/電信業者
何時 一直都有, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 外部(外部)
遊戲開發團隊要做的事 用每位玩家各自的輸入緩衝把指令平均分配套用,依輸入序號按原本的間隔套用;只加長其他人畫面上的內插緩衝並不夠(因為伺服器記錄的位置本身就是階梯狀)。
外部要做的事 引導慢的玩家改用有線連線,並檢查 Wi-Fi 與分享器。
數值參考 抖動 80ms 時,在 20 tick(50ms)伺服器上,每個 tick 的指令數會在 0~3 個之間波動。
圖表上 只有部分偏高 · 各玩家每個 tick 套用的指令數、各玩家的抖動
查看位置 在伺服器端封包擷取中只篩選被回報玩家送出的封包,計算每個 tick 間隔(例:50ms)抵達幾個,並與其他玩家比較。有伺服器 log 的話,查看各玩家每個 tick 套用的移動指令數與輸入序號 符合的跡象 只有被回報玩家的封包在每個 tick 間 0 個與 2~3 個之間跳動、成批抵達,且該玩家的抖動、封包遺失偏高,其他玩家的封包則均勻抵達。該玩家改用有線後會減少 不符合的跡象 多個角色同時快轉時,是伺服器 tick 延遲或觀看者那端的線路。抵達與套用都均勻、卻只有那個角色看起來亂跳時,是觀看端的內插或顯示問題 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 在伺服器權威架構下,這是正常行為。一個慢的人造成的 lag,在別人眼中只會呈現為「那個人動作怪怪的」,不會影響其他人的操作或怪物的動作。只是與那個人直接往來的事(交易、隊伍機制、PvP 判定)也會跟著延遲。
出處 3 筆
一到就處理的伺服器造成快轉 Event-driven processing of bursty inputs
ID pt-event-server · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
封包一抵達就立即處理並通知的伺服器,會把慢的人成批湧入的動作接連立即執行。
為什麼 慢的人的技能、移動請求成批抵達 → 於是 伺服器一收到就依序執行,並立即通知所有人 → 畫面上 在其他人眼中,那個人在一瞬間放出好幾個技能,或像快轉一樣移動
症狀 快轉
因素 抖動
誰會遇到 只有特定角色看起來怪怪的
何時 做特定動作時, 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:依動作附帶的輸入時間間隔執行(時間只在容許範圍內才採信),或把成批湧入的動作按最小間隔(公共冷卻)錯開依序執行,不要直接拒絕;不要只看抵達時間做冷卻檢查(正常輸入會被吃掉)。用戶端:在動作上附上輸入時間再送出。
圖表上 只有部分偏高 · 各玩家的動作執行間隔
查看位置 在伺服器 log 記錄各玩家動作的抵達時間、執行時間、用戶端附上的輸入時間(若有),比較執行間隔與輸入間隔。同時在伺服器端封包擷取中查看該玩家封包的抵達間隔 符合的跡象 輸入間隔正常,伺服器的抵達與執行間隔卻擠在幾 ms 內,且擠在一起的時刻與其他人回報快轉的時間重疊 不符合的跡象 輸入時間的間隔本身就擠在一起時,是用戶端或巨集的問題。伺服器執行間隔均勻、只有在別人畫面上看起來擠在一起時,是觀看者的線路 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
各玩家的輸入緩衝大小 Per-player server input buffer (jitter buffer)
ID pt-input-buffer · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
伺服器替每個人暫存一點輸入、每個 tick 取出一個使用時,在其他人眼中很流暢,但本人的動作在伺服器上確定的時間點也會晚上這麼多。
為什麼 伺服器把慢的人的輸入存進緩衝,每個 tick 套用一個 → 於是 緩衝小時經常被取空,那個角色會停在原地,或由伺服器依最後一個輸入推測移動;緩衝大時,本人的輸入會較晚確定 → 畫面上 緩衝小時在別人眼中會頓一下,緩衝大時本人的技能結果較晚出現(輸入延遲)
症狀 卡頓 , 輸入延遲
因素 抖動
誰會遇到 只有特定角色看起來怪怪的, 只有我
何時 一直都有
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:依每個人的線路狀態自動調整緩衝大小,積壓時一次取出兩個追上進度,並指示緩衝經常取空的人的用戶端提早送出輸入。用戶端:依伺服器指示,把輸入再提早一點送出(調整用戶端時間)。
數值參考 依遊戲而異,通常是 1~3 tick 的量。VALORANT 的 128 tick 伺服器把伺服器緩衝壓得更短,平均只有半個畫格(約 4ms)。常見做法是自適應,只替抖動大的人加大緩衝。
圖表上 只有部分偏高 · 各玩家的輸入緩衝長度、取空次數
查看位置 在伺服器上依玩家記錄每個 tick 輸入緩衝中剩餘的輸入數、緩衝取空而依最後輸入推測補上的次數、從輸入抵達到套用所花的時間 符合的跡象 緩衝小的人取空次數多,且在那些時刻於別人畫面上短暫停住;緩衝大的人從輸入到套用的時間則多了一個緩衝長度 不符合的跡象 緩衝幾乎不會取空、別人畫面上卻出現卡頓時,是觀看端的內插問題。緩衝很短、輸入延遲卻很大時,是 RTT 本身或雙重 tick 等待 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
集中在特定電信業者玩家的驗證誤判 Anti-cheat / movement validation false positives on bad ISPs
ID pt-isp-validation · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施)
線路抖動大的人,輸入會成批抵達,因此常被伺服器的速度、冷卻檢查攔下。
為什麼 特定電信業者、地區線路的抖動在晚間變大 → 於是 伺服器把成批抵達的正常輸入判定為加速或違反冷卻 → 畫面上 只有該電信業者的玩家出現拉回、技能被拒,嚴重時被伺服器踢出而斷線
症狀 拉回 , 吃指令/回檔 , 斷線
因素 抖動
誰會遇到 特定地區/電信業者, 只有我
何時 晚間尖峰時段, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 檢查改用數秒內的累積容許量,參考線路狀態(ping、抖動)放寬標準,強制斷線前先有警告階段,並用每位玩家各自的輸入緩衝把成批湧入的輸入平均分配到各 tick,從根本減少誤判。
基礎設施團隊要做的事 依時段確認各電信業者的遺失率與抖動分布並分享給遊戲開發團隊,檢查該電信業者區段的路由(雙向 mtr),必要時變更路由或向電信業者升級處理(escalation)。
圖表上 只在特定時段偏高 · 各電信業者(ASN)的驗證拒絕、強制斷線次數,各電信業者的抖動
查看位置 在伺服器的驗證拒絕、校正、強制斷線 log 加上連線 IP 所屬電信業者(ASN)與時間,依電信業者與時段統計。基礎設施團隊在同一時間往該電信業者方向執行雙向 mtr,查看抖動與封包遺失 符合的跡象 拒絕與強制斷線集中在特定電信業者、晚間增加,同一時間該電信業者的抖動也偏高,而以數秒為單位加總的移動量仍在規則內 不符合的跡象 與電信業者無關、只有特定帳號反覆出現時,可能真的是作弊。所有電信業者一起增加時,是伺服器 tick 落後、指令被集中套用的伺服器端原因(超出 tick 預算) 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
一個慢的隊友與王的機制 One laggy member in a synchronized mechanic
ID pt-raid-member · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
在所有人必須在指定瞬間一起反應的團隊副本機制中,一個慢的人反應太晚,就會讓整個隊伍失敗。
為什麼 「全員同時散開」、「由一人按下按鈕」這類共同機制 → 於是 慢的人較晚看到預兆,輸入也較晚抵達 → 畫面上 因為那一個人而團滅,其他隊友覺得「都是 lag 的人害的」
症狀 吃指令/回檔 , 輸入延遲
因素 延遲
誰會遇到 特定地點/頻道, 只有特定角色看起來怪怪的
何時 人潮湧入時, 做特定動作時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:機制判定區間保留 ping 的餘裕,預兆以伺服器時間提前送出,設計成一個人失敗不會導致團滅。用戶端:把收到的預兆配合伺服器時間播放。
圖表上 只有部分偏高 · 造成機制失敗的各玩家 RTT
查看位置 在伺服器機制 log 記錄造成失敗的玩家、該玩家的輸入抵達時間、判定區間、該玩家的 RTT 與封包遺失 符合的跡象 導致團滅的輸入大多來自同一個人,該玩家的 RTT 明顯高於隊伍平均,且輸入在判定區間剛結束時才抵達 不符合的跡象 失敗平均分散在隊友身上時,是判定區間本身太短的問題(被 ping 吃掉的短判定區間)。慢的人的輸入在判定區間內抵達卻仍失敗時,是伺服器判定程式碼 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
怪物控制權在慢速用戶端上 Monster movement delegated to a player client
ID pt-mob-control · 主要負責 遊戲開發團隊(伺服器開發)
有些遊戲為了減輕伺服器負載,把怪物移動的計算交給附近某位玩家的用戶端。那個人線路差時,該怪物在所有人的畫面上都會動得很怪。
為什麼 伺服器把怪物移動計算交給最近(或最先到)的玩家用戶端 → 於是 負責者的結果回報延遲,或成批抵達伺服器 → 畫面上 只有那隻怪物在周圍所有人畫面上頓一下後瞬移。負責者本人的畫面上卻正常
症狀 瞬移 , 卡頓 , 快轉
因素 抖動, 遺失
誰會遇到 只有特定角色看起來怪怪的, 特定地點/頻道
何時 一直都有, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把控制權交給線路好的人(以 ping、封包遺失為標準),回報中斷時由伺服器立即收回,王這類重要怪物由伺服器自行計算。
圖表上 只有部分偏高 · 各怪物的位置回報間隔(依擁有控制權的用戶端)
查看位置 在伺服器上為每隻怪物記錄擁有控制權的用戶端,以及該用戶端的回報間隔、RTT、封包遺失。也可以從伺服器端封包擷取查看該用戶端送出封包的抵達間隔 符合的跡象 動作異常的怪物,控制權全都在同一個人手上,該玩家的回報間隔忽長忽短或中斷,把控制權交給別人後立即恢復正常 不符合的跡象 伺服器自行計算的怪物也一樣亂跳時,是伺服器 tick 延遲或觀看者那端的線路。轉移控制權後仍持續亂跳時,是指令同步的路徑計算不一致 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 負責的人自己覺得一切正常,所以回報只會是「怪物怪怪的」。如果除了一個人之外,所有人都看到同一隻怪物動作異常,要先確認那隻怪物的控制權在誰手上。
出處 2 筆
特定角色的資料過於龐大 One character with oversized data (inventory, mail, buffs)
ID pt-heavy-char · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
累積了數千個道具或信件,或好友、封鎖名單、buff 特別多的角色,在登入、儲存與通知周圍玩家時要處理的量是別人的好幾倍。與線路無關,只有用那個角色時才慢。
為什麼 練了很久的角色,背包、信箱裡累積了數千個道具或活動獎勵 → 於是 每次登入、切換地圖、儲存都要讀寫那麼多 DB 資料,要送給周圍的裝備與 buff 資訊也很大 → 畫面上 只有那個角色進場載入很久,開背包或信箱時會頓一下。若伺服器在遊戲執行緒上等待儲存完成,連周圍的人也會短暫定格
症狀 連不上/無限讀取 , 輸入延遲 , 定格
因素 停滯
誰會遇到 只有我, 只有特定功能
何時 剛登入/維護剛結束, 做特定動作時, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(DB 基礎設施)
遊戲開發團隊要做的事 設定背包與信件的保存上限並自動清理舊信件,只分批載入需要的部分,儲存只寫有變更的部分,並在遊戲執行緒以外進行。
基礎設施團隊要做的事 從慢查詢 log 找出同一角色反覆出現的慢查詢並轉給遊戲開發團隊,提供道具、信件資料列數最多的角色排行清單。
數值參考 若一個道具是 DB 的一列,擁有 5,000 個道具的角色每次登入就要讀 5,000 列,是一般角色的數十倍。
圖表上 只有部分偏高 · 各角色的登入、儲存時間,各角色的 DB 查詢資料列數
查看位置 在 DB 的慢查詢 log(MySQL slow query log、PostgreSQL log_min_duration_statement)中找出同一角色 ID 反覆出現的慢查詢與儲存,並列出道具、信件資料表中各角色資料列數的排行 符合的跡象 慢查詢集中在少數幾個角色 ID,這些角色的道具、信件資料列數是平均的數十倍,從其他電腦、線路登入也一樣慢 不符合的跡象 同帳號的其他角色或其他玩家也一起變慢時,是 DB 設備或鎖定的問題。那個角色在其他電腦上正常時,是玩家端環境 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 用同一個角色從其他電腦、線路登入也一樣慢,而同帳號的其他角色正常時,就要懷疑角色資料。這也是回報時一定要附上角色名稱的原因。
出處 3 筆
頻道、實例、相位不同 Different channel / instance / phase
ID pt-phase · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
兩個角色在不同的頻道或實例(instance),或處在依任務進度決定能看到哪些 NPC 的不同「相位」時,看到的是不同的世界。
為什麼 第二個角色被分配到其他頻道,或任務階段不同 → 於是 伺服器不會把該 NPC 送給那個角色(正常) → 畫面上 只有一邊沒有 NPC。看起來像 bug,但符合設計
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 一直都有, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:把頻道、相位資訊送給用戶端,在 QA 檢查清單加入「確認兩個角色的頻道與任務階段」。用戶端:在畫面上顯示頻道與相位。
圖表上 只有部分偏高 · 各用戶端周圍的物件數、頻道與相位
查看位置 在遊戲畫面比較兩個角色的頻道編號與該任務的進行階段,調成相同的頻道與階段後再看一次。有伺服器物件傳送 log 的話,確認沒有把那個 NPC 送給該角色的原因(頻道、相位) 符合的跡象 兩個角色的頻道或任務階段不同,調成相同後就看得到 NPC 不符合的跡象 頻道與階段都相同、仍只有一邊沒有時,要查載入中抵達的出現通知被丟棄、剛進場時湧入的出現資訊遺失、視野登錄順序錯亂 確認方式 在玩家端環境確認
深入了解 也要確認任務進度是以帳號為單位還是以角色為單位儲存。同一帳號的兩個角色,一邊的進度可能會改變另一邊的相位。
出處 2 筆
載入中抵達的出現通知被丟棄 Spawn messages dropped before the client is ready
ID pt-loading-drop · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
一進入 zone,伺服器就送出周圍 NPC 的出現通知,但用戶端還在載入地圖,於是把通知丟掉。
為什麼 伺服器在進場處理後立即送出周圍物件的出現通知 → 於是 用戶端正在載入,訊息處理常式(handler)還沒準備好,於是丟棄通知 → 畫面上 伺服器當作已經送過,不會再送。在 NPC 離開視野再回來之前都看不見
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 剛登入/維護剛結束, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:載入結束後送出「準備完成」,或把載入中收到的封包先保存起來再處理。伺服器:收到「準備完成」後才傳送周圍資訊。
數值參考 同一台電腦上兩個用戶端同時載入,或正在載入的那一邊是背景視窗時,CPU 與磁碟要分著用,處理也受到限制,那一邊的載入可能拉長好幾倍。伺服器的進場處理變快時,也會讓同一個 bug 浮現。
圖表上 只有部分偏高 · 各用戶端的載入時間、載入中丟棄的訊息數
查看位置 把用戶端在載入中收到並丟棄的訊息數量與種類、載入完成時間,與伺服器送出出現通知的時間比較。在同一台電腦上讓兩個用戶端同時載入,或把正在載入的那一邊放到背景視窗,就容易重現 符合的跡象 看不見的 NPC 的出現通知伺服器有送,抵達時間在載入完成之前,且那段時間丟棄的訊息數增加。只發生在載入較久的那個用戶端 不符合的跡象 出現通知在載入完成後才抵達卻仍看不見時,是基準快照遺失或物件 ID 重複使用造成誤認。伺服器根本沒送該 NPC 的通知時,是視野登錄順序錯亂或頻道、實例、相位不同 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
視野登錄順序錯亂 Interest-management race on enter/leave
ID pt-aoi-race · 主要負責 遊戲開發團隊(伺服器開發)
角色登錄到視野格狀(grid)的瞬間,與 NPC 換到其他格子的瞬間重疊時,該 NPC 的出現通知可能會漏掉。
為什麼 進場、換頻道、傳送的處理與 NPC 移動在同一瞬間重疊 → 於是 在「新進入視野的物件」計算中漏掉了那個 NPC → 畫面上 只有特定幾隻 NPC 看不見,或早已離開的 NPC 還留著
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 移動中/切換地圖時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 視野更新以單一執行緒、單一順序處理,並定期重新對齊整份「可見清單」。
圖表上 偶爾隨機飆高 · 伺服器可見清單與用戶端物件清單的差異數
查看位置 在伺服器上連同 tick 編號記錄視野格狀登錄、物件換格子、出現與消失通知的發送,並定期比較伺服器的「可見清單」與用戶端持有的清單 符合的跡象 漏掉的 NPC 在該角色進場或傳送處理的同一個 tick 換了格子,且沒有對該 NPC 發送出現通知的紀錄 不符合的跡象 出現通知有送、但用戶端沒收到或丟掉時,是傳遞環節的問題(剛進場時湧入的出現資訊遺失、載入中抵達的出現通知被丟棄)。總是同一隻 NPC 不見時,是相位或顯示選項不同 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
基準快照遺失 Lost baseline for delta compression
ID pt-baseline · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
在伺服器只送「與上次不同的部分」的方式中,最初送一次的完整資訊(基準)遺失時,之後的變化量就無法套用。
為什麼 物件的完整資訊(基準)封包遺失,或在處理前被丟棄 → 於是 用戶端沒有可以套用後續變化量的對象,只好忽略 → 畫面上 那個物件看不見,或過了很久才突然出現
症狀 看不見/幽靈物件 , 瞬移
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:基準在收到接收確認(ACK)前一定要重傳,變化量只針對用戶端已確認收到的基準產生。用戶端:基準實際套用後才送出接收確認(ACK),收到未知物件的變化量時向伺服器重新請求。
圖表上 偶爾隨機飆高 · 收到未知物件變化量的次數
查看位置 把用戶端在沒有基準時丟棄變化量的次數與物件 ID,與伺服器送出該物件基準、收到 ACK 的時間對照。在開發環境加入封包遺失(tc netem 的 loss、Unreal 網路模擬的封包遺失比例)來重現 符合的跡象 對於看不見的物件,伺服器送了基準卻沒收到 ACK,仍持續只送變化量,而用戶端丟棄了這些變化量 不符合的跡象 基準已收到 ACK 並套用到用戶端、仍看不見時,是消失通知遺失或物件 ID 重複使用造成誤認 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 4 筆
消失通知遺失(幽靈物件) Missed despawn (ghost entity)
ID pt-ghost · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
反過來,漏掉「已消失」的通知時,早已死亡或離開的 NPC、玩家會只留在自己的畫面上。
為什麼 死亡、離場、離開視野的通知遺失或順序錯亂 → 於是 用戶端認為那個物件還在 → 畫面上 打了也沒反應的怪物、早已離開的玩家還站在原地
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 偶爾隨機發生, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:定期送出「目前可見清單」。用戶端:刪除清單上沒有的物件,應該在移動的物件若長時間沒有更新就隱藏。
圖表上 偶爾隨機飆高 · 只留在用戶端的物件數
查看位置 比較伺服器送來的「目前可見清單」與用戶端持有的物件清單,計算只存在於用戶端的物件,並以物件 ID 對照消失通知的發送與接收 log 符合的跡象 幽靈物件的消失通知伺服器有送,用戶端卻沒有接收紀錄,或消失通知比出現通知先到、順序顛倒 不符合的跡象 伺服器的可見清單裡也還留著那個物件時,是伺服器端漏了物件清理。剛有新物件以同一個 ID 出現時,是物件 ID 重複使用造成誤認 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
剛進場時湧入的出現資訊遺失 Initial spawn burst lost (unreliable channel, receive buffer, fragmentation)
ID pt-spawn-burst · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
踏進 zone 的瞬間,伺服器會一次送出周圍數十~數百個物件的出現資訊。若用不可靠(unreliable)通道送出,或在載入中無法讀取 socket 的期間接收緩衝區溢位,就會有一部分消失且不再重送。
為什麼 剛進場時,出現資訊在短時間內大量湧入 → 於是 載入中的用戶端太晚讀取 socket,使 OS 接收緩衝區溢位;或大型 UDP 封包被分段,只要遺失一個分段就整個消失。若是不可靠通道,也不會重送 → 畫面上 只有載入較慢的那個用戶端少了幾隻 NPC。離開視野再回來就看得到
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 剛登入/維護剛結束, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:出現與消失通知一律用保證重傳的可靠通道送出,初始資訊分批傳送。用戶端:在與載入分開的執行緒接收,並加大接收緩衝區。
數值參考 電腦的 UDP 接收緩衝區預設值依 OS 而異,大多為數十~數百 KB。人多的城鎮進場資訊若比這更大,只要因為載入而短暫沒讀 socket 就會溢位。
圖表上 剛開服或維護結束後暴增 · 剛進場時的接收量、出現通知遺漏數
查看位置 比較伺服器剛進場時送出的出現通知數與用戶端收到的數量,並查看是用哪種通道(可靠/不可靠)送出。在伺服器端封包擷取中查看剛進場時送往該玩家的量與被分段的封包(Wireshark 篩選器 ip.flags.mf == 1 || ip.frag_offset > 0) 符合的跡象 收到的數量少於送出數量,遺漏集中在剛進場湧入的區段,且是以不可靠通道送出或大封包被分段。在載入較慢的用戶端上更常發生 不符合的跡象 送出與收到數量相同卻看不見時,是收到後被丟棄(載入中抵達的出現通知被丟棄)或視野計算的問題。與剛進場無關、隨時都會遺漏時,是線路的封包遺失 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 4 筆
物件 ID 重複使用造成誤認 Entity ID reused without a generation counter
ID pt-id-reuse · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
死亡的 NPC 重新出現時,伺服器若再次使用同一個物件 ID,在這段期間漏掉消失通知的用戶端,就會把新的 NPC 誤認成舊的 NPC。
為什麼 NPC 死亡後以同一個物件 ID 重新出現 → 於是 漏掉消失通知的用戶端認為是「已知的物件」,忽略出現通知或維持死亡狀態 → 畫面上 只有一邊的畫面上沒有 NPC 或看到它倒在地上,有時還會以其他 NPC 的外觀出現
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 偶爾隨機發生, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:在物件 ID 上加上世代編號(generation),區分重複使用。用戶端:收到已知 ID 的出現通知時,刪除既有物件並重新建立。
圖表上 偶爾隨機飆高 · 收到已知 ID 出現通知的次數
查看位置 在伺服器記錄各物件 ID 的建立與刪除時間(有世代編號時一併記錄),統計用戶端以已知 ID 收到出現通知的次數,以及視野更新時被當成「沒有變化」處理的刪除與重新建立 符合的跡象 看不見或倒在地上的 NPC 的 ID 與剛死亡的 NPC 相同,且這段期間該用戶端沒收到消失通知,或伺服器消失與出現通知都沒送 不符合的跡象 ID 有世代編號、比較時也有用到的話,就不是這個原因。ID 沒有被重複使用卻仍看不見時,是出現通知遺失 確認方式 需要遊戲伺服器/用戶端的 log 與指標
深入了解 伺服器端也會發生。只以 ID 比較視野內的物件清單時,在兩次視野更新之間死亡、又以同一個 ID 重新生成的 NPC 會被當成「沒有變化」,消失與出現通知都不會送出。每個人的視野更新時間點錯開時,只有剛好碰上那一刻的用戶端會遇到。
出處 2 筆
固定 UDP port 衝突 Two clients bound to the same local UDP port
ID pt-port-collision · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
用戶端若設計成使用固定的本機 port,同一台電腦的第二個用戶端就無法使用該 port,或與第一個用戶端分食封包。
為什麼 兩個用戶端都要開同一個本機 UDP port(用重複使用選項硬是共用) → 於是 OS 只把進來的封包交給其中一個 socket,或不保證由哪一個接收。分享器與伺服器也把兩個用戶端看成同一個位址 → 畫面上 其中一邊收不到世界封包,看不見 NPC 與其他玩家,或斷線
症狀 看不見/幽靈物件 , 斷線 , 連不上/無限讀取
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端
何時 剛登入/維護剛結束, 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:本機 port 交由 OS 自動選擇(bind 到 0 號 port)。伺服器:以每條連線核發的 session token 區分連線。
圖表上 只有部分偏高 · 各用戶端的接收封包數
查看位置 在玩家電腦上開著兩個用戶端,於命令提示字元執行 netstat -ano -p udp,查看每個遊戲處理程序(PID)開啟的本機 UDP port。伺服器端則確認兩個 session 是否以同一個公用 IP、同一個 port 進來 符合的跡象 兩個遊戲處理程序綁在同一個本機 port,或伺服器看到兩個 session 是同一個 IP 與 port。只開一個就正常 不符合的跡象 兩個用戶端使用不同的本機 port 卻仍有一邊異常時,是以 IP/裝置區分 session 的 bug 或多開限制 確認方式 在玩家端環境確認
出處 3 筆
ID pt-session-key · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
伺服器或中介伺服器以 IP 或裝置 ID 區分連線時,會把同一台電腦(同一個公用 IP)的兩個用戶端視為同一個人。
為什麼 session 表以 IP 或 IP + 裝置 ID 建立 → 於是 第二個用戶端的資訊覆蓋或混入第一個 session → 畫面上 一邊看不見 NPC,另一邊斷線或收到別人的資訊
症狀 看不見/幽靈物件 , 斷線
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端, 同一個家, 特定地區/電信業者
何時 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:伺服器與中介伺服器都以每條連線唯一的 session token 區分;同一個家(分享器 NAT 後方)的多人,以及電信業者把一個 IP 分給多個用戶的行動網路(CGNAT)玩家也會遇到同樣的問題,務必修正。用戶端:每個執行中的用戶端使用各自取得的 session token。
圖表上 只有部分偏高 · 同一公用 IP 的同時 session 數、session 覆蓋次數
查看位置 在伺服器與中介伺服器 log 記錄尋找 session 時使用的 key、session token、用戶端 IP 與 port,查看同一 IP 進來第二個連線的瞬間,既有 session 是否被改變。在同一台電腦上依序開啟兩個用戶端即可重現 符合的跡象 第二個用戶端連線的瞬間,第一個 session 的位址或角色資訊改變,且同一台分享器或行動網路(CGNAT)後方的其他玩家也出現同樣的斷線 不符合的跡象 同一 IP 的兩個 session 以不同 token 各自維持時,就不是這個原因。兩個處理程序使用同一個本機 port 時,是固定 UDP port 衝突 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 1 筆
多開限制 Multi-client restriction policy
ID pt-multiclient · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
安全模組或伺服器政策限制同一台電腦開多個用戶端時,第二個用戶端會無法執行或連線,或者先開的那一個會斷線。有些遊戲只封鎖額外用戶端的功能。
為什麼 安全模組偵測到重複執行,或伺服器限制同一裝置的額外連線 → 於是 拒絕第二次執行或連線,或切斷其中一邊。少數情況只封鎖額外用戶端的部分功能 → 畫面上 連不上,或其中一邊斷線。在只封鎖功能的遊戲中,只有一邊看不見 NPC 或商店
症狀 連不上/無限讀取 , 看不見/幽靈物件 , 斷線
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端
何時 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:若要限制,就顯示明確的提示訊息,並在安全模組設定 QA 用的例外。伺服器:同一裝置連線限制也要設定 QA 用的例外。
圖表上 只有部分偏高 · 依原因分類的連線拒絕、斷線次數(重複連線)
查看位置 查看開啟第二個用戶端時出現的訊息,以及先開那一邊的斷線訊息。確認伺服器的連線拒絕、強制斷線 log 是否留下重複連線、同一裝置之類的原因代碼 符合的跡象 第二次執行或連線的瞬間跳出拒絕訊息,或先開的那一邊以重複連線為由斷線;只開一個用戶端就沒有問題 不符合的跡象 沒有拒絕或斷線原因、兩邊都連上了,卻只有一邊看不見 NPC 時,是固定 UDP port 衝突、以 IP/裝置區分 session 的 bug,或載入、顯示方面的原因 確認方式 在玩家端環境確認
出處 1 筆
背景視窗的處理限制 Background window throttling
ID pt-background · 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
背景視窗中的用戶端,會被遊戲、引擎、OS 降低畫格數與處理量。收到的封包來不及處理,就會積壓或溢位。
為什麼 遊戲選項或顯示卡驅動程式的背景畫格限制(例:NVIDIA 驅動程式可在每秒 20~200 之間指定)、省電、引擎的背景暫停設定。OS 也會優先把 CPU、GPU 分配給前景視窗 → 於是 每個畫格處理的封包數減少,佇列堆積,接收緩衝區溢位時就被丟棄 → 畫面上 把視窗切到前景時一口氣全部冒出來,或部分 NPC 始終看不見
症狀 看不見/幽靈物件 , 快轉 , 斷線
因素 停滯, 遺失
誰會遇到 同一台電腦只有其中一個用戶端
何時 閒置一段時間後, 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲開發團隊要做的事 網路接收在與遊戲迴圈分開的執行緒持續進行,在背景也保證最低處理量,並開啟引擎的背景執行設定(Unity 為 runInBackground)。
外部要做的事 引導玩家關閉顯示卡驅動程式的背景畫格限制與電腦的省電模式。
數值參考 Unity 在 runInBackground 設定關閉時,視窗一失去焦點遊戲迴圈就會停止。若只在這個迴圈中接收,這段期間的封包完全不會被處理。
圖表上 中斷後一次湧入 · 用戶端畫格間隔、每個畫格處理的封包數
查看位置 在同一台電腦上把一個視窗放前景、另一個放背景,交換角色比較。用 PresentMon 測量兩個處理程序的畫格間隔;有遊戲端 log 的話,查看視窗焦點狀態與每個畫格處理的封包數 符合的跡象 只有在背景視窗時畫格間隔大幅增加(若是驅動程式限制,會在設定的畫格率所對應的間隔上持平)或處理停止,切換視窗後問題也跟著移到另一個用戶端 不符合的跡象 在前景視窗也一樣發生時,就不是背景限制造成的。不論視窗位置,總是同一個用戶端異常時,是顯示選項或版本不同 確認方式 在玩家端環境確認
出處 4 筆
快取/資源檔案同時存取衝突 Shared cache / asset file lock conflicts
ID pt-asset-lock · 主要負責 遊戲開發團隊(用戶端開發)
兩個用戶端同時寫入同一個快取資料夾或鎖定檔案時,其中一邊會載入不了 NPC 模型或貼圖。
為什麼 兩個用戶端同時寫入同一個安裝資料夾裡的快取、更新檔案 → 於是 檔案鎖定失敗,或讀到寫到一半的檔案而載入失敗 → 畫面上 名字還在卻沒有角色模型,或 NPC 是透明的
症狀 看不見/幽靈物件
因素 停滯
誰會遇到 同一台電腦只有其中一個用戶端
何時 剛登入/維護剛結束, 移動中/切換地圖時
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 每個用戶端使用各自的快取資料夾,檔案鎖定失敗時重試,載入失敗時至少顯示預設模型。
圖表上 只有部分偏高 · 各用戶端的資源載入失敗次數
查看位置 在玩家電腦上用 Process Monitor 只篩選遊戲安裝與快取資料夾路徑,查看兩個遊戲處理程序開啟、寫入檔案的結果。有用戶端 log 的話,找出資源載入失敗與檔案開啟錯誤代碼(ERROR_SHARING_VIOLATION) 符合的跡象 看不見的模型在開啟檔案時以共用違規或鎖定失敗結束,同一時間另一個用戶端正在寫入該檔案。只開一個或把安裝、快取資料夾分開後就消失 不符合的跡象 只開一個用戶端也看不見同一個模型時,是檔案損毀或用戶端版本、資料不一致。檔案順利開啟卻畫不出來時,是記憶體/VRAM 不足 確認方式 在玩家端環境確認
出處 2 筆
ID pt-vram · 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
兩個用戶端分著用顯示記憶體時,沒有空間載入新需要的模型與貼圖,部分物件就畫不出來。
為什麼 兩個用戶端分用 VRAM 與 RAM。OS 有時也會先縮減背景視窗的顯示記憶體配額 → 於是 引擎無法載入新的模型與貼圖,或不斷卸載又重新載入 → 畫面上 NPC 很晚才出現、模糊或看不見,畫面卡頓
症狀 看不見/幽靈物件 , 卡頓
因素 停滯
誰會遇到 同一台電腦只有其中一個用戶端
何時 移動中/切換地圖時, 人潮湧入時
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 外部(外部)
遊戲開發團隊要做的事 依記憶體預算自動調整畫質,載入失敗時顯示替代模型。
外部要做的事 引導同時開兩個用戶端的玩家降低畫質或使用低規格模式,並說明建議的 VRAM 與 RAM 規格。
圖表上 碰到上限後持平 · 各處理程序的專用 GPU 記憶體使用量
查看位置 在玩家電腦的工作管理員「詳細資料」分頁加上專用 GPU 記憶體欄位,把兩個用戶端的使用量總和與顯示卡的 VRAM 容量比較。遊戲端記錄 DXGI 的 QueryVideoMemoryInfo 回報的預算(Budget)與目前使用量(CurrentUsage) 符合的跡象 兩個用戶端使用量總和在 VRAM 容量附近持平,目前使用量超過預算的時間點,模型與貼圖載入失敗集中出現。降低畫質或只開一個就消失 不符合的跡象 VRAM 還有餘裕卻看不見時,是快取/資源檔案同時存取衝突或顯示選項不同 確認方式 在玩家端環境確認
出處 3 筆
顯示選項不同 Different display settings
ID pt-display-option · 主要負責 遊戲開發團隊(用戶端開發)
顯示人數上限、隱藏 NPC 名字與模型、低規格模式這類選項,在兩個用戶端設定不同時,看到的東西就不同。
為什麼 只有一個用戶端開了「周圍角色顯示數量上限」或低規格模式 → 於是 不繪製遠處或優先順序低的 NPC(正常) → 畫面上 只有一邊沒有 NPC
症狀 看不見/幽靈物件
因素 停滯
誰會遇到 同一台電腦只有其中一個用戶端, 只有我
何時 人潮湧入時, 一直都有
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 讓玩家看得出是被選項隱藏的物件,並把設定檔依用戶端分開,避免互相混用。
圖表上 只有部分偏高 · 各用戶端畫面上繪製的物件數
查看位置 把兩個用戶端的顯示人數上限、名字與模型隱藏、低規格模式設定並排比較,再把一邊調成和另一邊完全相同。也要確認兩個用戶端是否共用同一個設定檔、互相覆蓋 符合的跡象 把設定調成相同後兩個畫面就一樣,之前看不見的 NPC 是顯示上限人數以外的遠處物件或優先順序低的物件 不符合的跡象 設定調成完全相同仍只有一邊沒有時,是頻道、實例、相位不同或出現通知遺失 確認方式 在玩家端環境確認
出處 1 筆
用戶端版本、資料不一致 Client version / data table mismatch
ID pt-version · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
第二個用戶端是不同的安裝版本或尚未更新完成時,會不認得伺服器送來的新 NPC ID,直接默默忽略。
為什麼 其他資料夾的安裝版本,或在更新途中執行的用戶端 → 於是 收到不認得的 NPC ID、模型 ID 就略過 → 畫面上 只有新加入的 NPC 在一邊看不見
症狀 看不見/幽靈物件
因素 遺失
誰會遇到 同一台電腦只有其中一個用戶端
何時 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 用戶端:連線時送出資料版本,收到未知 ID 時留下 log 並顯示替代物。伺服器:連線時確認資料版本,不同就拒絕連線並引導更新。
圖表上 只有部分偏高 · 依用戶端版本統計收到未知 ID 的次數
查看位置 比較兩個用戶端的執行檔路徑,以及畫面與 log 上顯示的用戶端、資料版本。遊戲端記錄連線時送出的資料版本,以及收到未知 NPC、模型 ID 而略過的次數 符合的跡象 兩個用戶端的版本或安裝資料夾不同,看不見的 NPC 是最近更新新增的,且在已完成更新的安裝版本上看得到 不符合的跡象 版本與安裝資料夾都相同、仍只有一邊沒有時,是頻道、實例、相位不同,或載入、傳遞方面的原因 確認方式 在玩家端環境確認
出處 1 筆
各連線的傳送預算與優先順序 Per-connection bandwidth budget and priority
ID pt-priority · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
伺服器對每條連線的傳送量設上限、從近的開始送時,上限被設得較低的那一邊,會較晚收到或收不到遠處的 NPC。
為什麼 在人多的地方,伺服器在每條連線的傳送量上限內依重要度依序傳送 → 於是 頻寬推估偏低的連線(例:因為是背景視窗而接收確認較慢的那一邊),會一直延後後段的物件 → 畫面上 遠處的 NPC 只在一邊較晚出現或看不見
症狀 看不見/幽靈物件 , 輸入延遲
因素 延遲
誰會遇到 同一台電腦只有其中一個用戶端, 特定地點/頻道
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:被延後的物件隨時間提高優先順序,避免一直輪不到(starvation),並保證最低更新週期。用戶端:在背景也及時送出接收確認,避免頻寬推估降低。
圖表上 隨人數/負載上升 · 各連線延後的物件數、各連線的傳送量
查看位置 在伺服器上依連線記錄每個 tick 的傳送位元組、傳送上限(推估頻寬)、沒送出而延後的物件數、各物件距離上次傳送經過的時間。Unreal 可在 Networking Insights 查看各連線的封包大小與其中包含的複製物件 符合的跡象 看不見的 NPC 是在那條連線上被延後很久的物件,該連線的上限低於其他連線,且越擁擠延後的物件越多 不符合的跡象 沒有延後的物件、那個 NPC 也及時送出時,問題在傳送之後的環節(接收緩衝區、載入、顯示選項)。所有連線都頂到上限時,是整個伺服器的傳送量或視野設計問題 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 3 筆
時鐘推估誤差導致物件暫緩顯示 Clock estimate error holds or discards entities
ID pt-clock-hold · 主要負責 遊戲開發團隊(用戶端開發)
用戶端推估的伺服器時間有誤時,會把剛抵達的物件資訊當成「還在未來」而暫緩,或當成「太舊」而丟棄。
為什麼 某一個用戶端的伺服器時間推估大幅偏差(在載入中測量、從省電喚醒) → 於是 內插的基準時間與物件資訊的時間對不上 → 畫面上 物件很晚才出現,或看起來停住不動
症狀 看不見/幽靈物件 , 卡頓
因素 延遲
誰會遇到 同一台電腦只有其中一個用戶端
何時 閒置一段時間後, 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 定期重新做時間同步,差距大時立即重設,不採用在載入中或剛從省電喚醒時測到的值。
圖表上 只有部分偏高 · 各用戶端的伺服器時間推估誤差
查看位置 在用戶端記錄推估的伺服器時間、RTT、重新做時間同步的時間、暫緩或丟棄物件資訊的次數。在剛載入完或剛從省電喚醒時嘗試重現 符合的跡象 只有出問題的用戶端推估誤差超過重設門檻(Unity 為 hardResetThresholdSec,預設 0.2 秒),且有把物件資訊當成未來而暫緩、當成過去而丟棄的紀錄,重新做時間同步後立即恢復正常 不符合的跡象 推估誤差很小卻很晚出現時,是各連線的傳送預算與優先順序或載入方面的原因 確認方式 需要遊戲伺服器/用戶端的 log 與指標
出處 2 筆
TCP 重傳的根本原因
20 個原因 · 完整版章節
無線區段的封包遺失 Wi-Fi / cellular link loss
ID rt-wireless · 主要負責 外部(外部) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
Wi-Fi 與行動網路在無線區段會先重傳幾次,仍然失敗就丟棄封包。被丟棄的封包,TCP 要過好一段時間才會重送。
為什麼 訊號弱或干擾嚴重,無線區段的傳輸接連失敗 → 於是 超過無線設備的重試上限(通常是數次~十幾次)就丟棄封包 → 畫面上 定格的時間等於 TCP 等待重傳的時間,後面的封包在接收緩衝區等候,之後快轉
症狀 定格 , 快轉 , 瞬移
因素 遺失, 抖動
誰會遇到 只有我, 同一個家
何時 偶爾隨機發生, 移動中/切換地圖時
負責單位 主要負責 外部(外部) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:開啟 TCP_NODELAY(Nagle 開著時,RACK 沒有後續封包可用來判斷遺失);重傳卡住期間,待送的狀態更新只保留最新的一筆(用 TCP_NOTSENT_LOWAT 限制累積在 kernel 的量)。用戶端:開啟 TCP_NODELAY(玩家輸入方向的遺失由用戶端 OS 負責復原);遺失集中出現或 ping 急遽升高時,在畫面上顯示網路狀態。
基礎設施團隊要做的事 用 RACK-TLP 加快遺失復原(伺服器無法阻止無線遺失,能做的只有加快復原)、確認新版 Linux 的預設值 net.ipv4.tcp_recovery=1(RACK)、net.ipv4.tcp_early_retrans=3(TLP)沒有被改掉。
外部要做的事 建議玩家改用有線連線、使用 5GHz 或 6GHz 頻段、調整分享器位置或更換頻道。
數值參考 無線遺失率 1% 時,每 100 個遊戲封包就有 1 個消失。每秒收 10 個封包的話,大約每 10 秒就會頓一下。沒有 RACK-TLP 時,每次遺失都要停住一個 RTO(ping + 200ms 以上)的時間。
圖表上 只有部分偏高 · 各連線的重傳率、各連線的 RTT(ping)
查看位置 在玩家電腦上分別對分享器(閘道)位址與遊戲伺服器各 ping 數百次,比較遺失與延遲的變動幅度,再改用有線或行動數據重新測量。伺服器端用 ss -ti 查看該玩家連線的 retrans 與 rtt(平均值/偏差) 符合的跡象 ping 分享器時就已出現遺失或忽高忽低的延遲,改用有線後就消失。從伺服器看,只有該玩家連線的 retrans 與 RTT 偏差偏大 不符合的跡象 到分享器為止都正常、過了分享器才開始遺失時,問題在電信業者或路徑端(「瓶頸佇列溢位」、「路由變更、ECMP 不良路徑」)。同一電信業者的多位玩家同時變差時,先查電信業者區段 確認方式 在玩家端環境確認
深入了解 無線設備的重試會造成抖動(每次重試數 ms),只有超過重試上限的封包才會變成遺失。因此無線品質越差,症狀就會依「抖動 → 偶爾定格 → 頻繁定格」的順序加重。在分享器(AP)之間切換的瞬間(漫遊),有時會連續遺失數十 ms~數秒。行動網路在基地台區段會大量重傳,所以比起遺失,更常以數百 ms 的延遲飆升出現。
實際案例 Square Enix 2021: FINAL FANTASY XIV 資料片上市的壅塞與登入排隊錯誤
出處 8 筆
瓶頸佇列溢位(壅塞遺失) Tail drop at a congested bottleneck
ID rt-queue-drop · 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部), 遊戲開發團隊(用戶端開發)
分享器、電信業者之間的互連區段、資料中心線路這類最窄的地方,佇列一滿就會丟棄新進來的封包。
為什麼 影片、下載與其他使用者的流量把瓶頸區段塞滿 → 於是 佇列滿的期間,新到的封包接連被丟棄(tail drop)。沒被丟棄的封包也要在塞滿的佇列尾端等待 → 畫面上 多個封包同時消失,長時間定格後快轉,晚間時段常見
症狀 定格 , 快轉 , 拉回
因素 遺失, 延遲
誰會遇到 同一個家, 特定地區/電信業者, 整個伺服器
何時 晚間尖峰時段, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 外部(外部), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 遺失集中出現或 ping 急遽升高時,在畫面上顯示網路狀態(提示可能是同一條線路上有大量傳輸)。
基礎設施團隊要做的事 確保資料中心線路有餘裕、檢查我方線路與交換器 port 的佇列丟棄(output drops)計數器、電信業者區段壅塞時改走其他線路或 peering 繞開。
外部要做的事 建議玩家在分享器使用 SQM(fq_codel、CAKE)與 ECN(讓傳送端在佇列溢位前降速)、要求電信業者為瓶頸區段擴充容量。
數值參考 佇列溢位的瞬間,數十 ms 內進來的封包會有相當多一起消失。容易連續遺失,連重送的封包也可能遺失,因此常常要等到 RTO 才復原。
圖表上 只在特定時段偏高 · 重傳率、RTT(ping)
查看位置 把伺服器重傳率(每 1 分鐘執行一次 nstat 取得的 TcpRetransSegs ÷ TcpOutSegs 增加量)與各連線 RTT 依地區、電信業者、時段分開看,同時查看我方線路與交換器 port 的輸出丟棄(ifOutDiscards)。在尖峰與離峰時段各對問題地區跑 mtr 比較 符合的跡象 只有晚間尖峰時重傳率上升,而且遺失前 RTT 先升高(佇列逐漸塞滿的樣子)。mtr 只在尖峰時段從某個躍點起到終點遺失與延遲一起增加 不符合的跡象 遺失前 RTT 沒有升高時是「Policer 丟棄超額流量」。不論哪個時段遺失都差不多時,是「實體層錯誤」或「路由變更、ECMP 不良路徑」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 Riot Games 2015: 繞遠路的 League of Legends 流量與 Riot Direct
出處 9 筆
突發傳送造成淺緩衝區溢位 Sender bursts overflow shallow buffers
ID rt-burst · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(網路基礎設施)
伺服器每個 tick 把數千人份的更新在一瞬間集中送出時,交換器的小緩衝區或雲端的瞬間上限不到 1ms 就會溢位,部分封包因此被丟棄。
為什麼 每個 tick 開始的瞬間,把要送給所有人的封包一次送出 → 於是 匯集多台伺服器流量的交換器 port 緩衝區(每個 port 數百 KB~數 MB)或雲端執行個體的上限瞬間溢位(平均使用率很低) → 畫面上 多人同時瞬移、頓一下,看平均指標找不出原因
症狀 瞬移 , 定格 , 快轉
因素 遺失
誰會遇到 特定地點/頻道, 整個伺服器
何時 人潮湧入時
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(網路基礎設施)
遊戲開發團隊要做的事 把一個 tick 的傳送分散到整個 tick 內送出(數千條連線在 tick 開始時集中送出,靠各連線的 pacing 很難解決)、錯開各伺服器的 tick 開始時間、傳送大量資料的連線用 SO_MAX_PACING_RATE 設定速度上限。
基礎設施團隊要做的事 伺服器設備/OS:設定整台伺服器的傳送速度上限(伺服器 OS 的 shaper,Linux tc),單一連線的集中送出用 pacing(Linux fq 佇列、BBR)打散。網路:採用大緩衝區交換器、以短間隔檢查交換器 port 的輸出丟棄計數器(看平均使用率看不出來)。
數值參考 10Gbps port 在 1ms 內能送出的量約 1.25MB。多台伺服器的 tick 剛好重疊、集中到同一個 port 時,緩衝區一下子就滿了。
圖表上 隨人數/負載上升 · 交換器 port 輸出丟棄數、重傳率
查看位置 以幾秒的間隔收集伺服器所接交換器 port 及其上層 port 的輸出丟棄(ifOutDiscards),雲端環境則看 ethtool -S 的 bw_out_allowance_exceeded、pps_allowance_exceeded。用 bcc tcpretrans 收集同一時間點的重傳來對照 符合的跡象 以分鐘為單位的平均使用率很低,輸出丟棄或 allowance 超出次數卻增加,而且隨同時上線人數與集中在同一處的人數變多。重傳在同一瞬間出現在該伺服器的多條連線上,沒有集中在特定玩家的 IP 網段(電信業者、地區) 不符合的跡象 同一個 port 的 CRC、輸入錯誤一起增加時是「實體層錯誤」。接收端伺服器的 NIC 丟棄計數器或 softnet dropped 增加時是「接收端伺服器主機丟棄封包」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 Pacing 是每條連線各自運作。數千條連線在 tick 開始時各送一兩個封包所形成的集中,靠各連線的 pacing 很難打散,必須由遊戲伺服器自己把傳送時間點分開。反過來,單一連線傳送大量資料時,NIC 會把數十 KB 的資料切成封包大小接連送出(TSO),這種集中 pacing 就能有效打散。
出處 7 筆
ID rt-policer · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發)
電信業者的資費方案、雲端執行個體的上限、DDoS 防護設備,有時會把超過規定速度的封包直接丟棄,不放進佇列。
為什麼 瞬間傳送量超過允許速率或允許突發量 → 於是 超出的封包不經佇列直接丟棄(policing) → 畫面上 每逢突發量大的瞬間就有多個封包消失,定格後快轉;平均速度看起來低於上限
症狀 定格 , 快轉 , 瞬移
因素 遺失
誰會遇到 整個伺服器, 特定地區/電信業者, 只有我
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把每個 tick 集中送出的量分散到 tick 內,讓瞬間傳送量低於允許突發量;碰到每秒封包數上限時,把一個 tick 的訊息合併成一個封包。
基礎設施團隊要做的事 網路:檢查設備的 policer 超出計數器、改用 shaper 取代 policer、調高允許突發量。伺服器設備/OS:檢查雲端上限超出指標(AWS 為 ethtool -S 的 bw_out_allowance_exceeded、pps_allowance_exceeded)、升級執行個體規格、在伺服器上做 pacing(Linux fq 佇列)。
數值參考 Shaper(放進佇列延後送出)會增加延遲,policer(立即丟棄)會增加遺失。TCP 遊戲連線遺失一次就可能停住數百 ms,所以只是短暫超過上限的程度時,通常 policer 的影響比較大。
圖表上 碰到上限後持平 · 短間隔的傳送量、policer/allowance 超出計數器
查看位置 查看套用 policer 的設備上的超出(exceed)與丟棄計數器,雲端環境則看 ethtool -S 的 bw_out_allowance_exceeded、pps_allowance_exceeded。發生遺失的連線,用 ss -ti 的 rtt 或封包擷取查看遺失前的 RTT 符合的跡象 超出計數器增加,短間隔的傳送量像被截斷在某個值一樣持平。遺失前 RTT 沒有升高,只有在突發量大的瞬間才有多個封包一起消失 不符合的跡象 遺失前 RTT 先升高時是佇列溢位(「瓶頸佇列溢位」、「突發傳送造成淺緩衝區溢位」)。超出計數器沒有變化就是其他原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
實體層錯誤(線材、光模組、接頭不良) Bit errors: bad cable, optics, dirty fiber
ID rt-physical · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 外部(外部)
纜線損壞、沾了灰塵的光纖接頭、壽命將盡的光模組會造成位元錯誤,損壞的封包會被設備默默丟棄。
為什麼 線材、光模組、接頭不良導致位元翻轉 → 於是 設備丟棄檢查碼(CRC)不符的封包 → 畫面上 只有經過該路徑的人持續出現短暫頓一下後快轉,與時段無關
症狀 定格 , 快轉 , 瞬移
因素 遺失
誰會遇到 特定地點/頻道, 同一個家
何時 一直都有
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 外部(外部)
基礎設施團隊要做的事 CRC 錯誤會累積在出錯方向的接收端,所以兩端都要檢查。網路:檢查設備 port 的 CRC 與輸入錯誤計數器、檢查光訊號強度(交換器的光模組資訊)、清潔光纖接頭、更換線材與光模組。伺服器設備/OS:檢查伺服器 ethtool -S 的 rx_crc_errors(名稱依驅動程式略有不同)、檢查光訊號強度(ethtool -m)、更換伺服器端的線材或 NIC。
外部要做的事 問題在玩家家中時,建議更換網路線或分享器;問題在電信業者線路區段時,請電信業者檢修線路。
數值參考 即使只有 0.1% 的遺失,也等於每 1,000 個遊戲封包遺失一次。經過該路徑的人有數十人時,每隔幾秒就有人頓一下。封包越大越容易遇上位元錯誤。
圖表上 只有部分偏高 · 各 port 的 CRC 錯誤數、各伺服器/port 的重傳率
查看位置 查看鏈路兩端的 CRC 計數器。伺服器看 ethtool -S 的 rx_crc_errors 或 ip -s -s link 的 crc,交換器看 port 的 FCS 錯誤(dot3StatsFCSErrors)與輸入錯誤(ifInErrors)。光纖鏈路則用 ethtool -m 與交換器的光模組資訊查看接收光功率 符合的跡象 某個 port 的 CRC 錯誤不分時段持續增加,只有經過該 port 的伺服器與連線重傳率偏高。接收光功率比同類型的其他鏈路低 不符合的跡象 CRC 沒有變化、只有輸出丟棄增加時是佇列溢位(「突發傳送造成淺緩衝區溢位」、「瓶頸佇列溢位」)。一端的延遲碰撞(late collision)與另一端的 CRC 一起增加時是「雙工模式不一致」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 3 筆
雙工模式不一致 Duplex mismatch
ID rt-duplex · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
一端設為自動協商、另一端把速度與雙工固定時,其中一端會以半雙工運作,每當負載升高就因碰撞而遺失封包。
為什麼 只有其中一台設備把速度與雙工設成固定值 → 於是 一端以全雙工運作、另一端以半雙工運作,發生碰撞與延遲碰撞 → 畫面上 平常一切正常,流量一增加,經過該設備的所有人都會定格後快轉
症狀 定格 , 快轉
因素 遺失
誰會遇到 整個伺服器, 特定地點/頻道
何時 人潮湧入時, 晚間尖峰時段
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 兩端都設為自動協商,或兩端都固定為相同的值。網路:在交換器 port 狀態中確認速度與雙工,並在 port 計數器中確認半雙工那一端的延遲碰撞、全雙工那一端的 CRC 錯誤與過短訊框(runt)是否增加。伺服器設備/OS:用 ethtool 確認速度與雙工。
數值參考 1Gbps 銅線必須使用自動協商,10Gbps 以上則根本沒有半雙工。所以現在主要發生在 100Mbps 以下的老舊設備、管理用 port,以及部分線路介接區段。
圖表上 隨人數/負載上升 · port 延遲碰撞與 CRC 錯誤數、重傳率
查看位置 查看鏈路兩端實際的速度與雙工。伺服器用只加介面名稱執行的 ethtool,交換器看 port 狀態或 SNMP 的 dot3StatsDuplexStatus。同時查看延遲碰撞(伺服器 tx_window_errors、交換器 dot3StatsLateCollisions)與 CRC 錯誤 符合的跡象 一端顯示半雙工,另一端顯示全雙工。每當流量增加,半雙工那一端的延遲碰撞與全雙工那一端的 CRC 錯誤就一起增加 不符合的跡象 兩端速度與雙工相同、只有 CRC 增加時是「實體層錯誤」。10Gbps 以上的鏈路沒有半雙工,可排除這個原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 6 筆
接收端伺服器主機丟棄封包 Receiver host drops (ring, softirq, CPU)
ID rt-host-drop · 主要負責 基礎設施團隊(伺服器基礎設施)
封包已經到了伺服器,卻因 NIC 的 ring buffer(暫存剛抵達封包的緩衝區)溢位,或 kernel 負責接收處理的 CPU 核心滿載而被丟棄。
為什麼 連線人數暴增、中斷集中在單一核心、虛擬機器 CPU steal、虛擬交換器過載 → 於是 在 ring buffer(rx_missed_errors 等,名稱依驅動程式而異)或 kernel 接收佇列(softnet dropped)被丟棄 → 畫面上 人潮湧入時,整個伺服器同時出現輸入慢半拍才生效、頓一下
症狀 輸入延遲 , 定格 , 快轉 , 瞬移
因素 遺失, 停滯
誰會遇到 整個伺服器
何時 人潮湧入時
負責單位 主要負責 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 把 ethtool -S 的 rx_missed_errors 這類丟棄計數器與 /proc/net/softnet_stat 的 dropped 加入監控、加大 ring buffer(ethtool -G)、把 RSS 與中斷分散到多個核心、把遊戲執行緒與接收處理核心分開、確保 CPU 有餘裕、虛擬機器則檢查 CPU steal 與虛擬交換器負載。
數值參考 伺服器在接收時丟棄的封包,會由用戶端重送。因此伺服器的重傳指標不太會反映出來,會先出現在 ethtool -S 的 rx_missed_errors 這類丟棄計數器(名稱依驅動程式而異)與 /proc/net/softnet_stat 的 dropped。
圖表上 碰到上限後持平 · 各核心的 softirq 使用率、NIC 丟棄計數器
查看位置 查看 ethtool -S 的丟棄計數器(rx_missed_errors 等,mlx5 為 rx_out_of_buffer、rx_discards_phy)、ip -s -s link 的 missed、/proc/net/softnet_stat 的第 2 欄(dropped)與第 3 欄(time_squeeze),並用 mpstat -P ALL 查看各核心的 %soft(軟體中斷處理)。虛擬機器也要看 %steal 符合的跡象 人潮湧入時丟棄計數器或 softnet dropped 增加,負責接收處理的核心 %soft 接近 100% 而無法再往上。該伺服器的所有連線同時出現輸入變慢 不符合的跡象 伺服器的丟棄計數器沒有變化,重傳集中在特定地區或電信業者的連線時,是路徑上的遺失。伺服器送出的封包在路徑上遺失時,伺服器 nstat 的 TcpRetransSegs 會增加,這些計數器則維持不變 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 10 筆
防火牆與連線追蹤丟棄封包 Stateful firewall / conntrack drops
ID rt-stateful-fw · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
防火牆或 Linux 連線追蹤(conntrack,把經過的連線記錄在表中的功能),在表已滿或判斷連線狀態不符時,會丟棄封包。
為什麼 連線追蹤表已滿(table full),或去回程路徑不同,只有單一方向經過防火牆(非對稱路由) → 於是 防火牆把封包視為「未知連線」或「序號超出視窗範圍」而丟棄 → 畫面上 表滿了之後新連線會被擋下;路徑不一致時,只有走該路徑的人在反覆重傳後斷線
症狀 定格 , 斷線 , 連不上/無限讀取
因素 遺失
誰會遇到 整個伺服器, 特定地區/電信業者
何時 人潮湧入時, 剛登入/維護剛結束, 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:為了因應表滿的情況,用登入排隊系統控制湧入的連線、重複使用連線以免反覆建立短連線(包括伺服器之間的呼叫)、心跳封包已中斷的連線要主動先清掉。用戶端:連線失敗或中斷時,逐步拉長重試間隔並隨機分散(避免表滿時所有人又一起湧入)。
基礎設施團隊要做的事 網路:加大防火牆的連線追蹤表、讓遊戲 port 不做連線追蹤、調整路由讓往返路徑經過同一台防火牆、確認防火牆的 TCP 視窗檢查設定。伺服器設備/OS:加大 Linux 的表(nf_conntrack_max)、讓遊戲 port 不做連線追蹤(NOTRACK)、確認 TCP 視窗檢查設定(nf_conntrack_tcp_be_liberal)、AWS 另外確認 conntrack_allowance_exceeded。
數值參考 Linux conntrack 的預設上限(nf_conntrack_max)依記憶體大小為數萬~數十萬筆。目前筆數(nf_conntrack_count)達到上限時,log 會留下「nf_conntrack: table full, dropping packet」。
圖表上 碰到上限後持平 · conntrack 項目數(nf_conntrack_count)、新連線失敗數
查看位置 Linux 伺服器看 nf_conntrack_count 與 nf_conntrack_max、dmesg 的「nf_conntrack: table full, dropping packet」、/proc/net/stat/nf_conntrack 的 drop 與 invalid(每個核心一行,16 進位)。防火牆看 session 表使用量與丟棄 log,AWS 看 ethtool -S 的 conntrack_allowance_exceeded 符合的跡象 項目數在上限值持平,同一時間 table full log 與 drop,或 conntrack_allowance_exceeded 增加。非對稱路由時,上限還有餘裕,但 invalid 與防火牆丟棄 log 在特定路徑的連線上增加 不符合的跡象 項目數離上限很遠,invalid 與丟棄 log 也沒有變化時,是其他原因。表還有餘裕,但防火牆的 CPU 或每秒封包數已滿載時,是「中間設備超過處理上限」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 5 筆
ID rt-appliance-pps · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
防火牆、入侵防禦設備(IPS)、DDoS 防護設備會逐一檢查經過的封包。從超過檢查能力的那一刻起,處理不了的封包就會被丟棄。
為什麼 尖峰時段或活動期間,每秒湧入數十萬個以上的小型遊戲封包,或是檢查規則太重 → 於是 設備的 CPU 或每秒封包數達到上限,封包在設備上被丟棄。誤判時連正常封包也會被擋 → 畫面上 該設備後方的所有伺服器同時出現定格、瞬移,只在人潮湧入時加劇
症狀 定格 , 快轉 , 瞬移 , 斷線
因素 遺失, 延遲
誰會遇到 整個伺服器, 特定地區/電信業者
何時 晚間尖峰時段, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 把遊戲的流量模式(port、封包大小、每秒封包數)提供給基礎設施團隊、把一個 tick 內要送的小訊息合併後一次送出,減少封包數。
基礎設施團隊要做的事 把設備的 CPU、每秒封包數、丟棄計數器與遊戲指標放在一起看、以小封包為基準規劃設備容量、讓遊戲 port 不經過重度檢查、讓 DDoS 防護規則配合遊戲流量模式。
數值參考 設備規格上的「10Gbps」,很多是以 1,500 位元組的大封包為基準標示的。100 位元組左右的遊戲封包在相同頻寬下,封包數多出 10 倍以上,所以即使線路看起來很空,每秒封包數上限也會先被用完。
圖表上 碰到上限後持平 · 設備每秒封包數與 CPU 使用率、設備丟棄數
查看位置 查看設備的 CPU、每秒封包數與丟棄計數器,並以相同間隔比較設備前後交換器 port 的封包數。與同時上線人數、伺服器重傳率疊在同一個畫面上看 符合的跡象 尖峰或活動時,設備的每秒封包數或 CPU 停在某個值無法再往上,從設備出來的封包比進去的少,同一時間該設備後方所有伺服器的重傳率一起上升 不符合的跡象 設備前後的封包數相同、設備也沒有丟棄時是其他原因。伺服器的 NIC 丟棄計數器或 softnet dropped 增加時是「接收端伺服器主機丟棄封包」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 1 筆
ID rt-mtu · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發)
中途區段能接收的大小變小,而「封包太大」的通知(ICMP)又被擋掉時,大封包不管重送幾次都會一直消失。
為什麼 VPN 或通道區段的最大大小變小,大小超過的通知被防火牆擋掉 → 於是 傳送端不知道原因,持續重傳同一個大封包,RTO 每次加倍 → 畫面上 平常一切正常,但在背包、人多的地方、進場載入這類有大量資料往來的瞬間,連後面的小封包也全部卡住而定格,最後斷線或無限讀取
症狀 定格 , 斷線 , 連不上/無限讀取
因素 遺失
誰會遇到 特定地區/電信業者, 只有我
何時 做特定動作時, 剛登入/維護剛結束
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 要從伺服器端直接調低,就設定 socket 的最大區段大小(TCP_MAXSEG);只在遊戲程式碼中把訊息切小並不能避免(TCP 會把要送的資料重新依 MSS 大小打包)。
基礎設施團隊要做的事 網路:在邊界設備做 MSS 調整(clamping)、在防火牆與雲端網路 ACL 允許大小超過的 ICMP(類型 3 代碼 4,fragmentation needed)。伺服器設備/OS:設定路徑 MTU、確認伺服器防火牆與雲端安全群組也沒有擋掉大小超過的 ICMP、以 Linux tcp_mtu_probing=1 作為最後一道防線。
數值參考 通常是 1,500 位元組,經過通道後為 1,400 左右。同一個封包重傳 5~6 次,定格就會超過 10 秒。
圖表上 只有部分偏高 · 各連線的 RTO 與 backoff、各地區/電信業者的斷線次數
查看位置 用伺服器端的封包擷取或 bcc tcpretrans -s(顯示序號)查看問題連線的重傳,並用 ss -ti 查看該連線的 mss、pmtu、backoff。從伺服器對該玩家位址分別送出小 ping 與開啟 DF 的 1,500 位元組 ping(ping -M do -s 1472)比較 符合的跡象 塞滿 MSS 的封包以相同序號持續重傳,間隔每次加倍,比它小的封包則能通過。沒有收到大小超過的 ICMP(Wireshark 篩選條件 icmp.type == 3 and icmp.code == 4),小 ping 有回應,只有大的 DF ping 沒有回應就消失 不符合的跡象 小封包也一起消失時,是與大小無關的遺失(「瓶頸佇列溢位」、「路由變更、ECMP 不良路徑」)。收到大小超過的 ICMP 且 ss -ti 的 pmtu 變小時,代表路徑 MTU 探索正常運作 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
深入了解 tcp_mtu_probing=1 要等重傳逾時持續幾秒(相當於 tcp_retries1=3)之後,才會判定為黑洞,並把 MSS 降到 1,024 位元組。這段期間連線會停住,所以只把它當作最後一道防線,優先採用事先預防的 MSS 調整。
出處 15 筆
ID rt-mapping · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施), 基礎設施團隊(伺服器基礎設施)
中途設備刪除閒置連線的 mapping(記錄這條連線要轉送到哪裡的項目)後,接下來送出的封包就無法送達。連線會不斷重傳直到斷線,或是設備回傳拒絕連線(RST)而立刻斷線。
為什麼 有一段時間沒有任何封包往來的連線(暫離、大廳) → 於是 分享器 NAT、電信業者 CGNAT、防火牆、負載平衡器、雲端安全群組刪除閒置的 mapping → 畫面上 再次移動的瞬間接連重傳,最後斷線,或是直接斷線
症狀 斷線 , 定格
因素 遺失
誰會遇到 只有我, 特定地區/電信業者
何時 閒置一段時間後
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(網路基礎設施), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 用戶端:以最短閒置逾時的一半以下為間隔送出心跳封包(玩家分享器與電信業者 CGNAT 的 mapping 只有從內部送出的封包才能確實更新,逾時時間我方也無法更改,所以由用戶端送出)、斷線時自動重新連線。伺服器:回應心跳封包,一段時間沒收到就主動先清掉連線(縮短 TCP keepalive 間隔(TCP_KEEPIDLE 等 socket 選項)、用 TCP_USER_TIMEOUT 快速偵測)、用 session token 接續連線。
基礎設施團隊要做的事 網路:彙整路徑上防火牆與負載平衡器的閒置逾時並提供給遊戲開發團隊,我方的防火牆與負載平衡器視需要調長。伺服器設備/OS:確認雲端安全群組的連線追蹤時間並提供給遊戲開發團隊。
數值參考 TCP mapping 的保留時間依設備而異,從幾分鐘到幾小時都有。雲端安全群組設為追蹤連線時,AWS Nitro v6 執行個體類型預設在 350 秒後刪除追蹤項目(其他類型為 5 天,請參考「雲端安全群組的連線追蹤過期」)。Linux TCP keepalive 的預設值是「閒置 2 小時才確認」,比大多數設備都晚。
圖表上 連線同時大量中斷 · 斷線次數、斷線前的閒置時間
查看位置 用伺服器端的封包擷取查看斷線連線的最後幾分鐘,仍存活的連線則用 ss -ti 的 lastsnd、lastrcv(距離最後一次傳送、接收經過的 ms)查看閒置時間。同時查看 nstat 的 TcpExtTCPAbortOnTimeout(計時器到期而放棄連線的次數) 符合的跡象 每條斷線的連線在斷線前的閒置時間都超過相近的值(路徑上設備的閒置逾時,例:AWS Nitro v6 執行個體安全群組的 350 秒),閒置後從第一個封包起就只有重傳、沒有 ACK,最後放棄,或是立刻收到 RST 不符合的跡象 與閒置時間無關、遊戲進行中也會斷線時,是其他原因(「路由變更、ECMP 不良路徑」、「防火牆與連線追蹤丟棄封包」)。心跳封包以最短閒置逾時的一半以下為間隔往來的連線,可排除這個原因 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 8 筆
路由變更、ECMP 不良路徑 Route change / bad ECMP member
ID rt-path · 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
網際網路路由變更的那幾秒內,或是多條 ECMP 路徑中被分配到不良路徑的連線,會有封包消失。
為什麼 BGP 重新計算路由,或多條路徑(ECMP、LAG)中某一條的設備或線路不良 → 於是 切換路由時暫時遺失,或只有走該路徑的連線持續遺失 → 畫面上 突然定格幾秒後快轉,或是「重新連線就變好」(被分配到其他路徑)
症狀 定格 , 快轉 , 瞬移
因素 遺失
誰會遇到 特定地區/電信業者
何時 偶爾隨機發生
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 遊戲開發團隊(伺服器開發), 外部(外部)
遊戲開發團隊要做的事 記錄各連線的重傳統計(TCP_INFO),以便找出受影響玩家的 IP、port 與時間點、停住幾秒的連線不要立刻切斷。
基礎設施團隊要做的事 監控各地區、各電信業者的重傳率、確認重新連線後路徑是否改變、準備多家電信業者的線路、檢查我方設備 ECMP 與 LAG 路徑中的不良鏈路、路徑量測也使用與遊戲相同的 TCP port(mtr --tcp --port。路徑依位址與 port 決定,一般 ping 可能走不同的路徑而顯示正常)。
外部要做的事 向電信業者回報不良路徑,並附上以相同 TCP port 量測的路徑結果與重新連線前後的比較。
圖表上 從某個時間點起階梯式上升 · RTT(ping)、各地區/電信業者的重傳率
查看位置 用 bcc tcpretrans -c 依連線彙整重傳,找出受影響玩家的位址與 port,再以與遊戲相同的 TCP port,分別從伺服器往玩家、從玩家往伺服器跑 mtr(mtr -T -P PORT)比較。重新連線前後的結果也要比較 符合的跡象 以某個時間點為分界,某一地區或電信業者的 RTT 像階梯一樣改變,並集中出現幾秒的遺失;或是在同一電信業者內,也只有部分連線(位址與 port 的組合)持續重傳,重新連線就變好。有時一般 ping 正常,只有 TCP mtr 看得到遺失 不符合的跡象 該電信業者的所有連線在晚間尖峰一起變差時是「瓶頸佇列溢位」。只有一名玩家變差、從 ping 分享器就開始遺失時是「無線區段的封包遺失」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 Cloudflare 2020: Cloudflare 骨幹設定錯誤導致部分城市的流量遺失
出處 5 筆
延遲飆升造成的不必要重傳 Spurious RTO from delay spikes
ID rt-spurious-delay · 主要負責 外部(外部) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
封包沒有消失,只是短暫地很晚才到;但這段延遲比 RTO 長時,傳送端就會判斷為遺失而重傳。
為什麼 bufferbloat、Wi-Fi 省電、行動網路無線狀態切換、虛擬機器暫停,造成瞬間延遲達數百 ms → 於是 RTO 先到期而重傳,原本的封包也隨即抵達(接收端收到重複的封包) → 畫面上 定格與快轉是延遲飆升本身造成的。不必要的重傳幾乎不會拉長定格,只會推高重傳指標,因而被誤認為遺失
症狀 定格 , 快轉 , 輸入延遲
因素 延遲, 抖動
誰會遇到 只有我, 整個伺服器
何時 偶爾隨機發生, 閒置一段時間後
負責單位 主要負責 外部(外部) · 協同 基礎設施團隊(伺服器基礎設施), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 Android 10 以上的用戶端在遊戲中要求低延遲 Wi-Fi 模式(WIFI_MODE_FULL_LOW_LATENCY Wi-Fi lock,只在螢幕開啟且遊戲位於前景時生效),減少省電造成的延遲飆升。
基礎設施團隊要做的事 避免使用突發型(burstable)執行個體、不要把 RTO 最小值調得太低、保持 F-RTO 與時間戳記開啟(tcp_frto、tcp_timestamps)、重傳指標要與 nstat 的 TCPSpuriousRTOs、TCPDSACKRecv 一起看,以免誤認為遺失。
外部要做的事 為了減少延遲飆升本身,建議玩家在分享器使用 SQM、關閉 Wi-Fi 省電。
數值參考 Linux 會用 F-RTO 偵測不必要的 RTO,有時也會撤回已降低的傳送量。可用 nstat 的 TCPSpuriousRTOs(判定為不必要 RTO 的次數)與 TCPDSACKRecv(接收端回報「已經收過」的次數)確認。
圖表上 偶爾隨機飆高 · RTT(ping)、不必要的 RTO 次數
查看位置 每 1 分鐘執行一次 nstat,一起查看 TcpExtTCPTimeouts(RTO 到期)、TcpExtTCPSpuriousRTOs、TcpExtTCPDSACKRecv、TcpExtTCPLostRetransmit 的增加量。有封包擷取時用 Wireshark 篩選條件 tcp.analysis.spurious_retransmission 符合的跡象 RTO 增加時,TcpExtTCPSpuriousRTOs 或 TcpExtTCPDSACKRecv 也一起增加,同一時間 RTT 飆到數百 ms。接收端的封包擷取中,原本的封包與重傳的封包都有抵達 不符合的跡象 TcpExtTCPSpuriousRTOs 與 DSACK 沒有變化,TcpExtTCPLostRetransmit(連重送的封包也再次遺失)卻增加時,是實際遺失。RTT 沒有飆高、只有 DSACK 一直很多時,是「封包亂序造成的不必要快速重傳」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 11 筆
封包亂序造成的不必要快速重傳 Reordering triggers spurious fast retransmit
ID rt-reorder · 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
封包經過多條路徑或聚合鏈路時順序被打亂,接收端會以重複 ACK 告知「有封包缺漏」,傳送端就把其實已正常送達的封包再送一次。
為什麼 依封包分配路徑的設備、依封包分散傳送的 LAG(鏈路聚合)、路由切換的瞬間,都會打亂封包順序 → 於是 後面的封包先到,累積 3 個重複 ACK → 快速重傳 → 畫面上 零星往來的遊戲封包幾乎不受影響。人多處的大型狀態更新與更新檔下載會變慢,偶爾出現卡頓
症狀 卡頓 , 輸入延遲
因素 抖動
誰會遇到 特定地區/電信業者, 整個伺服器
何時 一直都有, 人潮湧入時
負責單位 主要負責 基礎設施團隊(網路基礎設施) · 協同 基礎設施團隊(伺服器基礎設施)
基礎設施團隊要做的事 網路:改以連線為單位分散,不再以封包為單位分散(ECMP、LAG 依位址與 port 雜湊)。伺服器設備/OS:使用 RACK(以時間判斷遺失,對亂序的容忍度高;透過 DSACK 偵測到不必要的重傳時,會自動放寬亂序容許範圍)、確認 Linux 對每條連線自動估計的亂序程度(ss -ti 的 reordering 值,起始值為 tcp_reordering=3)。
圖表上 一開始就一直偏高 · 亂序偵測次數、DSACK 接收數
查看位置 查看 nstat 的 TcpExtTCPSACKReorder、TcpExtTCPTSReorder(偵測到亂序的次數)與 TcpExtTCPDSACKRecv,各連線則看 ss -ti 的 reordering(值不為 3 時才顯示)與 reord_seen。封包擷取則用 Wireshark 篩選條件 tcp.analysis.out_of_order 符合的跡象 亂序計數器與 DSACK 不分時段持續上升,經過特定路徑或設備的連線 reordering 值大於 3。接收端的封包擷取中,後面的封包先到,前面的封包也隨即抵達 不符合的跡象 亂序計數器沒有變化、TcpExtTCPLostRetransmit 增加時,是實際遺失。只在 RTT 飆高的瞬間 DSACK 增加時,是「延遲飆升造成的不必要重傳」 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 9 筆
ACK 延遲或消失(上傳飽和) ACK path congestion on asymmetric links
ID rt-ack-path · 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
資料已順利送達,但「收到了」的 ACK 在塞滿的上傳佇列裡延遲或消失時,傳送端會判斷為遺失而重傳。
為什麼 家中有人上傳影片或做雲端備份,把上傳頻寬塞滿 → 於是 ACK 在分享器佇列裡延遲數百 ms,或因溢位而被丟棄 → 畫面上 伺服器送來的遊戲封包大致準時到達。自己的輸入堆在同一個上傳佇列裡而晚送出,造成輸入延遲、拉回,偶爾出現不必要的重傳
症狀 輸入延遲 , 拉回
因素 延遲, 遺失
誰會遇到 同一個家
何時 偶爾隨機發生, 晚間尖峰時段
負責單位 主要負責 外部(外部) · 協同 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 ping 急遽升高時在畫面上顯示網路狀態、跳出「請檢查正在上傳的程式」提示。
外部要做的事 建議玩家用分享器的 SQM 縮短上傳佇列、優先處理小封包(ACK)、限制上傳速度(影片上傳、雲端備份)。
數值參考 後面的 ACK 會代替前面的 ACK 完成確認,所以少了幾個通常沒關係。真正的問題是 ACK 在佇列裡被延遲。
圖表上 只有部分偏高 · 各連線的 RTT(ping)
查看位置 在玩家電腦上,分別在開啟與關閉上傳(影片上傳、雲端備份)的狀態下 ping 遊戲伺服器比較。伺服器端用 ss -ti 查看該玩家連線的 rtt 符合的跡象 只有上傳期間 ping 升到數百 ms,並出現輸入延遲、拉回,停止上傳後很快恢復。從伺服器看,同一時間該連線的 rtt 也一起升高 不符合的跡象 與上傳無關也出現遺失與延遲時,是「無線區段的封包遺失」或路徑端的原因。只有伺服器往玩家的方向變慢、且與上傳無關時,是「瓶頸佇列溢位」 確認方式 在玩家端環境確認
出處 4 筆
RTO 設定不符合環境 RTO min too low or too high
ID rt-rto-setting · 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
RTO 最小值調得太低時,只要稍微延遲就會產生不必要的重傳;預設值(200ms)對遊戲來說又太長,每遺失一次就要停住很久。
為什麼 為了資料中心環境把 RTO 最小值大幅調低,或在網際網路區段直接沿用預設值 → 於是 太低時,瞬間延遲也會引發大量重傳;太高時,每次遺失都要等很久 → 畫面上 預設值時,遺失一次就定格數百 ms 後快轉;調得太低時定格變短,但不必要的重傳暴增,浪費線路頻寬
症狀 定格 , 快轉 , 輸入延遲
因素 延遲
誰會遇到 整個伺服器
何時 一直都有
負責單位 主要負責 基礎設施團隊(伺服器基礎設施) · 協同 遊戲開發團隊(伺服器開發)
遊戲開發團隊要做的事 Linux 6.15 以上時,評估在遊戲連線用 TCP_RTO_MAX_MS 調低 RTO 上限(放棄連線前的時間也會跟著縮短,所以要同時用 TCP_USER_TIMEOUT 設定斷線判定時間)、只對伺服器之間的內部連線用 socket 選項 TCP_RTO_MIN_US(6.15 以上)調低 RTO 最小值、評估用 socket 選項 TCP_THIN_LINEAR_TIMEOUTS 讓遊戲連線的連續 RTO 不再加倍。
基礎設施團隊要做的事 只對伺服器之間的內部連線依路由調低 rto_min,網際網路區段維持預設值,改用 RACK-TLP 與 thin stream 設定(tcp_thin_linear_timeouts)補強。
數值參考 Linux RTO = 往返時間 + max(200ms, RTT 偏差×4)。每失敗一次就加倍,最大 120 秒。Linux 6.15 以上可用 TCP_RTO_MAX_MS 把這個上限最低降到 1 秒。
圖表上 一開始就一直偏高 · 各連線的 RTO、不必要的 RTO 次數
查看位置 查看伺服器的 RTO 最小值設定(ip route show 的 rto_min,Linux 6.11 以上為 sysctl net.ipv4.tcp_rto_min_us)與 ss -ti 的 rto、rtt,並查看 nstat 的 TcpExtTCPSpuriousRTOs 增加量 符合的跡象 調低最小值的伺服器上,網際網路連線的 rto 緊貼著 rtt,TcpExtTCPSpuriousRTOs 大量增加。維持預設值時,遊戲連線的 rto 比 rtt 大 200ms 以上,每遺失一次就停住那麼久 不符合的跡象 rto 符合預設計算(rtt + 200ms 左右)、不必要的 RTO 也少,停頓卻特別長時,問題在連續遺失或復原方式(「thin stream 復原緩慢」、「中間設備移除 TCP 選項」) 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 12 筆
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。
出處 11 筆
中間設備移除 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 關掉之後就忘了改回來,結果也一樣。
出處 10 筆
Zero window(看起來像重傳的停頓) Zero window, often mistaken for retransmission
ID rt-zero-window · 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(伺服器基礎設施)
接收端程式沒有及時讀取 socket、緩衝區塞滿時,傳送端會停止傳送,只送出 zero window probe。線路本身沒有問題。
為什麼 用戶端的畫格更新停住、伺服器執行緒卡住,導致無法讀取 socket → 於是 接收視窗變成 0,傳送端停止傳送、只送 probe(間隔越來越長) → 畫面上 定格後快轉。封包擷取中看得到「ZeroWindow」,沒有遺失
症狀 定格 , 快轉
因素 停滯
誰會遇到 只有我, 整個伺服器
何時 人潮湧入時, 偶爾隨機發生
負責單位 主要負責 遊戲開發團隊(用戶端開發) · 協同 遊戲開發團隊(伺服器開發), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事 先從封包擷取中送出 ZeroWindow 的一方(無法讀取 socket 的一方)開始確認、在獨立的執行緒持續讀取網路接收資料、把接收緩衝區設為適當大小。用戶端:解決載入、GC 這類讓畫格更新停住的原因。伺服器:解決讀取 socket 的執行緒卡住的原因。
基礎設施團隊要做的事 把伺服器 nstat 的 TcpExtTCPToZeroWindowAdv(伺服器通告接收視窗為 0 的次數)加入監控(增加時問題在伺服器端,轉交伺服器開發)、提供伺服器端的封包擷取。
圖表上 中斷後一次湧入 · 各連線的接收量、zero window 次數
查看位置 在封包擷取中用 Wireshark 篩選條件 tcp.analysis.zero_window 找出通告視窗為 0 的一方。伺服器的 nstat 則分開查看 TcpExtTCPToZeroWindowAdv(伺服器通告視窗為 0)與 TcpExtTCPWinProbe(針對對方的視窗 0 送出 probe),並查看伺服器 socket 的 Recv-Q(ss 中程式尚未讀取的位元組) 符合的跡象 停住期間沒有重傳,只有 zero window 與 probe 往來。伺服器的 TcpExtTCPToZeroWindowAdv 或伺服器 socket 的 Recv-Q 增加時,是伺服器沒有及時讀取;TcpExtTCPWinProbe 增加時,是用戶端沒有及時讀取 不符合的跡象 擷取中沒有 zero window、同樣的資料被重送時,原因在遺失或不必要的重傳 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
實際案例 Roblox 2021: Roblox 73 小時事故:服務探索(Consul)叢集的資源競爭
出處 7 筆
連線請求(SYN)重傳 SYN retransmission on connect
ID rt-syn · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(網路基礎設施), 遊戲開發團隊(用戶端開發)
連線請求因連線等待佇列(backlog)溢位或被防火牆阻擋而消失時,用戶端 OS 會從 1 秒後開始,逐步拉長間隔重送。
為什麼 維護剛結束時連線暴增,伺服器的連線等待佇列溢位,或是防火牆、DDoS 防護丟棄 SYN → 於是 用戶端 OS 從 1 秒後開始以固定間隔重傳 SYN(舊版 Linux 為 1 秒 → 2 秒 → 4 秒) → 畫面上 按下連線按鈕後,延遲剛好是 1 秒、3 秒這種整秒數,持續失敗就連不上/無限讀取
症狀 連不上/無限讀取
因素 遺失
誰會遇到 整個伺服器, 特定地區/電信業者
何時 剛登入/維護剛結束
負責單位 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施), 基礎設施團隊(網路基礎設施), 遊戲開發團隊(用戶端開發)
遊戲開發團隊要做的事 伺服器:加大 listen 的 backlog 參數(與 somaxconn 一起調)、讓遊戲伺服器及時呼叫 accept、登入排隊系統。用戶端:拉長連線重試間隔(隨機分散)。
基礎設施團隊要做的事 伺服器設備/OS:伺服器連線等待佇列溢位可用 nstat 的 TcpExtListenOverflows、TcpExtListenDrops 與 log 中的「Possible SYN flooding」警告確認、加大 somaxconn(與 listen 參數一起調)、使用 SYN cookie。網路:放寬防火牆與 DDoS 防護的 SYN 限制。
數值參考 Linux(包括 Android)第一次 SYN 重傳在 1 秒後。舊版 kernel 之後間隔每次加倍,在第 1、3、7、15 秒……時重送,6.5 以上則在 1、2、3、4、5 秒重送五次後才開始加倍(7、11、19 秒……)(tcp_syn_linear_timeouts=4)。Android 手機即使更新 OS,很多仍沿用出廠時的 kernel,所以即使是同一個 Android 版本,不同裝置也可能不一樣。不論哪一種,全部失敗後約 2 分鐘就會放棄。Windows 依版本與設定從 1 秒或 3 秒開始拉長,重送次數為 2~4 次,因此 20~30 秒就會放棄(該電腦的值可用 netsh int tcp show global 的 Max SYN Retransmissions 確認)。
圖表上 剛開服或維護結束後暴增 · 連線嘗試次數、連線等待佇列溢位次數
查看位置 在伺服器的 nstat 查看 TcpExtListenOverflows、TcpExtListenDrops,以及 dmesg 的「Possible SYN flooding on port」警告,並用 ss -lnt 查看監聽 socket 的 Recv-Q(等待 accept 的連線數)是否碰到 Send-Q(backlog 上限)。用伺服器端擷取確認 SYN 是否抵達、是否回傳 SYN-ACK 符合的跡象 維護剛結束連線暴增時,TcpExtListenOverflows 增加,Recv-Q 貼著 Send-Q。擷取中同一個用戶端的 SYN 以整秒間隔重複送來,伺服器卻沒有回應 不符合的跡象 SYN 沒有到達伺服器、伺服器計數器也沒有變化時,是前端的防火牆或 DDoS 防護丟棄了 SYN,要查該設備的 SYN 限制與丟棄 log。伺服器已送出 SYN-ACK 但連線仍慢時,是回程方向的遺失 確認方式 用基礎設施工具確認(不需要遊戲程式碼)
出處 11 筆
各情境處理流程
更新後 lag 特定更新或部署之後,lag 回報增加時。適用於「這次更新後就怪怪的」這類回報集中出現,或圖表從某個時間點起階梯式上升並維持不降的情況。
確定開始時間,收集前後所有變更 : 找出回報最初集中的時間與圖表階梯式上升的時間,把前後發布的變更全部列出來。用戶端更新、伺服器部署、設定變更、DB schema 變更(DDL)與重新啟動、網路與防火牆作業、基礎設施更換(執行個體類型、kernel、驅動程式)都要一起看。每次部署時用監控工具的註記(annotation)功能在所有圖表上留下垂直線,這一步很快就能完成。遊戲更新與基礎設施作業若在同一個維護時段發布,兩者都要留作候選。優先聯絡:發布變更的遊戲開發團隊與基礎設施團隊雙方。 (部署與重新啟動 , OS、kernel、驅動程式、韌體更新後的效能變化 , 營運中 schema 變更(DDL)的鎖定 , 執行計畫改變造成的查詢延遲 , 冷快取(剛重新啟動時) ) 切分範圍:版本、裝置、伺服器、地區 : 先看異常集中在哪個面向。只有新版本的使用者有問題時懷疑用戶端;只有特定 OS、顯示卡、裝置有問題時懷疑用戶端效能或驅動程式;只有特定伺服器、頻道、zone 有問題時懷疑伺服器;只有特定國家、電信業者有問題時懷疑網路路徑;所有人同時出問題時,先懷疑共用資源(DB、負載平衡器、閘道)或剛發布的伺服器部署。用戶端遙測資料若有版本號,就把舊版本與新版本的 ping、FPS、畫格尖峰、斷線次數並排比較。ping 不變、只有 FPS 變差時,比起網路,更可能是用戶端效能的問題。優先聯絡:集中在版本或裝置時找遊戲開發團隊(用戶端);集中在伺服器或頻道時,主機指標正常找遊戲開發團隊(伺服器),異常則找基礎設施團隊(伺服器設備/OS);集中在國家或電信業者時找基礎設施團隊(網路)。 (畫格時間尖峰 , 主執行緒同步載入、著色器編譯 , 顯示記憶體(VRAM)不足 , 用戶端閃退 ) 在同一時段比較新版本與舊版本 : 只比較部署前後,會混入星期、時段、活動造成的變化,讓判斷變得模糊。可能的話,先把新版本部署到部分伺服器(金絲雀),與同一時段的舊版本伺服器(對照組)並排比較 tick 時間 p50 與 p99、超出 tick 預算的次數、CPU、記憶體與錯誤率。如果已經全面部署,就與上週同一天、同一時段比較。只看整個伺服器的平均值,部分伺服器或 zone 的問題會被掩蓋,所以要按伺服器與 zone 分開看。優先聯絡:遊戲開發團隊(伺服器)。 (超出 tick 預算 , 記憶體配置暴增 , 記憶體洩漏 , 廣播量暴增 ) 比較前後的流量特徵 : 即使不懂伺服器程式碼,也能用網路端看得到的數值,確認更新是否改變了流量的樣貌。比較前後的每位玩家每秒封包數(pps)與位元組數、平均與最大封包大小、連線數,以及每個 tick 一次送出的突發傳送量。UDP 封包開始超過路徑 MTU(通常是 1,500 位元組)時,就會發生 IP 分段。只要遺失一個分段,整個封包就遺失;也有 NAT 或防火牆會直接丟棄分段。途中經過 MTU 較小區段(通道、VPN)的玩家,只有大封包會消失。pps 增加時,要查是否碰到雲端執行個體的 PPS 上限,或防火牆、DDoS 防護設備的處理上限。優先聯絡:特徵有變時附上證據找遊戲開發團隊(伺服器);特徵不變、只有遺失與重傳增加時找基礎設施團隊(網路)。 (更新改變了流量模式 , UDP 封包的 IP 分段 , MTU 黑洞(只有大封包反覆遺失) , 超過雲端 PPS 上限 , 中間設備超過處理上限(防火牆、IPS、DDoS 防護) , 突發傳送造成淺緩衝區溢位 ) 比較前後 DB 查詢的種類與次數 : DB 延遲升高時,先看查詢數(QPS)是否也一起升高。PostgreSQL 的 pg_stat_statements 與 MySQL Performance Schema 的 digest 彙總,會把只有值不同的查詢歸為同一類,統計執行次數與總時間;比較更新前後的前幾名查詢清單,就能找出新出現的查詢、次數增加好幾倍的查詢(N+1),以及沒用索引而讀取整張資料表的查詢(MySQL 看 SUM_NO_INDEX_USED 欄位)。優先聯絡:QPS 或查詢樣貌有變時找遊戲開發團隊(伺服器);查詢相同、只有延遲增加時找基礎設施團隊(DB:執行計畫、IOPS、鎖定)。 (沒有索引的查詢 , 登入暴增與 N+1 查詢 , 執行計畫改變造成的查詢延遲 , Cache stampede ) 用主機與伺服器處理程序的指標切分層級 : 不需要程式碼,用 OS 上看得到的數值區分問題在伺服器內部還是主機。伺服器 socket 的接收佇列(Recv-Q)堆積,表示伺服器處理程序沒有及時讀取(tick 停住、GC、鎖);只有一個執行緒 100% 是單執行緒瓶頸;GC log 的暫停時間變長,表示記憶體使用模式改變了。也要確認是否以調高的 log 等級部署,導致 log 寫入增加。反過來,CPU steal、CPU 節流、NIC 丟棄(drop)增加時,要查同一時間變更的基礎設施(執行個體類型、kernel、容器上限)。優先聯絡:處理程序內部的訊號找遊戲開發團隊(伺服器),主機的訊號找基礎設施團隊(伺服器設備/OS)。 (伺服器 GC 全面暫停 , 單執行緒區域過載(熱點) , 同步寫入 log , 容器 CPU 節流(CFS 配額) , CPU steal(虛擬機器) , OS、kernel、驅動程式、韌體更新後的效能變化 ) 還原以確認原因,並留下紀錄 : 把最可能的變更只在部分伺服器或部分玩家身上還原(回復部署、關閉功能開關),或把設定改回之前的值,看症狀是否一起消失。只有還原的那一邊變好,原因就能確定。還原作業本身也可能因重新啟動與冷快取而暫時變慢,不急的話就在離峰時段進行。結果要連同原因 ID 記錄在事故紀錄中,並把封包大小、查詢數、tick 時間上限列入下次更新的部署前檢查項目。優先聯絡:發布變更的團隊。 (部署與重新啟動 , 冷快取(剛重新啟動時) )
新增海外國家/地區 開放新的服務國家,或新增區域、資料中心時。開服前的檢查,以及分辨「國內沒問題,只有新國家的玩家 lag」這類回報時,都可以使用。
開服前測量當地各電信業者的路徑品質 : 針對目標國家的主要電信業者(ASN),逐一測量到遊戲伺服器候選位置的往返時間(RTT)分布、抖動(jitter,封包抵達間隔忽長忽短)與遺失。單一平均值會掩蓋電信業者之間的差異,所以要看各電信業者的中位數與第 95 百分位數,並分成晚間尖峰與凌晨來看。公開量測網路 RIPE Atlas 可以指定國家與 ASN,從全球的探針(probe)發送 ping 與 traceroute;也可以在候選區域開臨時 VM 來測量。中間設備有時會限制 ICMP 回應,所以可能的話,也要用與遊戲相同的協定與 port 測量。只有特定電信業者特別繞經遠方城市時,就是 peering 或路由問題。電信業者比起延遲更重視成本,會選擇成本較低的路徑,所以近處也可能繞遠路。優先聯絡:基礎設施團隊(網路);路徑問題出在電信業者端時找外部(電信業者、IX)。 (傳播延遲(物理距離) , 繞遠路的路由 , 尖峰時段 peering 區段壅塞 , 海底電纜/國際線路故障 ) 把測量值與遊戲設計能承受的上限比較 : 把測得的 RTT 與抖動,拿來與遊戲的判定區間(閃避、格擋這類反應時間)、延遲補償上限、內插緩衝長度、輸入緩衝大小比較。例如格擋判定是 0.2 秒時,往返延遲加上內插緩衝超過這個值的電信業者用戶,即使及時反應也會太晚。若放寬延遲補償來配合,這次換成被打的一方回報「躲到牆後還被打到」的情況會增加。超過上限的電信業者很多時,基礎設施團隊要研究把區域或邊緣 PoP 設在更近的位置,遊戲開發團隊則要檢討判定、內插與延遲補償的數值。本白皮書的「同步方式」一章就是對照基準。優先聯絡:遊戲開發團隊(伺服器、用戶端:設計上限)、基礎設施團隊(網路:區域與 PoP 位置)。 (被 ping 吃掉的短判定區間 , 沒有延遲補償的判定 , 延遲補償過度 , 沒有內插緩衝或緩衝太短 ) 確認 MTU 與 UDP 能否通過 : 確認遊戲最大的封包能否在當地網路完整通過。以不同大小發送設定了禁止分段(DF)標記的 ping 來測量路徑 MTU,查看是否有 PPPoE、通道、行動網路這類小於 1,500 位元組的區段。UDP 這類資料包(datagram)傳輸的標準(RFC 8899)建議 IPv4 以 1,200 位元組作為大多數路徑都能通過的基本大小,遊戲的最大封包若大於這個值,要與遊戲開發團隊決定縮小或分開傳送的做法。也要確認公共 Wi-Fi、公司網路與部分電信業者是否封鎖 UDP 或遊戲 port,或限制速度,並查看被封鎖時有沒有替代路徑(TCP、443 port)。優先聯絡:基礎設施團隊(網路)與遊戲開發團隊(伺服器:封包大小)。 (MTU 不一致(只有大封包消失) , MTU 黑洞(只有大封包反覆遺失) , UDP 封包的 IP 分段 , 國家/電信業者層級的 UDP 限制與封包檢測 , 公共 Wi-Fi/公司網路限制 , 電信業者限速與流量管理 ) 測量 NAT、CGNAT 的閒置逾時,調整心跳封包間隔 : 測量當地家用分享器與行動網路(CGNAT)過多久會刪除閒置 UDP 連線的 mapping(位址與 port 的對應紀錄)。每次測試時,先從測試裝置送一個封包到伺服器建立 mapping,之後裝置不再送任何東西,讓伺服器在設定的時間(30 秒、60 秒、120 秒……)過後送封包到裝置。裝置開始收不到這個封包的時間,就是這個網路的閒置逾時。標準(RFC 4787)規定 UDP mapping 的過期時間不得短於 2 分鐘,並建議預設 5 分鐘以上,但各設備的數值差異很大,也有刪得更快的設備。mapping 只有靠從裝置送出的封包才能確實更新,所以心跳封包要由用戶端送出,並確認間隔不超過測得值、負載平衡器與雲端安全群組閒置逾時之中最短值的一半。優先聯絡:遊戲開發團隊(用戶端:心跳封包間隔;伺服器:逾時值)、基礎設施團隊(負載平衡器與安全群組設定)。 (NAT mapping 過期 , 電信業者共用 IP(CGNAT) , 連線途中 NAT 或負載平衡器的 mapping 過期 , 負載平衡器閒置逾時 , 雲端安全群組的連線追蹤過期 ) 確認在當地會經過的外部服務與安全設備 : 確認當地的平台登入、付款、身分驗證是否以正常速度回應,當地 DNS 能否正確解析登入與更新伺服器的位址,CDN 是否從靠近該國的據點提供更新檔。查看 DDoS 防護與防火牆的國家封鎖規則與速率限制是否擋到新國家的 IP 網段,特別是多位用戶共用一個 IP 的 CGNAT 網段是否被整批封鎖。優先聯絡:基礎設施團隊(安全設備、DNS、CDN)、外部(平台、金流業者、電信業者)。 (依賴外部服務 , DNS 故障與延遲 , DDoS 防護導流與誤判 , 電信業者共用 IP(CGNAT) ) 開服後按國家與 ASN 分開看 : 在連線 log 與負載平衡器 log 的用戶端 IP 加上國家與 ASN,按國家與電信業者查看 RTT、重傳、斷線次數與原因(心跳封包逾時、RST、伺服器踢出)。可以用 MaxMind GeoLite ASN 這類免費資料庫把 IP 轉換為 ASN 與組織名稱,並依當地個資法規,把 IP 縮減為 /24 或 ASN 單位再保存。只集中在一個 ASN 時,先查該電信業者的路徑(基礎設施團隊、外部);整個新國家都差時,先查距離與設計上限(基礎設施團隊、遊戲開發團隊);只有晚間變差時,先查 peering 壅塞。如果只有部分玩家 ping 一直偏高,要與遊戲開發團隊(伺服器)一起確認是否因 GeoIP 錯誤、VPN、以隊長為準的分配而被分到遠方區域。合成監控正常、只有玩家端不好時,問題在玩家環境或用戶端。 (尖峰時段 peering 區段壅塞 , 繞遠路的路由 , 瓶頸佇列溢位(壅塞遺失) , 集中在特定電信業者玩家的驗證誤判 , 配對與區域分配錯誤 ) 確認遠地玩家對其他玩家造成的影響 : 遠地連線的玩家增加時,影響不只是那個人的畫面變差而已。延遲高的玩家,輸入會集中抵達,在其他人的畫面上只有那個角色以快轉的方式移動,還會被伺服器的速度與冷卻檢查擋下,出現拉回或技能被拒絕。在隊伍機制中,一個延遲高的玩家反應太晚就會讓整個隊伍失敗;在 lockstep 方式中,所有人都要等最慢的那個人。新國家開服後,要看既有玩家「只有特定角色看起來怪怪的」這類回報是否增加,並與遊戲開發團隊決定輸入緩衝、驗證容許值與配對地區分離。優先聯絡:遊戲開發團隊(伺服器)。 (慢的人在別人畫面上快轉移動 , 集中在特定電信業者玩家的驗證誤判 , 一個慢的隊友與王的機制 , Lockstep 中等待最慢的玩家 )
實際事故案例
只收錄遊戲公司與基礎設施業者自行公開的事後檢討。
CCP Games 2014: EVE Online HED-GP 大規模艦隊戰的伺服器過載 發生什麼事 2014 年 1 月的一篇回顧文章談到 HED-GP 星系的大規模艦隊戰,當時伺服器嚴重過載。Time Dilation(過載時放慢遊戲時間的功能)降到下限 10%、整個戰場進入慢動作之後,負載仍持續堆積;處理模組停止與重複運作的工作積壓程度(Dogma Lateness)最高達到遊戲時間 193 秒,換算成實際時間約 32 分鐘。規模幾乎相同的 2013 年 7 月 6VDT 戰役,最高為 42 秒(實際約 7 分鐘)。 原因 CCP 先聲明,效能分析工具本身會增加負載,這種情況下不會執行,所以無法確定原因,接著舉出兩個可能的主因。第一是戰鬥拖長,來不及處理的負載不斷累積。第二是無人機使用量增加:戰鬥期間部署的無人機數量(不重複計算)在 6VDT 為 21,123 架,在 HED-GP 為 38,852 架,多了 84%。一個人的行動必須通知所有看得到的人,這類傳送量會隨人數的平方(O(n²))增加,而無人機每次攻擊產生的訊息更多。無人機挑選攻擊目標的程式碼也常把同一戰場上所有可攻擊的目標全部掃過一遍,成本接近 n² 成長。 學到的教訓 人潮集中的單一區域處理量超過上限時,整個區域都會變成慢動作;戰鬥越久,積壓的處理越多,輸入延遲也越大。確認訊號是負責該區域的伺服器(節點)的 tick 時間、積壓工作量,以及人數與物件數;其他區域都正常是這類問題的特徵。主要負責單位是遊戲開發團隊(伺服器),要修改的是一個行動需要通知的對象範圍,以及 AI 搜尋目標的成本。放慢遊戲時間的設計無法消除過載,但能讓所有人以相同速度變慢,避免只有部分行動無止盡地積壓。 相關原因 廣播量暴增 , 超出 tick 預算 , 訊息佇列積壓 , 單執行緒區域過載(熱點) 原文 CCP Games
Riot Games 2015: 繞遠路的 League of Legends 流量與 Riot Direct 發生什麼事 這是 Riot Games 說明網際網路為何不適合即時遊戲的技術文章。一位 League of Legends 玩家回報的實際流量本來應該從舊金山直接送到波特蘭,卻經過洛杉磯、丹佛、西雅圖,直接走只要 14ms 的路程花了 70ms。Riot 說明,路由器滿載而丟棄封包時,其他英雄會在畫面上亂跳,投射物看起來像瞬移一樣。 原因 Riot 指出原因在路徑與路由器。比起延遲最短的路徑,骨幹業者與電信業者更傾向把流量送往成本最低的路徑;BGP 決定的路徑若繞遠路,經過的路由器也會變多。路由器的處理負擔取決於封包數量,與封包大小無關。遊戲封包約 55 位元組左右,同樣的資料量下,封包數是 1,500 位元組封包的 27 倍,填滿路由器輸入緩衝區的速度也快上同樣倍數。依 Riot 的說明,許多路由器在過載時會先丟棄 UDP 封包。Riot 的解決方案是建立自有網路 Riot Direct:在美國 10 個大型網際網路據點架設路由器,並與盡可能多的電信業者直接互連(peering)。根據系列第 2 篇,以 ping 不到 80ms 遊玩的玩家比例在 9 個多月內從 31% 升到 50%,遊戲伺服器搬到芝加哥後,一夜之間達到 80%。 學到的教訓 即使在同一個國家,如果只有特定電信業者的用戶 ping 特別高,就要懷疑路徑。確認訊號是各電信業者(ASN)的 RTT 分布,以及 traceroute 顯示的途經城市。主要負責單位是基礎設施團隊(網路),修正方式是與電信業者直接 peering、連接 IX(網際網路交換中心),以及選擇伺服器位置。電信業者端的路由政策需要與外部(電信業者)協商。這個案例也顯示,光是把伺服器移到靠近玩家分布中心的位置,效果就很大。 相關原因 繞遠路的路由 , 傳播延遲(物理距離) , 瓶頸佇列溢位(壅塞遺失) 原文 Riot Games
Riot Games 2020: League of Legends 歐洲、巴西伺服器的邊緣主機過載 發生什麼事 2020 年 2 月底,League of Legends 的 EUW、EUNE、BR 伺服器多次發生事故,新開始的對局數大幅減少。配對、遊戲伺服器等後端服務狀態全都正常,但幾乎沒有流量進來。Riot 為了避免在可能不穩定的叢集上開放錦標賽模式(Clash),把時程延後一週。事後檢討報告沒有寫出每次事故持續多久。 原因 三件事疊在一起。送往某個服務的請求格式有誤,在特定情況下不斷失敗、不斷重試,請求量因此暴增。容器系統與 OS 版本之間有已知的相容性問題,造成 OS 內部記憶體洩漏,而升級只在 Riot 全部容器環境中約 60% 完成,歐洲與拉丁美洲叢集還在進行中。接收網際網路流量、過濾後轉送到後端的邊緣(edge)容器,在同一個 shard(伺服器群)內會分散部署,但不同 shard 之間沒有這種限制,所以每次事故時,至少有三個 shard 的邊緣容器集中在同一台主機上。暴增的重試壓在這台主機上,記憶體洩漏則讓這台主機停擺。 學到的教訓 後端服務都回報「正常,但流量進不來」時,就要查它們前面那一層(邊緣、閘道、負載平衡器)。確認訊號是各主機傳入連線數是否偏向少數主機,以及特定請求的失敗與重試比率。主要負責單位是遊戲開發團隊(伺服器:錯誤的請求與重試方式),容器部署規則、OS 升級與連線集中警示則由基礎設施團隊(伺服器設備/OS)負責。Riot 修正了請求程式碼,讓重試不再暴增,並在實作 shard 之間的分散部署之前,先加上連線集中警示。 相關原因 經由閘道/proxy , 連鎖故障 原文 Riot Games
Riot Games 2021: League of Legends EUW 5 小時事故:一個附屬 DB 讓整個伺服器停擺 發生什麼事 2021 年 1 月 22 日,League of Legends EUW 伺服器有 5 個多小時無法正常運作。登入玩家數與遊戲中玩家數兩項指標同時中斷,兩次重新啟動之間,登入人數雖然增加,對局卻幾乎沒有開始。 原因 負責非關鍵功能的 DB 主伺服器發生硬體故障,而這個 DB 沒有設定自動容錯移轉到備用伺服器。各 DB 的連線池雖然分開,所有連線池卻共用同一個執行緒池;送往故障 DB 的工作一直沒有結束、持續佔用執行緒,整個系統可用的執行緒因此耗盡。大量警示湧入時,團隊先懷疑最近遭遇的惡意網路攻擊與其他地區的硬體作業,故障 DB 的警示約 1 小時後才被注意到。所有系統都在同一個 JVM 中執行,重新啟動後在重新連線的負載下,GC 每次讓處理程序暫停幾秒,指標收集也出現很大的空白。登入排隊也沒有遵守設定的上限,湧入的玩家忽多忽少。 學到的教訓 一個被認為不重要的附屬 DB,也可能透過執行緒池這類共用資源讓整體停擺。確認訊號是各 DB 等待中的請求數、執行緒池使用率,以及對局開始數相對於登入數過低的比例。負責單位是遊戲開發團隊(伺服器:執行緒池隔離、逾時)與基礎設施團隊(DB:自動容錯移轉)。大量警示湧入時,很容易先懷疑最近遇過的問題(例如攻擊),所以要依判定順序(範圍 → 時間點 → 層級)逐一排除。重新啟動後,也要一併確認登入排隊是否依設定限制湧入量。 相關原因 執行緒池耗盡 , DB 容錯移轉 , 連鎖故障 , 伺服器 GC 全面暫停 原文 Riot Games
Roblox 2021: Roblox 73 小時事故:服務探索(Consul)叢集的資源競爭 發生什麼事 事故始於 2021 年 10 月 28 日下午(太平洋時間)一台 Consul 伺服器的 CPU 高負載;16:35 在線玩家數掉到平時的一半,接著整個服務停擺。直到 10 月 31 日 16:45,所有玩家才能重新進入,距事故開始已過了 73 小時。Roblox 表示每天有 5 千萬人使用。 原因 Roblox 用 HashiCorp Consul 處理服務探索(服務之間互相找到對方位址的功能)、健康檢查與 KV 儲存,而一個 Consul 叢集同時承擔多種工作負載。根本原因有兩個。第一,Consul 新的 streaming 功能在幾個月間逐步擴大使用範圍,事故前一天也在流量路由服務上啟用,並把該服務的節點數增加 50%;在讀寫都非常大量的負載下,這項功能在單一共用資源(Go channel)上造成競爭。事故期間換上了核心數更多的雙插槽(NUMA)伺服器,在這些伺服器上競爭更嚴重。第二,Consul 用來儲存 Raft log 的 BoltDB,其空閒頁面清單(freelist)管理變得異常緩慢,每追加 16kB 以下的資料就要寫入 7.8MB 到磁碟。平時不到 300ms 的 KV 寫入延遲中位數升到 2 秒,在緩慢的 leader 伺服器上還觀察到 TCP 緩衝區塞滿的 zero window。遙測(telemetry)依賴 Consul,找原因所需的指標也跟著消失。 學到的教訓 許多服務共同依賴的基礎系統(服務探索、設定儲存、驗證)一旦變慢,所有功能會同時停擺。確認訊號是該系統的寫入延遲、leader 切換與 CPU,以及事故前剛做的設定變更。負責單位是遊戲開發團隊(伺服器)與基礎設施團隊(伺服器設備/OS)雙方。監控必須與受監控的系統分開、不依賴它,事故期間才看得到指標。復原時快取是空的,一次全部放人進來可能再次崩潰,所以 Roblox 透過 DNS 調整可進入的玩家比例,每次增加約 10%。 相關原因 連鎖故障 , 鎖競爭 , Zero window(看起來像重傳的停頓) , 冷快取(剛重新啟動時) 原文 Roblox
Square Enix 2021: FINAL FANTASY XIV 資料片上市的壅塞與登入排隊錯誤 發生什麼事 2021 年 12 月,從資料片 Endwalker 的搶先體驗開始,各 World 都極度壅塞。登入排隊變長,在角色選擇畫面登入時或排隊等候中,經常出現 Error 2002。部分 World 與 zone 也曾當機(Error 3001),也出現過排隊逾時(Error 4004)。到 12 月 11 日公告時,搶先體驗進入第 8 天,壅塞仍在持續。 原因 Error 2002 會在兩種情況下發生。第一種是每個邏輯資料中心的排隊人數超過 17,000 人時;這是為了避免排隊過長導致登入伺服器當機而設的上限,此時用戶端會完全關閉。12 月 7 日把開發用的備用設備投入大廳伺服器、提高上限後,這個錯誤減少了,排隊卻反而變得更長。第二種是排隊中玩家的線路不穩定時。等待時間拉長後,網際網路路徑上的封包遺失或 Wi-Fi 不穩造成短暫斷線的情況變多。大廳伺服器會等待重新連線數十秒到 1 分鐘左右,在這段時間內連回就能從排隊中原本的位置接續,超過時間就得排到最後面。Square Enix 表示大部分回報都屬於這種情況。由於半導體短缺,也無法立即增加 World。 學到的教訓 排隊越長,排隊中玩家短暫的線路中斷就越容易變成連線錯誤。即使是同樣的壅塞,錯誤也會集中在使用 Wi-Fi 或不穩定線路的人身上,成為「只有部分人」遇到的問題。確認訊號是排隊長度、等待時間,以及斷線原因中排隊時斷線的比例。主要負責單位是遊戲開發團隊(伺服器:排隊上限與重新連線寬限時間),大廳與 World 伺服器擴充則由基礎設施團隊協同處理。重新連線寬限時間留得充裕,就能減少玩家線路短暫中斷演變成失去排隊順位的情況。 相關原因 登入排隊上限與重新連線寬限不足 , Wi-Fi 干擾與訊號減弱 , 無線區段的封包遺失 原文 Square Enix
Cloudflare 2020: Cloudflare 骨幹設定錯誤導致部分城市的流量遺失 發生什麼事 許多遊戲把網站、API 與 DDoS 防護交給 CDN 業者,因此這是遊戲也會一起受影響的基礎設施事故類型。2020 年 7 月 17 日 21:12 到 21:39(UTC)的 27 分鐘內,Cloudflare 整個網路的流量減少約 50%。影響僅限於連接骨幹的美國、歐洲、俄羅斯、巴西部分城市據點,其他據點正常。 原因 紐華克–芝加哥骨幹區段故障,使亞特蘭大–華盛頓區段壅塞,工程師為了減輕亞特蘭大的骨幹流量而修改路由器設定。原本應該停用整個政策項目(term),卻只停用了其中的條件(prefix-list),結果亞特蘭大路由器以更高的優先順序(local-preference 200)把所有 BGP 路由散布到整個骨幹。各據點為通往自家伺服器的路由所設定的優先順序是 100,因此連接骨幹的據點流量全都湧向亞特蘭大。亞特蘭大過載,受影響的據點則幾乎沒有流量可處理。把亞特蘭大路由器從骨幹移除後即恢復。Cloudflare 表示這與攻擊或入侵無關。 學到的教訓 如果只有特定城市或地區的玩家同時遇到斷線或連不上/無限讀取,其他人都正常,就先懷疑剛做過的路由設定變更。圖表上只有一個據點的 CPU 與流量往上衝,受影響的據點反而掉到接近 0。主要負責單位是基礎設施團隊(網路),若是業者端的故障則屬於外部。Cloudflare 決定為骨幹 BGP session 設定可接收的路由數上限(maximum-prefix),並調整優先順序,讓單一據點無法把其他據點的流量拉走。 相關原因 BGP 路由變更與收斂 , 路由變更、ECMP 不良路徑 原文 Cloudflare
Fastly 2021: Fastly CDN 全球性錯誤 發生什麼事 許多遊戲透過 CDN 發送更新檔、啟動器與網頁,因此這是遊戲也會一起受影響的基礎設施事故類型。2021 年 6 月 8 日 09:47(UTC)起,Fastly 網路有 85% 回傳錯誤。49 分鐘內網路的 95% 恢復正常,12:35 事故平息。 原因 5 月 12 日開始的軟體部署中,含有一個特定客戶設定遇到特定條件時就會觸發的 bug。6 月 8 日,一位客戶推送了正常的設定變更,剛好符合這個條件。Fastly 在 1 分鐘內偵測到異常,找出並停用造成問題的客戶設定後開始恢復。修正 bug 的部署在同一天 17:25 開始。 學到的教訓 已部署好幾週的程式碼,遇到罕見條件時也可能瞬間變成全球事故。遊戲端的確認訊號是更新、啟動器、網頁請求的 HTTP 錯誤率在所有地區同時升高,以及 CDN 業者的狀態頁面。已建立的遊戲連線若不經過 CDN 就不受影響,只有新連線、更新下載與網頁登入受阻,這是此類事故的特徵。主要負責單位是外部(CDN 業者),遊戲開發團隊與基礎設施團隊要預先準備替代路徑,例如同時使用兩家以上的 CDN,或直接從來源伺服器(origin)下載。 相關原因 依賴外部服務 原文 Fastly
Meta 2021: 一道骨幹指令讓 Facebook 連 DNS 都消失的事故 發生什麼事 這是一起同樣適用於遊戲公司自有網路與 DNS 的基礎設施事故。2021 年 10 月 4 日,Facebook(現為 Meta)的服務在全球都無法連線。連接各資料中心的骨幹全部中斷,網際網路端也找不到 Facebook 的 DNS 伺服器。事後檢討報告沒有寫出事故持續了多久。 原因 例行維護作業中,為了確認全球骨幹容量而下的指令,意外切斷了骨幹的所有連線,而原本應該擋下這類指令的稽核工具因為 bug 沒有擋住。小型據點的 DNS 伺服器設計成無法與資料中心通訊時,會判定自己異常並撤回 BGP 宣告,所以 DNS 伺服器明明還在運作,網際網路上卻連不到。平常的連線路徑與頻外(out-of-band)管理連線都中斷,內部工具也失去 DNS,只好派工程師親自到資料中心,又因為安全程序多花了時間。復原時,各資料中心的用電量都少了數十 MW,研判一次全部恢復可能讓電力設備到快取都陷入風險,因此分階段提高負載。 學到的教訓 所有地區、所有電信業者同時出現連不上/無限讀取時,要先查 DNS 與 BGP 路由,再看遊戲伺服器。透過外部 DNS 查詢與公開的 BGP 路由資訊,在公司外部也能確認。主要負責單位是基礎設施團隊(網路)。要事先檢查事故時使用的頻外連線路徑與內部工具是否依賴同一套 DNS 與網路;復原時分階段提高負載,避免重新連線一次湧入。 相關原因 BGP 路由變更與收斂 , DNS 故障與延遲 原文 Meta
AWS 2021: AWS us-east-1 內部網路壅塞 發生什麼事 許多遊戲把伺服器、登入與資料放在公有雲上,因此這是遊戲也會一起受影響的基礎設施事故類型。2021 年 12 月 7 日上午 7:30(太平洋標準時間),北維吉尼亞區域(us-east-1)的內部網路發生壅塞。上午 7:33 起 EC2 API 錯誤與延遲增加,難以啟動新的執行個體(執行個體啟動於下午 2:40 恢復),接著出現主控台登入失敗、無法變更 Route 53 設定、CloudWatch 指標延遲與部分遺失。網路設備在下午 2:22 完全恢復。已在執行的 EC2 執行個體與既有的 DNS 回應不受影響。 原因 一項為主網路中某個服務擴充容量的自動作業,在內部網路的大量用戶端上引發非預期的行為,連線嘗試因此暴增。連接內部網路與主網路的設備超出負荷,通訊出現延遲,延遲又讓連線嘗試與重試增加,壅塞因此持續。用戶端本來具有在這種壅塞時拉長請求間隔的退避(backoff)機制,卻因為潛在缺陷而沒有正常運作。內部監控也依賴同一個網路,維運團隊只能在沒有即時指標的情況下靠 log 應變。 學到的教訓 重試無法拉長間隔時,短暫的壅塞就會變成長達幾小時的事故。從遊戲端來看,已在執行的遊戲伺服器可能正常,但新伺服器擴充(自動擴展)、使用雲端 API 的登入、配對、付款,以及監控,可能會同時受阻。確認訊號是雲端供應商的狀態頁面、雲端 API 錯誤率與執行個體啟動失敗。主要負責單位是外部(雲端供應商);遊戲開發團隊要為所有重試加上隨機間隔的指數退避與次數限制,基礎設施團隊則要準備好即使無法擴充也撐得住的餘裕容量,以及其他區域的備案。 相關原因 連鎖故障 , 自動擴展延遲 , 依賴外部服務 原文 AWS
Cloudflare 2025: Cloudflare 公用 DNS 1.1.1.1 事故 發生什麼事 這是玩家自己在裝置或分享器上設定使用的公用 DNS 解析器(resolver)發生的事故。這類事故的特點是只有使用這項設定的玩家會遇到,而且這些玩家的所有遊戲與服務會同時受阻。2025 年 7 月 14 日 21:52 到 22:54(UTC)的 62 分鐘內,1.1.1.1 解析器在全球都沒有回應。Cloudflare 表示,對許多使用者來說,這等於幾乎所有網際網路服務都無法使用。UDP、TCP、DNS over TLS 查詢受到影響,以網域名稱連線的 DNS over HTTPS 則相對穩定。 原因 6 月 6 日為日後要用的另一個服務準備服務拓撲(決定在哪些據點宣告哪些 IP 網段的組態)時,1.1.1.1 解析器的 IP 網段被誤綁進這份組態。7 月 14 日變更這個服務的組態後,宣告解析器網段的據點從全部據點縮減為一個離線據點,全球的 BGP 路由因此撤回。這項變更沒有經過金絲雀(canary)部署,直接擴散到所有資料中心。22:20 還原設定後,流量恢復到約 77%,但這段期間約 23% 的邊緣伺服器上必要的 IP 設定已被刪除,重新設定又花了時間,直到 22:54 才恢復正常。Cloudflare 表示這是與攻擊或 BGP 劫持無關的內部設定錯誤。 學到的教訓 遊戲伺服器與其他玩家都正常,只有部分玩家在登入、更新伺服器上出現連不上/無限讀取時,要懷疑這些玩家使用的 DNS。已連線的 session 維持不變、只有新連線失敗,是這類問題的特徵。請玩家更換 DNS 設定,或直接查詢伺服器位址試試,馬上就能分辨。主要負責單位是外部(DNS 營運者、電信業者);遊戲開發團隊(用戶端)若把名稱解析失敗與其他錯誤分開提示,客服就能立刻判定。 相關原因 DNS 故障與延遲 , BGP 路由變更與收斂 原文 Cloudflare
AWS 2025: AWS us-east-1 DynamoDB DNS 事故與漫長的復原 發生什麼事 許多遊戲把伺服器、登入與資料放在公有雲上,因此這是遊戲也會一起受影響的基礎設施事故類型。從 2025 年 10 月 19 日晚上 11:48 到 20 日下午 2:20(太平洋夏令時間),北維吉尼亞區域分三個階段持續受到影響。到 20 日凌晨 2:40 為止 DynamoDB API 錯誤增加;凌晨 2:25 到上午 10:36 新的 EC2 執行個體啟動失敗(部分新執行個體的連線問題於下午 1:50 解除);上午 5:30 到下午 2:09 部分 Network Load Balancer(NLB)的連線錯誤增加。 原因 管理 DynamoDB DNS 的自動化系統中存在潛在的競爭條件(race condition)。在不同可用區域套用 DNS 計畫的執行器(DNS Enactor)中,有一個延遲得特別嚴重,它用舊計畫覆蓋了新計畫;緊接著,另一個執行器的清理作業刪除了這份舊計畫,區域端點(dynamodb.us-east-1.amazonaws.com)的 DNS 記錄因此變成空值。自動化無法修復這個狀況,只能由人工復原。EC2 的實體伺服器管理系統依賴 DynamoDB,這段期間每台實體伺服器維持的租約(lease)都過期了。DynamoDB 恢復後,實體伺服器數量太多,重新建立租約的作業還沒完成就逾時,重試的工作又再次堆積,陷入「壅塞崩潰(congestive collapse)」狀態。新啟動執行個體的網路設定傳播得慢,NLB 健康檢查在成功與失敗之間反覆,連正常節點也一再從 DNS 移除又加回。 學到的教訓 一處的 DNS 記錄錯誤會擴散到依賴該服務的其他服務,原因排除後,積壓的工作與反覆波動的健康檢查仍會讓復原多拖好幾個小時。從遊戲端來看,已在執行的伺服器或許撐得住,但無法啟動新伺服器,自動擴展會停擺;健康檢查不穩時,負載平衡器還可能把正常的伺服器移出。確認訊號是雲端狀態頁面、受管服務的 API 錯誤率、執行個體啟動失敗,以及負載平衡器的健康目標數。主要負責單位是外部(雲端供應商),基礎設施團隊要限制因健康檢查失敗而一次被移出的伺服器數量,並準備其他區域的備案。 相關原因 依賴外部服務 , 連鎖故障 , 自動擴展延遲 , 負載平衡器分配不均與健康檢查誤判 , DNS 故障與延遲 原文 AWS
名詞解釋
Ping Ping, RTT. 自己送出的訊號到伺服器再回來所花的時間(往返)。遊戲裡顯示的 ping 有時也包含伺服器處理的等待時間。
延遲 Latency. 封包從出發到抵達所花的時間。通常只指單一方向,所以大約是 ping 的一半。
抖動 Jitter. 封包抵達間隔忽長忽短的程度。即使平均 ping 相同,抖動大時畫面就會卡頓。
封包 Packet. 在網路上一次送出的一包資料。通常最大 1,500 位元組,遊戲的狀態更新則是數十到數百位元組。
封包遺失 Packet loss. 送出的封包沒有抵達,在途中消失。使用 TCP 的遊戲只要 1% 就能感覺到每隔幾秒到十幾秒頓一下;具備內插與輸入重複傳送的 UDP 遊戲,有時到幾 % 都還遮得住。
頻寬 Bandwidth. 線路每秒能傳送的最大資料量(Mbps)。和多快送達(延遲)是不同的概念。
Tick Tick. 伺服器計算一次遊戲狀態的單位。20 tick 的伺服器每秒計算 20 次,也就是每 50ms 一次。
Tick rate Tick rate. 每秒跑幾次 tick。越高反應越快,但伺服器成本和傳輸量也會增加。為了節省傳輸量,送封包的頻率有時會設得比 tick rate 低。
Tick 預算 Tick budget. 跑完一次 tick 的時間上限。超過的話下一個 tick 會延後,tick 間隔因此拉長。
FPS Frames per second. 每秒繪製畫面的次數。60FPS 代表一個畫格 16.7ms。
畫格時間 Frame time. 繪製一個畫格所花的時間。對體感來說,偶爾飆高的畫格比平均 FPS 更重要。
快照 Snapshot. 伺服器每個 tick 送出的「目前遊戲狀態」摘要,內含位置、血量、狀態等。通常只挑出和接收端現有狀態不同的部分來送(差異壓縮)。
內插 Interpolation. 把收到的兩個快照之間連起來繪製,讓畫面看起來流暢的技術。代價是呈現的畫面會稍微落後。
內插緩衝 Interpolation buffer. 為了內插而刻意延後繪製的時間,是吸收抖動和一兩個遺失封包的緩衝時間。通常是封包間隔的 2 倍(每秒收 20 次就是 100ms),也有遊戲會在抖動變大時自動加長。
Extrapolation, Dead reckoning. 沒有新封包時,用最後的速度推測接下來會在哪裡並繪製出來的技術。猜錯時看起來就像瞬移,所以很多遊戲只推測 0.25 秒左右就停下(Source 引擎預設值 0.25 秒)。
用戶端預測 Client-side prediction. 不等伺服器確認,先讓自己的角色動起來的技術。
伺服器校正 Reconciliation. 伺服器結果回來後,與預測比對並修正自己角色的位置。做法是從伺服器確認過的位置開始,重新套用尚未確認的輸入來計算。差距大時看起來就是拉回。
延遲補償 Lag compensation. 伺服器做攻擊判定時,回溯到攻擊者當時看到的過去時間點,確認是否命中的技術。為了不讓被打的一方太冤,回溯幅度會設上限。競技射擊遊戲常見 0.2~0.25 秒左右,也有像 Source 引擎預設值那樣回溯到 1 秒的。
權威伺服器 Authoritative server. 最終判定只由伺服器做的設計。可以防止作弊,但所有結果都要經過一次伺服器往返,所以要用預測和先行演出掩蓋等待時間。
Lockstep Deterministic lockstep. 所有人只交換輸入,在同一回合做完全相同計算的方式。輸入會加上固定延遲,只要有一個人的輸入晚到,所有人都要等。
伺服器輸入緩衝 Server-side input buffer. 伺服器替每個人先存一點輸入,每個 tick 取出一個來用的緩衝。抖動大的人在別人眼中也會很流暢,但這個人的動作在伺服器上確定的時間點也會相應延後。
Listen server Listen server. 由一名玩家的電腦一邊玩遊戲、一邊兼任伺服器的方式。房主的 ping 是 0,但房主的線路或電腦一慢,所有人都會 lag。
相位 Phasing. 即使在同一個地點,也會依任務進度顯示不同 NPC 與地形的功能。兩個角色進度不同時,只有一邊看不到 NPC 是正常的。
Rollback netcode Rollback netcode (GGPO). 先預測對手的輸入繼續進行,實際輸入不同時再倒回過去的畫格重新計算的方式。格鬥遊戲常用。和 DB 的回滾是不同的東西。
預輸入 Input buffer, spell queue. 在冷卻或動作結束前不久按下的下一個輸入先記下來,等結束的瞬間立刻執行。讓連段之間不會夾著一次往返時間。
先行演出 Client-side feedback. 不等伺服器確認,先播放動畫、音效、特效。只有傷害、獎勵這類需要確定的結果才等伺服器回應。伺服器拒絕時,已經演出的內容必須收回。
TCP Transmission Control Protocol. 依序、完整無缺地傳遞資料的協定。在重新收到遺失的封包之前,不會把後面的封包交給遊戲。
UDP User Datagram Protocol. 不做任何保證、送什麼就傳什麼的協定。沒有等待,但遺失與順序要由遊戲自己處理。
可靠 UDP Reliable UDP (KCP, ENet…). 在 UDP 之上,自行實作所需程度的重傳與順序保證的方式。
HOL 阻塞 Head-of-line blocking. 前面一個卡住,後面全部都得等的現象,是 TCP 造成快轉的原因。
RTO Retransmission timeout. 重傳計時器。TCP 判斷封包遺失後,到重新送出之前等待的時間。Linux 是 ping + 200ms 以上,每失敗一次就加倍。
Nagle 演算法 Nagle’s algorithm. 在先前送出的資料收到確認(ACK)之前,先把小筆資料湊在一起再一次送出,藉此減少封包數的 TCP 功能。遊戲通常要關掉。
TCP_NODELAY TCP_NODELAY. 關閉 Nagle 演算法的 socket 選項,小訊息會立刻送出。
延遲 ACK Delayed ACK. 把收到的確認稍微延後、和其他資料一起送出的功能。Linux 通常是 40ms(最多 200ms),Windows 舊版是 200ms,新版是 40ms。
Socket 緩衝區 SO_SNDBUF / SO_RCVBUF. OS 為每個 socket 配置的傳送、接收等待空間大小。太小會滿出來,太大則會讓舊資料堆積等待。
keepalive SO_KEEPALIVE. 確認閒置連線是否還活著的 TCP 功能。預設為關閉,就算開啟,預設值也要 2 小時後才確認。
RST TCP reset. 當場強制切斷連線的 TCP 訊號,還沒送出的資料會被丟棄。
心跳封包 Heartbeat. 遊戲自己定期送出的「我還活著」訊號,用來偵測斷掉的連線,並讓中間設備維持連線。
逾時 Timeout. 在這段時間內沒有回應就視為失敗的標準。太短會誤判,太長則太晚發現。
NAT Network Address Translation. 分享器讓家中多台裝置共用一個公用 IP 對外連線,並把連線記錄在 NAT 表的功能。
CGNAT Carrier-grade NAT. 電信業者讓多個用戶共用一個 IP 的大規模 NAT。
MTU Maximum Transmission Unit. 一次能送出的封包大小上限。通常是 1,500 位元組,經過 VPN、PPPoE 的路段會更小。
Bufferbloat Bufferbloat. 設備讓佇列堆得太大,使延遲增加到數百 ms 的現象。
SQM Smart Queue Management (fq_codel, CAKE). 讓佇列保持短小、並依各個資料流公平送出的分享器功能,是 bufferbloat 的解法。
QoS Quality of Service. 給予優先順序、讓重要流量先送出的功能。
Peering Peering. 電信業者之間互相連接網路的地方,晚上容易壅塞。
BGP Border Gateway Protocol. 電信業者之間互相告知網際網路上該走哪條路由的規則。一旦改變,路由和 ping 都會跟著變。
DDoS Distributed Denial of Service. 從許多來源送出大量流量、讓服務癱瘓的攻擊。
清洗中心 DDoS scrubbing center. DDoS 攻擊時,先接下送往伺服器的流量、濾掉攻擊,只把正常流量轉過去的防護業者據點。據點越遠,路徑就越長。
防火牆 Firewall. 只讓允許的連線通過的設備或程式,用 session 表追蹤連線。
負載平衡器 Load balancer. 把進來的連線分配到多台伺服器的設備。
Session 表 Session table, conntrack. 設備或 OS 用來追蹤目前連線的表,大小有上限。
Microburst Microburst. 平均流量不高,但在 1ms 以下的極短瞬間流量集中湧入的現象。
NIC Network Interface Card. 伺服器的網路卡。
Ring buffer Ring buffer. 把 NIC 收到的封包暫存到 CPU 取走為止的緩衝區。循環使用固定數量的 slot,slot 全滿時新封包就會被丟棄。
中斷 Interrupt. 裝置通知 CPU「有事要處理」的訊號。
RSS Receive Side Scaling. 把收到的封包分到多個接收佇列,讓多個 CPU 核心處理的 NIC 功能。
PPS Packets per second. 每秒封包數。遊戲伺服器常常在頻寬還有餘裕時,就先碰到這個數字的上限。
Kernel Kernel. 作業系統的核心部分,負責網路、記憶體與 CPU 分配。
backlog Listen backlog. 伺服器尚未接受的新連線請求所排的佇列。佇列滿了之後,Linux 會默默丟棄新請求,Windows 則回傳拒絕回應。
TIME_WAIT TIME_WAIT. 先關閉連線的一方為了防範晚到的封包,暫時(Linux 為 60 秒)保留該 port 組合的狀態。
CPU steal Steal time. 虛擬機器想用 CPU,但實體伺服器正把 CPU 分給其他虛擬機器,因而等待的時間。用 top 的 st 值查看。
CPU 節流 CFS throttling. 容器在固定週期(CFS period,通常 100ms)內用完 CPU 配額(quota)時,被強制暫停到下一個週期。
檔案描述子 File descriptor. 處理程序每開啟一個檔案或連線就會配給的編號(fd),數量有上限。
執行緒 Thread. 程式內獨立執行的工作單位,多個執行緒可以同時執行。
Context switch Context switch. CPU 把正在執行的執行緒換成另一個執行緒。這個動作本身有成本。
鎖 Lock, Mutex. 讓共用資料一次只能由一個執行緒使用的鎖定機制。
死結 Deadlock. 執行緒彼此等待對方持有的鎖,永遠停住的狀態。
執行緒池 Thread pool. 預先建立好的一組工作執行緒。全部都在忙時,新工作就得等。
非同步 I/O epoll, IOCP, io_uring. 不等待 I/O 完成,先做其他事,完成時再收到通知的方式。
AOI Area of Interest. 每位玩家「看得到的範圍」。只傳送範圍內的變化,以減少傳輸量。為了降低判斷誰在範圍內的成本,通常會把地圖切成格狀(grid),只看鄰近的格子。
廣播 Broadcast, fan-out. 把一個變化送給所有看得到它的人。聚集的人彼此都看得到時,要送的量會隨人數的平方成長。
GC Garbage collection. 自動回收用完不要的記憶體的功能。GC 進行中,程式有時會停住。
Heap Heap. 程式執行中隨需要配置來用的記憶體區域。
記憶體洩漏 Memory leak. 用完的記憶體沒有歸還,使用量持續增加的 bug。即使有 GC,只要某處還一直參照已經用完的物件,就會發生。
Swap Swap, paging. RAM 不夠時,把部分記憶體搬到磁碟上。要再用搬出去的記憶體時,速度比 RAM 慢 1,000 倍以上。
OOM killer Out-of-memory killer. 記憶體耗盡時,Linux 挑出用最多記憶體的處理程序強制結束的機制。容器只要碰到記憶體上限就會觸發。
快取未命中 Cache miss. CPU 旁邊的快取裡沒有需要的資料,必須到較慢的記憶體去拿。
IOPS I/O operations per second. 磁碟每秒能處理的讀寫次數。雲端磁碟的上限取決於付了多少錢。
fsync fsync. 等到資料確實寫進磁碟為止的指令。一般寫入會先放在 OS 記憶體裡,之後才寫進磁碟,中間若伺服器斷電,資料可能會消失。fsync 安全但慢。
Burst credit Burst credits. 雲端磁碟或伺服器累積的額度,讓它們能短時間發揮超過基準的效能。額度用完就會掉回基準效能。
索引 Index. DB 的索引。沒有索引就必須讀完整張資料表。
全表掃描 Full table scan. 不用索引,逐一檢查資料表所有資料列的查詢。
執行計畫 Query plan. DB 決定以什麼順序、用哪個索引來執行查詢的方法。即使程式碼沒變,只要 DB 換了執行計畫,同一個查詢也可能突然變慢。
Transaction Transaction. 綁成一組、「全部完成,或全部不做」的 DB 操作。遊戲內交易一定要用 transaction 處理。結束前會鎖住修改過的資料列,所以越短越好。
連線池 Connection pool. 預先建立好的一組 DB 連線。全部被占用時,新請求就要等待。
熱點資料列 Hot row. 許多請求同時想修改的同一筆資料列,是鎖競爭的成因。
複寫延遲 Replication lag. 複本 DB 跟不上主 DB 而落後的時間。
回滾 Rollback. 存檔被取消、回到先前的狀態。玩家會覺得「道具不見了」。
快取 Cache (Redis etc.). 把常用資料複製一份放在較快的地方,以減輕 DB 負載。
檢查點 Checkpoint. DB 定期把累積在記憶體中的變更一次寫入磁碟。在那個當下,存檔與查詢可能會短暫變慢。
容錯移轉 Failover. 主伺服器或主 DB 掛掉時切換到備援端。切換期間短暫無法存檔,若複寫落後,最後一部分資料可能會遺失。
MVCC Multi-version concurrency control. DB 為了讓讀取者和修改者互不阻擋,暫時保留舊版本資料的方式。只要有長時間未結束的 transaction,舊版本就會堆積而變慢。
Cache stampede Cache stampede. 快取同時失效,請求一口氣湧向原始資料來源(DB)的現象。
閘道 Gateway. 接收用戶端連線、再轉送給後端遊戲伺服器的中介伺服器。
斷路器 Circuit breaker. 對持續失敗的服務呼叫暫時切斷、直接當作失敗處理,以防止連鎖故障的機制。過一陣子會試著呼叫一兩次,確認恢復後再重新允許呼叫。
連鎖故障 Cascading failure. 一處的故障沿著呼叫鏈擴散到其他服務。
自動擴展 Autoscaling. 依負載自動增減伺服器數量的功能。擴展需要時間。
看門狗 Watchdog. 監視伺服器是否停住的計時器。遊戲迴圈停住超過設定時間(數秒到數十秒)時,會留下狀態紀錄(dump),並強制結束伺服器讓它重新啟動。
使用率 Utilization. worker(CPU 核心、執行緒、DB 連線這類處理請求的單位)忙碌時間所占的比例。超過 80~90% 後,等待時間會急遽增加。
p99 99th percentile. 100 次中有 99 次比它快、約 1 次比它慢的值。比平均值更能反映體感上的 lag。
V-Sync Vertical sync. 配合螢幕更新週期輸出畫格的功能。能消除畫面撕裂,但會產生輸入延遲;FPS 掉到更新率以下時,還可能在 60 和 30 之間來回切換而卡頓。
可變更新率 VRR, G-Sync, FreeSync. 讓螢幕配合畫格完成的時機更新畫面的功能,可減少 V-Sync 在 60 與 30 之間切換造成的卡頓與輸入延遲。
反作弊 Anti-cheat. 防止遊戲外掛的安全模組。定期檢查或與伺服器之間的心跳封包失敗時,也可能造成卡頓或斷線。
Overlay Overlay. 通訊軟體、錄影、FPS 顯示程式在遊戲畫面上疊加繪製的功能。因為會插進遊戲的繪製流程,可能造成卡頓。
著色器編譯 Shader compilation. 把圖形特效程式轉換成 GPU 用格式的作業。沒有事先做好的話,第一次看到時畫面會頓一下;更新顯示卡驅動程式後,已存下的結果會失效,必須重做。
主執行緒 Main thread, Game thread. 依序處理遊戲規則計算與畫面準備的核心執行緒。這裡只要有一件事耗時太久,畫面就會在那段時間停住。
計時器解析度 Timer resolution. 作業系統喚醒休眠中程式的最短間隔。Windows 預設值是 15.6ms,程式若沒有另外調整,即使要求「1ms 後叫醒我」也會晚醒。
過熱降頻 Thermal throttling. 裝置過熱時自動降低 CPU、GPU 速度的保護機制。手機玩遊戲幾分鐘到數十分鐘後很常發生。
VRAM Video memory. 顯示卡上的專用記憶體,貼圖與模型都放在這裡再繪製。不夠時得經由較慢的路徑和電腦記憶體來回搬資料,因而卡頓。
Net graph Net graph. 在遊戲畫面上以即時圖表顯示 ping、封包遺失、FPS、tick 的開發/除錯用顯示。回報 lag 的影片裡若一起錄到,找原因會容易得多。
重傳率 Retransmission rate. 送出的 TCP 封包中重送的比例。沒有公認標準,但整台伺服器平均低於 0.1% 算健康,超過 1% 就容易有很多玩家感到 lag。也要一併看比平常值多了幾倍。
SACK Selective ACK. 接收端詳細告知「這段收到了,只缺這部分」的 TCP 功能。即使遺失好幾個,也能一次補回。
RACK-TLP Recent ACK, Tail Loss Probe. 以時間為基準判斷遺失,一段時間沒收到 ACK 就把最後一個封包再送一次,讓復原提早的 TCP 功能。是新版 Linux、Android 的預設行為。Windows 從 10(1607)與 Server 2016 起預設啟用 TLP 與 RACK,連遺失的重傳也能補救的新版 RACK 則從 Server 2022 開始。只在啟用 SACK 的連線上運作。
不必要的重傳 Spurious retransmission. 封包其實沒遺失,只是晚到或順序顛倒,就被當成遺失而重送。既浪費線路,又白白降低傳輸量。
Zero window Zero window. 接收端緩衝區滿了,通知對方「先暫停傳送」的狀態。看起來像重傳,但線路正常,是接收端程式沒有及時讀取。
thin stream Thin stream. 像遊戲這樣零星送出小封包的連線。因為不容易湊齊觸發快速重傳的訊號,遺失時會停住很久。
Policer Policer. 超過設定速率的封包不進佇列、直接丟棄的限速方式。先放進佇列再慢慢送出的方式則稱為 shaper。
Pacing Pacing. 把要送的封包在時間上平均分散送出,避免一次全部倒出去。可以防止小緩衝區滿溢。
ECN Explicit Congestion Notification. 壅塞時不丟棄封包,改為加上「壅塞」標記,讓傳送端降低速度的功能。不必遺失封包就能通知壅塞。兩端與壅塞路段的設備都必須支援才有效果。
MSS Maximum Segment Size. TCP 單一封包承載資料的最大大小。通常是 1,460 位元組,配合通道路段調小可以避免 MTU 黑洞。
換手 Handover. 移動中的手機切換所連線的基地台。
百分位數 Percentile (p50, p95, p99). 把數值由小到大排列時,位於第幾 % 的值。p50 是中位數,p99 則接近 100 次中最慢那 1 次的值。能呈現被平均值掩蓋的飆高。
尾端延遲 Tail latency. 大部分都很快,偶爾才出現的長延遲。在平均值裡幾乎看不出來,卻是玩家記得的 lag。
合成監控 Synthetic monitoring. 由量測用的裝置或伺服器代替真實玩家,在固定地點定期發送 ping、traceroute 等,量測路徑品質。RIPE Atlas 是代表性的公開工具。
彙總間隔 Aggregation interval. 圖表上的一個點彙總了幾秒或幾分鐘的值。間隔越長,短暫的飆高就越會被平均稀釋掉。
事後檢討 Postmortem. 事故結束後,整理發生了什麼、為什麼發生、要改什麼的文件。比起究責,更重視防止再次發生。
C-state CPU idle state. CPU 閒置時進入的省電狀態。越深層越省電,但喚醒所需時間也越長。
即時遷移 Live migration. 雲端業者為了主機維護等原因,把執行中的虛擬機器搬到另一台主機。搬移的瞬間可能短暫停住。
SNAT Source NAT. 把送出封包的來源位址換成公用位址的 NAT。一個公用位址可用的 port 數有上限,用完時新連線就會失敗。
NAT 閘道 NAT gateway. 讓私有網路中的伺服器連到網際網路時共用一個公用位址的雲端元件。每個目的地的同時連線數有上限。
低軌衛星網路 LEO satellite internet. 透過高度數百到數千 km 的衛星群連線的網路。延遲比同步軌道衛星短得多,但切換連線衛星時延遲可能飆高。
GeoIP IP geolocation. 以 IP 位址推估國家、城市、電信業者的資料庫。其中有錯誤或過時的項目,有時會導致玩家被分配到遠方地區的伺服器。
TLS 憑證 TLS certificate. 證明伺服器確實是本尊的電子文件。有效期限一到就會讓加密連線失敗,無法連線。
畫格生成 Frame generation. 顯示卡在實際繪製的畫格之間插入預測畫格來提高 FPS 的技術。畫面會更流暢,但從輸入到畫面的延遲可能增加。
參考文獻
資料 616 筆,發行者 83 家。包括標準文件,kernel、OS、雲端、引擎、DB 的官方文件,論文,以及原開發商的技術文章。
Microsoft 85
Linux kernel 62
IETF 59
AWS 51
MySQL 32
Unity 26
PostgreSQL 25
ACM 20
Epic Games 19
Android (Google) 17 Android common kernels Android (Google) 5.10~6.18 的通用 kernel(common kernel)同時受到支援,舊平台用的 kernel(例:android14-6.1)也可用於新 Android 裝置的出廠或升級 ApplicationExitInfo Android (Google) REASON_LOW_MEMORY:系統的 low memory killer 結束了 App 處理程序(不支援的裝置會回報為 REASON_SIGNALED、SIGKILL) Cached apps freezer Android (Google) Android 14 以上會在 App 處理程序進入快取狀態 10 秒後將其凍結,凍結後所有執行緒都停止 Crashes Android (Google) 當機(crash)指 App 因未處理的例外或訊號(SIGSEGV 等)意外結束,由 Play Console 的 Android vitals 彙總 Frame Pacing library Android (Google) 60Hz 螢幕沒有新畫格時會再顯示上一個畫格;以 30FPS 遊戲的畫格時間變成 49、16、33ms 這樣忽長忽短為例 Memory allocation among processes Android (Google) Android 把記憶體壓縮到 zRAM 撐住,不夠時由 low memory killer 結束處理程序;前景 App 被結束時看起來像閃退 Network security configuration Android (Google) 使用憑證釘選時,必須一併放入備用金鑰以因應金鑰更換、CA 變更,否則在 App 更新前連線都會中斷 Optimize network access Android (Google) 無線狀態切換延遲與 tail 時間依無線技術(3G、LTE、5G)與電信業者設定而不同;3G 例:低功率 → 全功率約 1.5 秒,待機 → 全功率 2 秒以上 Read network state Android (Google) 預設網路改變後,新連線會走新網路,舊網路上的連線最後會被強制中斷;用 registerDefaultNetworkCallback 偵測切換 Security with network protocols Android (Google) 伺服器送出時少了中繼憑證,Android App 會以 SSLHandshakeException 失敗,但電腦瀏覽器可能用已取得的中繼憑證補上而不報錯;用 openssl s_client 確認伺服器送出的憑證鏈 Slow rendering Android (Google) 要達到 60FPS,一個畫格必須在 16ms 內畫完;來不及就會跳過畫格,看起來像卡頓(jank) Slow Sessions (games only) Android (Google) Android vitals 把超過 50ms(20FPS)或 34ms(30FPS)的遊戲畫格視為慢速畫格 TelephonyDisplayInfo Android (Google) OVERRIDE_NETWORK_TYPE_NR_NSA:連在 LTE 上,且可以或已經與 5G(NR)雙連結(EN-DC)時的網路類型顯示 Thermal API Android (Google) 裝置只能在有限時間內維持高效能,之後會因發熱而降頻;建議依熱狀態提前降低負載 Wi-Fi low-latency mode Android (Google) 低延遲模式會關閉 Wi-Fi 省電,掃描與漫遊設定的最佳化則依裝置製造商的實作而不同 WifiManager Android (Google) WIFI_MODE_FULL_LOW_LATENCY(API 29,Android 10):只在連上 AP、螢幕開啟且 App 位於前景時才生效的低延遲 Wi-Fi lock Window.setPreferMinimalPostProcessing Android (Google) 遊戲這類延遲很重要的視窗會要求顯示器進行最少的影像處理;以 HDMI 連接時會送出 ALLM、Game Content Type 訊號,把電視切換到低延遲模式
Linux man-pages 15
Microsoft Azure 12
Oracle 9
Redis 9 Diagnosing latency issues Redis 由單一執行緒依序處理請求,慢指令會擋住後面所有請求;用 SCAN 取代 KEYS;fork 在實體伺服器與新型 VM 上實測每 1GB 約 9~13ms;THP 會因 fork 後的複製造成延遲與記憶體暴增;同一秒大量過期時會停住 High availability with Redis Sentinel Redis 主伺服器故障時把複本升格的自動容錯移轉 INFO Redis keyspace_hits、keyspace_misses(key 查詢成功、失敗次數)、expired_keys(過期的 key 數)、uptime_in_seconds(啟動後經過的時間) KEYS Redis 在正式環境中務必極度謹慎使用,在大型 DB 上可能嚴重拖垮效能(入門級筆電上 100 萬個 key 需 40ms) Redis CLI Redis --bigkeys:掃描 keyspace 找出大型 key Redis latency monitoring Redis latency-monitor-threshold 預設為 0(關閉);LATENCY LATEST、LATENCY DOCTOR;記錄 fork、expire-cycle 等各事件的延遲 Redis persistence Redis 每隔幾分鐘建立一次 RDB 快照的話,就得接受異常關閉時遺失最後幾分鐘資料的風險 SLOWLOG Redis 記錄超過 slowlog-log-slower-than 之指令的慢指令 log,執行時間不含與用戶端往來的 I/O UNLINK Redis 立即移除 key、在其他執行緒回收記憶體的非同步刪除
Cloudflare 8
Gaffer On Games 7
Google Cloud 7
iproute2 7
Apple 6
Bufferbloat.net 6
Google 6
Microsoft SQL Server 6
Wireshark 6
.NET 5
OpenJDK 5
systemd 5
ITU 4
sysstat 4
Valve 4
AMD 3
CCP Games 3
chrony 3
Go 3
IEEE 3
Intel 3
IO Visor 3
Kubernetes 3
NVIDIA 3
perf 3
Riot Games 3
RIPE NCC 3
APNIC 2
Istio 2 Istio Standard Metrics Istio istio_request_duration_milliseconds(HTTP、gRPC 請求處理時間分布),以 reporter 標籤區分發送端(source)與接收端(destination)的 proxy Performance and Scalability Istio sidecar 模式下請求依序經過發送端與接收端的 sidecar proxy;功能加得越多,proxy 內的處理路徑越長,收集遙測資料(telemetry)也會拉長下一個請求的等待時間
Let's Encrypt 2
MaxMind 2
numactl 2
OpenSSL 2
SK텔레콤 2
Solidigm 2
Square Enix 2
USENIX 2
util-linux 2
Amazon Builders' Library 1
Apache Software Foundation 1 Asynchronous loggers Apache Software Foundation 非同步 log 用佇列吸收短暫的暴增,但輸出持續很慢時佇列會滿,速度降到最慢的輸出速度,或依政策丟棄 log(Discard)
coreutils 1
Envoy 1 What is Envoy Envoy Envoy 是在每台應用程式伺服器旁邊獨立執行的處理程序,應用程式透過 localhost 上的 Envoy 收發資料
ethtool 1
Frontiers 1
Game Developer 1
gdb 1
GDC 1
GGPO 1
GNU Project 1
HDMI Licensing Administrator 1
id Software 1
iputils 1
IRTF 1
jemalloc 1
Juniper Networks 1 Flow-Based Sessions Juniper Networks 實驗的公司防火牆:SRX 防火牆的預設 session 逾時為 TCP 1,800 秒(30 分鐘)、UDP 60 秒
Lua.org 1 Lua 5.4 Reference Manual Lua.org 漸進式模式把回收拆成小步驟,穿插在程式執行之間(步驟設得太大就會全面暫停);分代模式的 major 回收會走訪所有物件,屬於全面暫停;collectgarbage("count") 回傳 Lua 使用的記憶體總量(KB)
Meta 1
mtr 1
net-tools 1
netfilter 1
Netflix 1
Network Time Foundation 1
OpenWrt 1
procps-ng 1
Red Hat 1
Seagate 1
Starlink 1 Improving Starlink’s Latency Starlink 美國尖峰時段中位數 48.5ms→33ms,最慢的 1%(p99)超過 150ms→低於 65ms(2024 年),衛星單段傳播 1.8~3.6ms,經雷射鏈路繞行時延遲增加,地面站到網際網路接入點(PoP)的距離也是延遲因素
VLDB Endowment 1
과학기술정보통신부 1