遊戲 Lag 白皮書 › L12 資料庫
登入暴增與 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 查詢的函式庫)的延遲載入,會在開發者沒察覺的情況下產生這類查詢。開發伺服器上只有幾個角色,看不出差異,要到正式環境大量同時登入時才會浮現。
出處
- Efficient Querying .NET
ORM 的延遲載入會造成每個項目多送一次查詢的 N+1 問題,使效能大幅下降;建議一次合併載入(eager loading) - pg_stat_statements — track statistics of SQL planning and execution PostgreSQL
收集每個 SQL 陳述式的執行次數(calls)與總執行時間,列出呼叫次數多的查詢排行 - Performance Schema Statement Digests and Sampling MySQL
用 events_statements_summary_by_digest 把形式相同的查詢歸為一組,彙總次數與時間 - Statement Summary Tables MySQL
摘要資料表的 COUNT_STAR(執行次數)、SUM_TIMER_WAIT(總時間) - Server Status Variables MySQL
Questions:用戶端送出的陳述式數量
相關原因
同一層:L12 資料庫
同一症狀(連不上/無限讀取)在其他層的原因
查看含圖解與實驗的完整版卡片