mysql如何分析InnoDB的页级锁闩(Latch)_mysql内核锁竞争排查

1次阅读

查innodb页级latch争用,首选show engine innodb status的semaphores段,重点关注os wait array info中spin waits与rounds比值、buf_pool_mutex或buf_block->lock等待;辅以performance_schema(需启用对应consumers/instruments)定位具体线程与内存地址,结合执行计划和业务模型优化。

mysql如何分析InnoDB的页级锁闩(Latch)_mysql内核锁竞争排查

查InnoDB页级Latch争用,先看SHOW ENGINE INNODB STATUS里的LATEST DETECTED DEADLOCKSEMAPHORES

InnoDB的页级Latch(如btr_search_latchbuf_pool_mutexpage_hash_lock)不是sql层可见的锁,不走INformatION_SCHEMA.INNODB_TRX,得靠引擎内部状态。最直接的入口就是SHOW ENGINE INNODB STATUS——但注意:它只保留最近一次死锁和最近一段活跃的等待/信号量统计。

重点关注SEMAPHORES节里的OS WAIT Array INFO部分:
– 如果某mutexrw-lockspin waits极高、rounds远大于spin waits,说明自旋失败多,开始频繁进系统等待,大概率是热点页争用;
– 若看到大量wait events集中在buf_pool_mutexbuf_block->lock,基本指向缓冲池页访问冲突。

  • 执行前确保innodb_status_output_locks = ONmysql 5.6.16+),否则TRANSACTIONS段不显示行锁/页锁细节
  • SHOW ENGINE INNODB STATUS输出是快照,需在业务高峰期间多次执行比对趋势,单次结果意义有限
  • 别依赖INFORMATION_SCHEMA.INNODB_METRICS里的innodb_buffer_pool_mutex_spin_waits等指标——它们是累加值,无时间粒度,难定位瞬时尖峰

performance_schema定位具体SQL和页号(page_no)争用源

MySQL 5.7+ 的 performance_schema 能抓到更细粒度的Latch等待,关键是启用对应消费者和仪器:

  • 开启:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_waits_current';
  • 启用仪器:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/synch/%/innodb%';
  • 之后查performance_schema.events_waits_current,过滤EVENT_NAME LIKE 'wait/synch/%/buf_pool%''wait/synch/%/btr_search%',能拿到THREAD_IDSOURCEOBJECT_INSTANCE_BEGIN(可反推页地址)

⚠️ 注意:OBJECT_INSTANCE_BEGIN 是内存地址,不是页号。若想关联到具体表空间+页号,需配合gdbpstack在进程挂起时解析buf_block_t结构体,或改用Percona Server的innodb_metrics扩展字段(如innodb_buffer_pool_pages_data + page_get_page_no()调用)。

innodb_adaptive_hash_index = OFF可能缓解btr_search_latch争用,但得看场景

btr_search_latch是B+树自适应哈希索引的全局读写锁,高并发点查(尤其主键等值查询)易成瓶颈。关掉AHK确实能消除这个Latch,但代价是失去哈希查找的O(1)优势,回归B+树的O(log n)遍历。

  • 适用场景:业务以范围扫描、JOIN为主,或主键查询已命中足够多的缓冲池页(buf_pool_hit_rate > 99%),此时AHK收益低,争用反而明显
  • 不适用场景:大量短小主键等值查询(如用户中心ID查)、且QPS > 5k,关AHK后CPU和buffer pool scan压力会陡增
  • 验证方法:压测前后对比SHOW ENGINE INNODB STATUSbtr_search_latchspin waitsos_waits变化,同时观察Handler_read_key / Handler_read_next比例

批量更新/删除导致buf_block->lock争用?优先检查是否锁了不该锁的页

大事务批量操作(如delete FROM t WHERE ts )会逐页加载、加<code>buf_block->lock(页级rw-lock),若没走索引或索引区分度差,容易扫到大量无关页,把Latch争用扩散到整个buffer pool。

  • 确认执行计划:EXPLAIN FORMAT=json看是否用了覆盖索引、是否rows_examined远超实际影响行数
  • 避免全表扫描式批量删:改用按主键分段(WHERE id BETWEEN ? AND ?),每次控制在1k行内,减少单次持有的页锁数量和时间
  • 检查innodb_change_buffering设置:对非唯一二级索引的DML,开启change buffer可延迟页加载,间接降低buf_block->lock争用,但仅适用于非唯一索引+非查询场景

真正棘手的是多个线程反复访问同一组热页(比如计数器表、配置缓存页),这时Latch争用本质是业务模型问题,不是参数能调平的——得考虑分片、本地缓存或异步化。

text=ZqhQzanResources