supervisor 开启多个进程,导致队列重复执行

我有个队列用来发送短信通知,之前我配置 supervistor 的时候只开启了一个进程,所以并没有发现问题。数据多了,我就想多开几个进程,可是当我多开几个进程的时候,一个队列就会重复执行,并且重复执行的次数就是设置的进程数量,比如我 numprocs=4,最后就会发送 4 条短信到同一个手机号上。我队列驱动是 database;

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php 项目路径/artisan queue:work queue=sms --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
numprocs=4
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log
stopwaitsecs=3600
附言 1  ·  5年前

感谢各位的帮助,目前问题已解决。队列驱动换成了 redis。

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
最佳答案

如果你用 database 又开启多个消费者的话,你需要做这几个步骤:
1. 消费者判断当前数据是否被消费,如果消费过了就不做任何动作
2. 消费者消费数据的时候,用悲观锁锁住当前数据,消费完成后标记已经消费

数据库用来做队列不是明智之选。因为 mysql 数据库并不擅长做队列,包括 redis 也是。当程序消费者同时消费的过多,会造成 mysql 性能下降。mysql 连接是有上限的,可执行的线程也是有上限的。何况 mysql 做延迟队列性能也很差,需要一直进行扫描。

综上,建议你换成 rabbitmq,rocketmq 或者 kafka。我觉得 rabbitmq 挺好用,推荐你使用。

5年前 评论
yangonce (楼主) 5年前
L学习不停 (作者) 5年前
讨论数量: 29

numprocs=1

5年前 评论
yangonce (楼主) 5年前
panda-sir

没用过 database 做驱动 可能需要代码里去处理这个问题吧 我一般用 redislist 结构或者专业级的消息队列

5年前 评论
yangonce (楼主) 5年前

如果你用 database 又开启多个消费者的话,你需要做这几个步骤:
1. 消费者判断当前数据是否被消费,如果消费过了就不做任何动作
2. 消费者消费数据的时候,用悲观锁锁住当前数据,消费完成后标记已经消费

数据库用来做队列不是明智之选。因为 mysql 数据库并不擅长做队列,包括 redis 也是。当程序消费者同时消费的过多,会造成 mysql 性能下降。mysql 连接是有上限的,可执行的线程也是有上限的。何况 mysql 做延迟队列性能也很差,需要一直进行扫描。

综上,建议你换成 rabbitmq,rocketmq 或者 kafka。我觉得 rabbitmq 挺好用,推荐你使用。

5年前 评论
yangonce (楼主) 5年前
L学习不停 (作者) 5年前

应该不是 supervisor 的问题。因为每个 job 从数据库中被 pop 出来,laravel 都会加锁的,防止重复消费。

5年前 评论
yangonce (楼主) 5年前
L学习不停 5年前
JerryBool (作者) 5年前

建议使用 laravel5.5 + horizon + redis

5年前 评论
yangonce (楼主) 5年前
siyecao

redis 没问题的

5年前 评论
yangonce (楼主) 5年前

问题预估:

  1. 结论:和 supervisor 无关,对队列的概念理解有误,队列最基本的原则就是保证数据不被重复消费,就算是用 database 也没问题,现上跑了一年没问题,numprocs=8
  2. 解决:加入队列,是把手机号作为 job 参数传入,job 里面根据手机号,再做相应逻辑,就没这个问题,因为不会被重复消费。
  3. 分析:把数据写入表,再分发 job 去表里取数据处理,多进程肯定会取到重复数据,伪 sql:SELECT * FROM mobile ORDER BY id DESC LMMIT 1 取到重复数据,很正常

PS:不找到问题的本质,换 redisrabbitmqrocketmqkafka 都解决不了你现有问题

5年前 评论
yangonce (楼主) 5年前
Hachiko (作者) 5年前
yangonce (楼主) 5年前
Hachiko (作者) 5年前
yangonce (楼主) 5年前
Hachiko (作者) 5年前
yangonce (楼主) 5年前
Hachiko (作者) 5年前
yangonce (楼主) 5年前
Hachiko (作者) 5年前
游离不2

database 存在并发的问题,还是 redis 靠谱点,或者看有没有办法上锁。

5年前 评论

数据库我的理解是要加锁避免多个进程执行同一个数据

5年前 评论

这是资源抢占问题,多个进程抢到了同一个任务,用 redis 做驱动,list 数据类型只会被第一个进程取出,但 redis 也不是完善的消息队列,会有丢数据的情况

3年前 评论