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

游戏卡顿白皮书 › L12 数据库

线上表结构变更(DDL)锁 Schema change lock (DDL / metadata lock)

原因 ID db-ddl-lock · 主责 运维团队·数据库运维 · 配合 研发团队·服务器开发

在含图示和实验的完整版中打开此卡片 →

在服务运行中给表加列或加索引,仅仅因为一个短暂需要的锁,使用这张表的所有请求都可能被迫等待。

起因 通过热修复给线上表加列、加索引 → 结果 表结构变更在等之前开启的长事务,后来的所有请求又在等这个表结构变更 → 画面表现 使用这张表的功能(背包、邮件等)整体卡住并超时

症状
操作延迟, 吞操作/回档, 连不上/无限加载
因素
停顿
谁会遇到
仅特定功能, 全服
何时出现
偶尔随机, 刚登录/维护结束后
负责方
主责 运维团队·数据库运维 · 配合 研发团队·服务器开发
研发团队要做的事
含表结构变更的热修复要与数据库运维协商时间,先发布在没有新列时也能正常运行的代码。
运维团队要做的事
设置较短的锁等待超时,失败就重试;在没有长事务时执行;使用在线变更工具;大表放到维护时间做。
监控图上
某一时刻起台阶式上升 · 锁等待会话数、这张表的查询延迟
查看位置
MySQL 统计 SHOW PROCESSLIST 中 State 为 Waiting for table metadata lock 的会话,用 sys.schema_table_lock_waits 找出阻塞它们的会话(blocking_pid)。PostgreSQL 看 pg_locks 中 granted 为 false 的请求和 AccessExclusiveLock,用 pg_blocking_pids() 找出阻塞它们的会话
确认依据
从开始变更表结构的时刻起,使用这张表的所有查询都堆积在锁等待中,排在最前面的是未结束的事务或表结构变更语句
排除依据
等待只集中在特定行上,同一张表的其他行处理正常,看“热点行锁竞争”(db-hot-row)
确认手段
运维工具即可确认(无需游戏代码)
深入了解
变更表结构时,MySQL 会短暂持有元数据锁,PostgreSQL 会短暂持有最强的表锁。变更本身哪怕一瞬间就完成,只要前面有一个未结束的事务,后面的所有请求都会排队等待。

出处

  1. Online DDL Performance and Concurrency MySQL
    在线 DDL 在收尾时也需要短暂持有排他元数据锁;有长事务时会等待,而这个等待中的锁请求会阻塞后面所有事务
  2. Server System Variables MySQL
    lock_wait_timeout:元数据锁等待超时,默认值 31,536,000 秒(1 年)
  3. ALTER TABLE (PostgreSQL Documentation) PostgreSQL
    未特别注明的 ALTER TABLE 会获取最强的 ACCESS EXCLUSIVE 锁
  4. Client Connection Defaults (PostgreSQL Documentation) PostgreSQL
    lock_timeout:锁等待超过这个时长就中止语句
  5. General Thread States MySQL
    Waiting for table metadata lock:正在等待元数据锁的线程状态
  6. The schema_table_lock_waits and x$schema_table_lock_waits Views MySQL
    等待元数据锁的会话(waiting_query)和阻塞它的会话(blocking_pid)
  7. pg_locks (PostgreSQL Documentation) PostgreSQL
    granted 为 false 表示正在等待锁,mode 显示 AccessExclusiveLock 等锁类型
  8. System Information Functions and Operators (PostgreSQL Documentation) PostgreSQL
    pg_blocking_pids():阻止指定会话获得锁的会话列表

相关原因

同一层:L12 数据库

其他层中同样导致“操作延迟”的原因

查看含图示和实验的原卡片