队列优先级
关于队列优先级,学院君在先导篇中已经简单介绍过了,这里再系统介绍下。
Laravel 是在处理消息队列时通过指定不同队列的前后顺序来实现队列优先级的,默认情况下所有队列任务都被推送到名为 default
的默认队列:
所以它们是没有优先级之分的。如果你想要为不同任务定义不同的处理优先级,可以通过将它们推送到不同的队列,然后在启动队列处理进程时,通过 --queue
参数为不同优先级的队列进行排序即可,排在前面的优先级高,排在后面的优先级低,关于这一块的底层实现先导篇中已经详细介绍过,这里不再赘述。
假设你的 Laravel 应用中存在多个队列任务,如 ProcessPayment
、SendVerificationMessage
等,并且 ProcessPayment
优先级比 SendVerificationMessage
高,要实现这个优先级,可以在推送队列任务到消息对列时通过 onQueue
方法指定推送的队列:
或者在任务类中通过设置 queue
属性来指定:
两者效果是一样的。接下来,在启动处理来自多个队列的消息任务时,通过 --queue
参数根据队列处理优先级显式设置不同队列的排序,越靠前优先级越高,反之越低:
这样一来,就可以实现优先处理 payments
队列消息的功能,也就等同于间接实现了队列优先级功能。
但是,这里会引入一个新的问题:如果 payments
队列一直是满的,那么 default
队列就一直不能被消费!这是我们不能接受的,你可以通过开启多个 php artisan queue:work --queue=payments,default
进程来加速消费 payments
队列中任务。
此外,还可以使用不同的队列处理器消费不同的队列任务,这样就可以保证无论何种极端情况下,两个队列中的任务都会被处理:
如果
payments
中的任务比较重要,需要尽快处理,可以通过增加该队列的处理进程来实现。
但这个方案也存在问题,那就是如果 payments
队列是满的、而 default
队列是空的话,会导致第二个处理器进程处于空闲状态,结合 Laravel 队列消费的底层实现,该进程会循环读取空队列,导致 CPU 资源的浪费,就像 Ajax 和 Websocket 两种方案实现长连接一样,Ajax 肯定不如 Websocket,因为 Ajax 基于 HTTP 协议,基于客户端轮询的实现存在无效通信,浪费系统资源。
为了解决这个问题,可以这么做:
不过,和前面一样,这样一来也就不存在什么队列优先级了,和都推送到 default
队列没有什么区别,你可以多启动几个 php artisan queue:work --queue=payments,default
处理进程来加速 payments
队列的消费作为折衷方案。
如果你非要杠的话,payments
和 default
队列都为空的话,还是存在空轮询,确实是这样,这也是基于 Redis 列表结构、数据库这些驱动实现消息队列的弊端,因为都是采用轮询来读取队列消息,而不是采用发布订阅这种更高效的事件驱动机制,基于数据库比 Redis 在高并发时性能还要再差一等。
No Comments