近期随着队列在项目中的使用愈来愈多,单个队列的时间出来愈来愈长,单进程队列处理,会致使后面的队列被阻塞住,没法及时响应处理,便会形成不良好的用户体验和功能误差。php
目前在咱们使用的Laravel项目中,使用的广播服务是redis,每次向客户端广播一次,都会生成一条Queue,假设每一个Queue的执行时间是1秒,假设用户执行如下操做:mysql
//推送即时点赞提醒 1s dispatch(new NewLike($like)); //推送即时评论提醒 1s dispatch(new NewComment($comment)); //推送即时回复提醒 1s dispatch(new NewReply($reply)); //推送即时通知提醒 1s dispatch(new NewNotite($notice)); //推送即时消息提醒 1s dispatch(new NewMessage($message));
以上每一个推送都将会耗时1秒以上,5个通知执行完成则须要5秒,假设系统天天产生10000次推送,则处理推送的时间10000 / 60 / 60 = 2.8(小时),则系统则须要花费2.8个小时才能将消息所有推送完成,可能会致使部分用户没法及时推送,从而对APP体验产生反感。laravel
随着系统推送愈来愈多,单进程队列以及没法知足咱们的需求,此时便须要开启多个队列消费者来进行处理。redis
开启多个队列消费者,就须要使用到多线程,每一个一个queue:work
都是一个单独的进程,运行多个queue:work
进程就能够达到同时处理多个任务的效果。sql
说了那么多,上个代码测试一下。多线程
经过artisan命令建立工具
art make:job TestJob
完善一下Job的主要逻辑:延迟1秒将传入的ID写入到日志到中。测试
<?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class TestJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public $id; /** * Create a new job instance. * * @return void */ public function __construct($id) { $this->id = $id; } /** * Execute the job. * * @return void */ public function handle() { sleep(1); info($this->id); } }
我本地环境使用的job是基于mysql database,目前先填充10000个job进去。优化
for ($i = 0; $i < 10000; $i++) { dispatch(new TestJob($i)); } dd('done');
针对这10000个job,我本地运行了两个queue:work
进程来进行同时处理。this
因为本地运行测试,为了方便,便把sleep移除了,下面来看看效果。
10000个job很快就被两个queue:work
处理完成了。
运行完成后,最担忧的问题莫过于,队列任务是否会被另外一个消费者进行重复执行?
答案就是:不会,除非是其中一个任务处理超时(timeout)才会有可能被其余队列进程重复执行到,关于为何不会,下次将会经过写一篇源码解析来为你们揭晓。
一般在服务端咱们使用的队列进程管理工具一半都是Supervisor,知道上面须要开启多个进程处理后,部分同窗便认为只须要添加多个conf配置文件,就完成啦。
可是当咱们须要添加的队列进程从2个变成8个、10个、20个、32个、64个。。。随着须要处理的愈来愈多,岂不是须要添加n个配置文件来保持多进程队列运行。
其实不是这样的,Supervisor早就作到了这一点,能够经过numprocs来控制进程数量进行处理,你能够根据服务端负载状况,来动态调整进程数量,配置以下:
[program:laravel-queue-work] process_name=%(program_name)s_%(process_num)02d directory=/data/yoursite command=php artisan queue:work autostart=true autorestart=true user=www numprocs=32 redirect_stderr=true
上面的案例中就开启了32个进程进行同时处理了job。
以上就完成laravel项目多进程队列的配置使用,同时从queue:work
输出和日志的写入来看,多个进程同时运行,也并不会形成队列重复执行的问题,能够放心使用😁😁