用GDB确认LOCK_active_mi持有者:先gdb attach后thread apply all bt定位卡住线程,frame N切换到__lll_lock_wait帧,p (pthread_mutex_t)$rdi获取__owner值(如102188),再ps -T -p | grep 102188查对应OS线程。

怎样用GDB确认哪个线程持有了LOCK_active_mi
当SHOW SLAVE STATUS卡住,且pstack显示停在inline_mysql_mutex_lock (LOCK_active_mi),说明你正面对一个典型的server层互斥锁争用。GDB不是用来“看日志”,而是直接读内存里的锁结构体字段。
关键操作是拿到当前pthread_mutex_t实例的地址,然后解析其__owner字段——它存的是持有该锁的LWP(轻量级进程)ID,对应ps -T -p 输出中的SPID列。
- 先用
gdb attach进入进程 - 查卡住线程的栈:
thread apply all bt,定位到__lll_lock_wait那一帧 - 切换到该帧:
frame N,再执行p *(pthread_mutex_t*)$rdi(x86_64下参数在$rdi) - 从输出中提取
__owner = 102188这类值,再用ps -T -p反查线程状态| grep 102188
注意:__owner不是MySQL的THREAD_ID,而是OS线程ID;若看到__owner = 0,说明锁当前空闲,问题不在这里。
如何从OBJECT_INSTANCE_BEGIN反推InnoDB页号
performance_schema.events_waits_current里出现的OBJECT_INSTANCE_BEGIN是内存地址,比如0x7f5faf078298,它指向一个buf_block_t结构体。这个地址本身不带页号信息,但InnoDB源码中buf_block_t开头几个字段是固定的:
-
frame:指向实际页数据的指针(即page_no所在页的起始地址) -
page:嵌入的page_t结构,其中page_get_page_no()可提取页号
所以你要做的是:
- 在GDB中执行
p *(buf_block_t*)0x7f5faf078298 - 观察输出中
page字段的地址,比如page = 0x7f5faf079000 - 再执行
p page_get_page_no((page_t*)0x7f5faf079000)(需确保已加载InnoDB符号,或用Percona Server的innodb_buffer_pool_pages_data配合page_get_page_no()扩展)
这一步无法全自动,必须依赖调试符号或已知的结构体偏移;生产环境没符号表时,基本只能靠pstack + SHOW ENGINE INNODB STATUS交叉比对。
排查global_sid_lock写锁阻塞读锁的实战断点位置
主从命令冲突常发生在global_sid_lock上:SHOW MASTER STATUS拿写锁,SHOW SLAVE STATUS要读锁,但InnoDB的pthread_rwlock_t实现里,只要__nr_writers_queued > 0,新来的读请求就会被挂起——哪怕写锁还没真正拿到。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
复现和验证的关键是打断点在锁获取前、释放后两个位置:
- 写锁入口:
b rpl_master.cc:647(global_sid_lock->wrlock()调用点) - 写锁出口:
b rpl_master.cc:649(global_sid_lock->unlock()) - 读锁入口:
b rpl_slave.cc:1203(global_sid_lock->rdlock()附近)
设置断点后,用另一个会话触发SHOW MASTER STATUS,等它停在647,再立刻在另一终端执行SHOW SLAVE STATUS——后者会卡在rdlock(),此时用info threads和thread apply all bt就能清楚看到谁在等谁。
这种阻塞不报错、不超时,只表现为“命令无响应”,最容易被误判为网络或IO问题。
为什么innodb_status_output_locks=ON后仍看不到页级Latch等待
因为InnoDB的页级Latch(如buf_pool_mutex、btr_search_latch)根本不在SQL层暴露,INFORMATION_SCHEMA.INNODB_TRX和INNODB_LOCKS完全不记录它们。开启innodb_status_output_locks只影响行锁/表锁的TRANSACTIONS段输出,对Latch毫无作用。
真正能反映Latch争用的只有两处:
-
SHOW ENGINE INNODB STATUS的SEMAPHORES节——看spin waits与rounds比值,比值>5说明自旋失败多,已进入系统等待 -
performance_schema中wait/synch/mutex/innodb/buf_pool_mutex类事件——前提是提前启用了对应instrument:UPDATE performance_schema.setup_instruments SET ENABLED='YES' WHERE NAME LIKE 'wait/synch/%/buf_pool%';
别指望innodb_metrics里的innodb_buffer_pool_mutex_spin_waits能帮你定位瞬时热点——它是累加值,没有时间戳,看不出是哪一秒冲高的。










