Laravel队列通知在AWS SQS中阻塞问题排查求助
Laravel队列Worker卡滞问题分析与解决
嘿,我仔细看了你遇到的Laravel队列Worker卡在AWS EBS上的问题,结合你给出的日志和排查过程,其实那些内存、超时错误大多是表象,你最后找到的根因才是关键——咱们来梳理清楚:
场景回顾
你基于Laravel/EBS/SQS架构部署了通知处理Worker,部分通知能正常发送,但有部分卡在队列中。已经把实例从t2.micro升级到t2.large,问题依旧;非队列模式下所有通知都正常,队列模式下前几条能跑,但后续就出问题,Laravel端只看到MaxAttemptsExceededException和内存不足的致命错误,日志里还有三类Nginx错误。
日志错误的表象分析
你提到的三类Nginx错误,其实都是根因引发的连锁反应:
- 内存分配失败:
2020/11/03 09:22:34 [emerg] 10932#0: *30 malloc(4096) failed (12: Cannot allocate memory)...
升级实例后还出现这个,说明不是实例内存不够,而是Worker进程在处理异常任务时,可能因为循环重试、错误逻辑导致内存暴涨,最终触发OOM。 - 上游超时:
2020/11/02 14:50:07 [error] 10241#0: *2623 upstream timed out (110: Connection timed out)...
这是PHP-FPM进程处理Worker请求超时,大概率是Worker在等待不存在的数据库资源,或者错误处理逻辑导致处理时间过长。 - 连接被重置:
2020/11/02 15:00:24 [error] 10241#0: *2698 recv() failed (104: Connection reset by peer)...
一般是PHP-FPM进程因为OOM被系统强制杀死,和第一个错误对应上了。
根本原因与解决方案
你最后找到的原因非常关键:Worker尝试为待创建对象发送通知时,数据库事务尚未完成。
这就完美解释了所有现象:
- 非队列模式下,代码是同步执行的,事务提交后才会触发通知,所以没问题;
- 队列模式下,如果是在事务内部分发队列任务,Worker可能在事务提交前就开始执行,此时数据库里还没有对应的对象,Worker处理时会抛出“模型不存在”之类的异常,进而引发重试,多次重试后内存暴涨、进程崩溃,最终任务卡在队列里,触发
MaxAttemptsExceededException。
解决这个问题的核心是确保队列任务在数据库事务提交后再执行,Laravel提供了很方便的方式:
- 使用
afterCommit()方法分发任务/通知:
DB::transaction(function () use ($data) { $model = Model::create($data); // 通知添加afterCommit Notification::send($model, new YourNotification())->afterCommit(); // 队列任务同理 dispatch(new YourQueueJob($model))->afterCommit(); });
- 如果是在事务外部分发任务,确保事务已经完全提交后再执行;
- 额外建议:给队列任务添加日志记录,在
handle()方法里打印要处理的模型ID,确认是否存在,方便后续快速排查类似问题;同时调整队列的重试次数和间隔,避免无意义的重试浪费资源。
内容的提问来源于stack exchange,提问作者Sherlock
相关产品推荐
相关产品推荐

