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

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

热点行锁竞争 Hot row lock contention

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

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

所有人都要修改同一行(公会仓库、拍卖行热门物品、全服计数器)时,同一时刻只有一个人能拿到锁。

起因 活动、热门物品让修改集中到同一行 → 结果 请求一直等到拿到锁 → 画面表现 交易失败、“请稍后再试”、超时

症状
吞操作/回档, 操作延迟
因素
停顿, 延迟
谁会遇到
仅特定功能
何时出现
人多的时候
负责方
主责 研发团队·服务器开发 · 配合 运维团队·数据库运维
研发团队要做的事
拆分行(分片计数器),缩短事务,在内存中汇总后一次性写入。
运维团队要做的事
监控行锁等待时间和次数,找出竞争集中的行并共享结果。
数值参考
一个请求持锁 10 ms,这一行每秒最多只能修改 100 次。如果事务中还夹着与其他服务器的往返通信,能修改的次数会更少。
监控图上
随人数/负载上升 · 行锁等待次数、时长
查看位置
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 的会话、pg_locks 中 granted 为 false 的请求;开启 log_lock_waits(默认关闭)后,等待时间长的锁会记入日志
确认依据
锁等待随活动、人数陡增,等待中的请求大多指向同一张表的同一行(同一个键)
排除依据
等待均匀分散在多张表、多行上,属于磁盘、CPU 饱和问题。某个会话长时间持锁不放,看“长事务”(db-long-tx)
确认手段
运维工具即可确认(无需游戏代码)

出处

  1. InnoDB Locking MySQL
    一个事务给行(索引记录)加锁后,其他事务无法修改这一行,只能等待
  2. How to Minimize and Handle Deadlocks MySQL
    建议事务保持小而短,相关修改完成后立即提交,以减少冲突
  3. Server Status Variables MySQL
    用 Innodb_row_lock_waits、Innodb_row_lock_time 查看行锁等待次数和时间,用 Innodb_row_lock_current_waits 查看当前正在等待的数量
  4. The innodb_lock_waits and x$innodb_lock_waits Views MySQL
    等待中的查询(waiting_query)、阻塞它的会话(blocking_pid)和等待时长(wait_age)
  5. The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
    pg_stat_activity 的 wait_event_type:为 Lock 表示正在等待重量级锁
  6. pg_locks (PostgreSQL Documentation) PostgreSQL
    granted 为 false 表示该进程正在等待获取锁
  7. Error Reporting and Logging (PostgreSQL Documentation) PostgreSQL
    log_lock_waits:锁等待超过 deadlock_timeout 时记录日志,默认关闭

相关原因

同一层:L12 数据库

其他层中同样导致“吞操作/回档”的原因

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