起因
最近有个简单的队列tp-queue时不时出现问题,出问题后就整个队列卡住了。 使用的是ThinkPHP的think-queue,项目地址:https://github.com/top-think/think-queue。
排查
执行程序
nohup /www/server/php/72/bin/php think queue:listen --queue=storeSystemJobQueue --delay=0 --memory=2048 --sleep=3 --tries=0
>> queue.log 2>&1
# 参数解析
# --queue[=QUEUE] The queue to listen on
# --delay[=DELAY] Amount of time to delay failed jobs [default: 0]
# --memory[=MEMORY] The memory limit in megabytes [default: 128]
# --timeout[=TIMEOUT] Seconds a job may run before timing out [default: 60]
# --sleep[=SLEEP] Seconds to wait before checking queue for jobs [default: 3]
# --tries[=TRIES] Number of times to attempt a job before logging it failed [default: 0]
用的是数据库驱动,数据库存储数据。出问题后显示的是队列执行成功,但是没有消化,然后就卡住了。
数据库sql日志执行的是这三条:
- 更新: 将处理数据,但是没有消化的队列数据初始化, 并更新尝试次数+1;
- 查询: 查询一条有效数据;
- 更新: 处理完业务,更新;
sql语句如下:
[ 2022-12-01T17:46:04+08:00 ][ sql ] [ SQL ] UPDATE `store_system_jobs` SET `reserved` = 0 , `reserved_at` = NULL , `attempts` = `attempts` + 1 WHERE `queue` = 'storeSystemWarehousingJobQueue' AND `reserved` = 1 AND `reserved_at` <= 1669886164 [ RunTime:0.003657s ]
[ 2022-12-01T17:46:04+08:00 ][ sql ] [ SQL ] SELECT * FROM `store_system_jobs` WHERE `queue` = 'storeSystemWarehousingJobQueue' AND `reserved` = 0 AND `available_at` <= 1669887964 ORDER BY `id` ASC LIMIT 1 FOR UPDATE [ RunTime:0.004706s ]
[ 2022-12-01T17:46:04+08:00 ][ sql ] [ SQL ] UPDATE `store_system_jobs` SET `reserved` = 1 , `reserved_at` = 1669887964 WHERE `id` = 450 [ RunTime:0.004191s ]
这里我梳理下,简易流程图如下:
程序挂了,任务不跑,第一开始没思路,临时解决的是重启,但是执行一段时间又不行,特别是高峰的时候很绝望。然后想的是性能问题,是不是数据库介质不行。 开始查看数据库是不是产生了死锁了,删除锁。查看锁的语句如下:
//查锁
select * from information_schema.innodb_trx
//删锁 id
kill 738178711
然后又可以了。又过了一段时间,还是不行。只能重新排查,突然发现在重启队列的时候,查看数据库锁看到有条没读锁的sql,一直挂着,然后查看业务代码 ,发现这不就是查看据库数据是否重复数据的sql语句吗?,这里产生了死循环,效果就会出现下面流程图:
由于框架队列默认超时机制是60s,超过了就会重新执行,直到达到一定次数,程序就会die。这里面有日志,但是没留意这个超时异常中断的记录。
反思
- 1、 优化队列,超时记录与报警。
- 2、 代码不可以留有死循环的可能,一定杜绝,一开始就设定个次数。
迭代
- 2022年12月12日 09:00:00 初稿
参考
1、Lock wait timeout exceeded; try restarting transaction
本作品采用CC BY-NC-ND 4.0进行许可。转载,请注明原作者 chunpat 及本文源链接。