遊戲 Lag 白皮書 › L12 資料庫
營運中 schema 變更(DDL)的鎖定 Schema change lock (DDL / metadata lock)
原因 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,後面所有請求都得等待。
出處
- Online DDL Performance and Concurrency MySQL
online DDL 在收尾時也需要短暫的排他中繼資料鎖定;有長 transaction 時會等待,而這個等待中的鎖定請求會擋住後面所有的 transaction - Server System Variables MySQL
lock_wait_timeout:中繼資料鎖定的等待上限,預設值 31,536,000 秒(1 年) - ALTER TABLE (PostgreSQL Documentation) PostgreSQL
沒有另外註明的 ALTER TABLE 會取得最強的 ACCESS EXCLUSIVE 鎖定 - Client Connection Defaults (PostgreSQL Documentation) PostgreSQL
lock_timeout:等待鎖定超過此時間時中止陳述式 - General Thread States MySQL
Waiting for table metadata lock:等待中繼資料鎖定的執行緒狀態 - The schema_table_lock_waits and x$schema_table_lock_waits Views MySQL
等待中繼資料鎖定的 session(waiting_query)與造成阻擋的 session(blocking_pid) - pg_locks (PostgreSQL Documentation) PostgreSQL
granted 為 false 表示正在等待鎖定,mode 顯示 AccessExclusiveLock 等鎖定種類 - System Information Functions and Operators (PostgreSQL Documentation) PostgreSQL
pg_blocking_pids():阻擋指定 session 取得鎖定的 session 清單
相關原因
同一層:L12 資料庫
同一症狀(輸入延遲)在其他層的原因
查看含圖解與實驗的完整版卡片