mysql 5.7.19 版本出现 semaphore wait has lasted > 600 seconds
错误,意味着 innodb 内部某些线程等待信号量超过了10分钟,导致数据库挂起崩溃。
针对这个问题,排查和定位的思路及步骤如下:
1. 理解信号量(semaphore)和等待的背景
- innodb 通过信号量机制保护共享资源访问,例如缓冲池页、锁、事务信息等。
- 长时间等待信号量一般是死锁、资源竞争、内部异常或io瓶颈导致的。
- 错误日志中会列出等待信号量的线程堆栈位置(源码文件 + 行号),有助定位是哪类资源阻塞。
2. 收集环境与上下文信息
mysql版本:
- 5.7.19,是较早的5.7版本,innodb还有一些已修复的问题,建议考虑升级。
服务器硬件与资源状况:
- cpu、内存利用率
- 磁盘io状况(iops、延迟)
数据库负载情况:
- 并发连接数
- 读写比例
- 是否有长事务/大事务
具体业务场景:
- 当时运行什么sql,是否有大量insert/update/delete
- 是否有ddl操作(alter、drop)
3. 查看mysql错误日志和innodb状态
a. 错误日志中的关键信息
确认报错线程对应的源码文件和行号:
mtr0mtr.cc
,row0ins.cc
等,分别代表:
mtr0mtr.cc
:多版本事务相关管理(mini-transaction)row0ins.cc
:行插入相关代码
这些提示可能表明在插入操作中出现了阻塞。
b. 通过show engine innodb status\g观察
- 锁等待情况(latest detected deadlock)
- 当前活跃事务列表
- semaphore wait 信息(
semaphore wait
块) - 主线程或阻塞线程的详细信息
4. 结合源码行号,定位具体阻塞点
可以通过查看5.7.19版本源码对应文件(mysql官方github或者源码包)定位:
mtr0mtr.cc line 567
涉及mini-transaction相关锁等待,可能是innodb内部的metadata锁或缓冲池访问竞争。
row0ins.cc line 193
插入行时等待信号量,可能是插入缓冲区竞争或插入锁等待。
5. 重点排查方向
5.1 长事务导致锁资源占用
show processlist
看是否存在长时间未提交的事务。information_schema.innodb_trx
查看当前活动事务。- 关闭长事务或者合理设置事务超时。
5.2 高并发写入导致缓冲池争用
高并发大批量写入,缓冲池页锁争用严重。
调整 innodb 参数,如:
innodb_thread_concurrency
innodb_lock_wait_timeout
innodb_buffer_pool_size
(确保足够大,避免频繁刷盘)
5.3 磁盘io瓶颈
- 使用系统工具(
iostat
,vmstat
)检查磁盘负载和延迟。 - 高io延迟会导致innodb锁等待。
5.4 表空间或数据页损坏
- 使用
check table
检查相关表。 - 参考错误日志是否有提示页损坏。
6. 其他诊断技巧
6.1 启用详细innodb调试日志
启动mysql时添加:
[mysqld] innodb_print_all_deadlocks=on innodb_lock_wait_timeout=50
查看死锁详细信息。
6.2 使用性能schema定位锁等待
- 查询
performance_schema.data_locks
和performance_schema.data_lock_waits
,定位锁资源。
7. 解决建议总结
问题点 | 排查方法 | 解决措施 |
---|---|---|
长事务占用锁 | show processlist, innodb_trx | 关闭或优化长事务,合理拆分事务 |
高并发写压力大 | 观察缓冲池争用,线程锁等待 | 优化参数,分批写入,升级版本 |
磁盘io瓶颈 | iostat, vmstat | 优化存储,使用ssd,提高io性能 |
表空间或页损坏 | check table, innodb_force_recovery尝试 | 恢复数据,导出备份,重建表空间 |
innodb版本缺陷 | 官方bug报告,源码分析 | 升级mysql版本到最新稳定版 |
8. 典型诊断命令举例
-- 查看当前阻塞事务 select * from information_schema.innodb_trx\g; -- 查看当前等待锁的线程 select * from performance_schema.data_locks where lock_status='waiting'; -- 查看进程列表,看长时间执行的sql show full processlist; -- 查看死锁日志(在错误日志中) -- 或启用 innodb_print_all_deadlocks=on 后捕获
总结
先从当前活跃事务和锁等待入手排查。
结合innodb状态和系统io性能分析瓶颈。
若怀疑数据损坏,尝试使用 innodb_force_recovery
。
5.7.19版本较老,建议升级至5.7较新版本,或者8.0版本,获得更多稳定性和bug修复。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论