关于 Laravel 队列经常卡死的问题。

使用队列的原因:因为项目需要每天定时拉取多个api的数据,数据量大(每次上万个任务),所以选择使用队列拉取。

工具:laravel队列,supervisor进程监控

遇到的问题:队列在运行过程中会突然卡住不再运行,需要重启horizon和supervisorctl,才会继续运行。

(2020-01-03 15:31:00补充)难点:手动运行正常!重启队列并观察,也正常!运行一段时间,队列卡住,只有重启才能运行

疑问:
一开始想着是否是自己的程序有问题,但是手动使用php artisan运行command来检测任务的时候,每次在horizon面板都是看着正常运行。而且每次宕机之后,去看horizon面板都是发现任务累积了很多,所以也不存在是因为队列没有任务,导致work挂掉(而且已使用Supervisor 进行监控)。
是否是说:laravel队列长时间运行之后,必须重启?因为有时候一两天内都是正常的,过几天突然就卡了。

关于日志:在horizon日志中:没有异常报错,比如一直processing循环这种,中断任务时候都是前面正常运行,后面突然就停止了(日志就中断了)。在failed_job中,报错基本都是job运行的次数过多或者时间过长

目前已采用的解决方案:
1、将任务分割为多个队列进程,第一为了不让某些任务影响到后续任务,第二方便定位问题并且重新手动运行任务,第三,不知是否是单一队列时,长时间运行被服务器自动kill进程
2、增加public $tries = 5;限制任务最大重试次数,避免任务重复被推进队列运行
3、将Eloquent 模型改为初始的DB::table()连接方式进行增删改查。

但是仍然无法解决,所以在此寻求帮助。感激不尽。

附上解决过程:
1、
使用背景:一开始任务不多,所以全部都是用default队列工作,导致任务卡死之后,只能所有任务都重新运行,
猜测:是否是任务过多,程序一直占用系统内存,导致被kill掉了
解决方案:因为对服务器的机制不太理解,猜测可能是系统内存不够时将进程终止了,也因为需要进队列的工作越来越多,方便调试和定位问题,所以将任务从default队列中分开来,使用多个队列运行不同类型(job)的任务。
2、
使用背景:已分割为多个任务,此时发现问题仍然存在,
找寻资料以及猜测:翻过资料,发现有可能是因为job中使用了Eloquent 模型,导致程序运行的时候,有时候无法检索到指定的模型,导致程序一直循环运行(中间查询failed_job以及log发现运行最大时间达到150s),
解决方案:将所有的job中使用模型的地方,全部使用DB::table()的初始方式来进行增删改查,并且增加public $tries = 5,限制重试次数。
结果:中间正确运行了几天,周末回来之后,发现任务再次中断。
3、
对于failed_job中的工作的测试,找到没有更新成功的数据,手动执行任务,除了中间调试语句出错的,剩下的报错信息是has been attempted too many times or run too long. The job may have previously timed out. 的任务,测试了有20个左右,都是成功的,

附言 1  ·  4年前

大家好,这个问题暂时不关闭了,期待有人能找到根源。
我现在的处理方案是,每天定时重启一次supervisorctl服务,并且每个job加上最长运行时间和最多重试次数,防止任务被重复推入队列,附上重启队列任务
0 16 * php /path/to/your/project/artisan horizon:terminate && sudo supervisorctl reload >> /dev/null 2>&1

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
最佳答案

首先给大家说声抱歉,最近都没看这边,导致问题一直没关闭,然后非常感谢各位的解答,我来说下我目前的处理方式吧。 首先,配置上进行了修改,将原先的队列进一步细分(不仅是为了让任务更快运行,也是保证不同板块的任务不会有干扰),如图: file 其次,代码中增加最大运行次数(因为查日志,发现部分任务失败后一直在重启,十分影响运行) file

最后,也是问题得到了根本解决!!换了服务器,内存扩大了几倍,再也没出现过终止的情况,同时增加了 config/horizon 中 memory_limit 的限制 ,(所以 加钱才是王道(嗯,确信!),

3年前 评论
讨论数量: 45

附服务器内存:

file
这时候队列正在工作,是否内存也会有影响呢?

4年前 评论

我之前有过类似的问题,不过我的是horizon自己掉了,所以任务也不跑。我的问题是用了deployer部署,所以出现这个问题。

4年前 评论
rensennance (楼主) 4年前

看了你的需求,我觉得你可以试试用计划任务去做crontab。因为没必要用队列啊。这是题外建议。

关于队列经常卡死的问题,我想问下你用的哪种队列,redis,rabbitmq还是mysql?如果都没用,而是保持默认的sync的话那就太糟糕了。

4年前 评论
_杭城浪子 4年前
rensennance (楼主) 4年前
rensennance (楼主) 4年前
L学习不停 (作者) 4年前
rensennance (楼主) 4年前
rensennance (楼主) 4年前
L学习不停 (作者) 4年前
rensennance (楼主) 4年前

我用的 mysql 也和你一样,过几天就不运行了

4年前 评论
rensennance (楼主) 4年前

别猜测,要动手去调试

4年前 评论
rensennance (楼主) 4年前
黑将军

是不是mysql长时间连接后断掉了?

4年前 评论
rensennance (楼主) 4年前
黑将军 (作者) 4年前
rensennance (楼主) 4年前

是不是空闲连接了?线程阻塞,mysql连接成了闲置连接,闲置过久,服务器一般会主动断开连接,应该编写异常捕获,进行重试。数据量大吗?会不会出现几小时没有队列处理?

4年前 评论

如果解决不了,可以加个延时队列。检查并处理失败的消息

4年前 评论
rensennance (楼主) 4年前

我也出现过这种的问题没解决过。谁解决了。发下教程

4年前 评论

当队列消耗太慢或者停止消费的时候,我手动执行队列监听,是能正常运行的。感觉这个时候,并不是代码层次的问题,有点怀疑supervisor 哪里有问题

3年前 评论

@chenyu0257 应该不是 supervisor 问题. 我用nohup的方式 也会存在这种情况

3年前 评论

如果谁解决了.. 麻烦发下答案

3年前 评论

有人解决了吗?我也遇到这个问题,驱动是database(mysql),用docker起了两个queue worker,执行php artisan queue:work --queue=high,default,low --tries=1 --timeout=60

经常报: SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction (SQL: delete from `jobs` where `id` = xxxx)

代码里面的事务都是用:

DB::transaction(function () {
    // TODO: Model CURD.
});
3年前 评论

会不会超时造成的,业务处理太久了

3年前 评论
Kiddo 3年前
Kiddo 3年前

完全相同的问题,真是一个头两个大 :sob::sob::sob::sob::sob::sob: 用的redis队列,莫名其妙的就停止

3年前 评论

说下我解决方法... 之前队列用的rabbitmq, 使用nohup 跑的脚本.. 就是会存在 过断时间就会卡住. 试了好多种方法.都不能解决. 后来 我加了个心跳检测. 解决了.... 希望童鞋们试试.

3年前 评论
congcong 3年前
qiyeal 2年前

这种问题我在工作中遇到过,我们是做异步导入导出操作出现的,我们目前解决方式:

  • 把导入数据(chunk)分块小块小块进行塞入队列,这样避免一个任务执行时间过长
  • 刚刚开始我们是队列里面塞队列,最后修改成队列之间不进行嵌套
  • 导入导出进行supervisor守护不同的队列

结果:经过以上进行修改,出现以上问提好像基本没有了。

3年前 评论

这个貌似是个bug, 看这里 www.jiangxianli.com/?p=80

3年前 评论
rensennance (楼主) 3年前
Leonz3n

最近我也遇到这个问题,从数据库读取数据到ES索引,有时候队列会卡死,经过排查,应该是内存不够的问题。 我是用的supervisor,查看队列进程

$ ps -aux|grep php
www      20982  1.6  0.5 424904 40068 ?        S    16:53   0:00 /usr/bin/php /data/www/YG-server/artisan horizon
www      20989  2.0  0.5 424908 40172 ?        S    16:53   0:00 /usr/bin/php artisan horizon:supervisor aliyun-test-gnGv:supervisor-1 redis --workers-name=default --balance=auto --max-processes=8 --min-processes=3 --nice=0 --balance-cooldown=3 --balance-max-shift=1 --backoff=0 --max-time=0 --max-jobs=0 --memory=128 --queue=default,medical,medical_data_convert --sleep=3 --timeout=60 --tries=1

内存被限制为 128MB,在 "laravel/horizon": "^5.0" 里的 config/horizon.php 里有配置

return [
...
'defaults' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['default'],
            'balance' => 'auto',
            'maxProcesses' => 1,
            'memory' => 128,
            'tries' => 1,
            'nice' => 0,
        ],
    ],
...
];

可以尝试一下修改内存限制

3年前 评论

发起请求api是使用的curl么?是否有设置超时时间?

3年前 评论

我之前也遇到过同样的问题,加个—timeout属性就解决了,刚开始加60还是有问题,加—timeout=120后彻底解决问题。

3年前 评论

首先给大家说声抱歉,最近都没看这边,导致问题一直没关闭,然后非常感谢各位的解答,我来说下我目前的处理方式吧。 首先,配置上进行了修改,将原先的队列进一步细分(不仅是为了让任务更快运行,也是保证不同板块的任务不会有干扰),如图: file 其次,代码中增加最大运行次数(因为查日志,发现部分任务失败后一直在重启,十分影响运行) file

最后,也是问题得到了根本解决!!换了服务器,内存扩大了几倍,再也没出现过终止的情况,同时增加了 config/horizon 中 memory_limit 的限制 ,(所以 加钱才是王道(嗯,确信!),

3年前 评论

我的项目里 使用的rabbitmq 出现了这种情况,不知道怎么解决,头大

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!