Laravel队列用MariaDB遇Too many connections问题,求排查方案
排查MariaDB「Too many connections」与jobs表插入锁等待问题方案
一、核对数据库与队列核心配置
- 检查MariaDB关键参数:执行
SHOW VARIABLES LIKE 'max_connections';确认连接上限,用SHOW GLOBAL STATUS LIKE 'Threads_connected';对比错误发生时的活跃连接数,确认是否确实触顶。同时查看wait_timeout、interactive_timeout,避免闲置连接未及时释放;检查innodb_lock_wait_timeout(当前为300秒)是否与业务逻辑匹配。 - 校验Laravel队列与数据库配置:确认
.env中QUEUE_CONNECTION=database,检查config/queue.php里database驱动的retry_after、timeout、max_jobs参数,确保worker超时逻辑与数据库锁等待周期适配,防止worker挂起后事务长期未提交。若启用数据库连接池,核对max_connections设置是否合理。
二、追踪批量插入场景的事务行为
- 新增批量插入日志:在自动化进程批量分发队列任务的代码处,强制记录事务起止时间、插入任务量、执行时长,同时捕获所有异常并输出完整栈信息,排查是否存在异常抛出后事务未回滚的情况。
- 临时开启MariaDB通用查询日志:执行
SET GLOBAL general_log = 1; SET GLOBAL general_log_file = '/tmp/mariadb_batch_insert.log';,捕获批量插入时的完整SQL链路(包括BEGIN/COMMIT/ROLLBACK语句),确认是否存在事务长期未提交的情况。操作完成后记得关闭日志:SET GLOBAL general_log = 0;。 - 排查InnoDB事务状态:执行
SELECT trx_id, trx_started, trx_mysql_thread_id, trx_state, trx_query FROM INFORMATION_SCHEMA.INNODB_TRX;,重点锁定trx_state为LOCK WAIT的事务,关联SHOW FULL PROCESSLIST中的线程,定位到对应的应用进程/worker。
三、分析队列Worker运行状态
- 检查Worker日志:在
storage/logs/laravel.log中搜索failed、timeout、exception关键词,确认是否存在worker报错退出但未正确释放数据库连接的情况。 - 核查Worker进程数:执行
ps aux | grep php artisan queue:work,对比配置的--max-processes值,确认是否存在过多worker进程同时创建数据库连接,导致连接池耗尽。 - 模拟异常场景:手动触发批量插入时的异常(如payload格式错误、数据库临时中断),检查事务是否自动回滚、数据库连接是否正常释放,验证是否会触发锁等待。
四、优化jobs表锁竞争与插入性能
- 整理jobs表碎片:执行
SHOW TABLE STATUS LIKE 'jobs';查看Data_free值,若主键(自增ID)碎片过多,在低峰期执行OPTIMIZE TABLE jobs;整理,减少插入时的锁竞争。 - 调整锁等待超时:临时将
innodb_lock_wait_timeout调低至60秒(SET GLOBAL innodb_lock_wait_timeout = 60;),避免锁等待连接长期占用资源,同时监控是否出现更多锁超时错误,反推问题根源。 - 拆分批量插入:将单次大数量插入拆分为小批次(如从1000条/次改为100条/次),缩短单事务锁持有时间,降低锁冲突概率。
五、搭建长期监控预警机制
- MariaDB指标监控:持续监控
Threads_connected、InnoDB_row_lock_waits、InnoDB_row_lock_time_avg指标,当连接数接近上限或锁等待激增时触发预警。 - Laravel队列监控:使用Laravel Horizon(若已部署)或自定义脚本,监控队列待处理任务数、worker存活状态、任务执行时长,及时发现异常worker进程。
内容的提问来源于stack exchange,提问作者Shan Abdussalam
相关产品推荐
相关产品推荐

