手机版

为什么不在Laravel中使用blpop来获取队列

时间:2021-08-30 来源:互联网 编辑:宝哥软件园 浏览:

前言

Redis的列表数据结构常被用作消息队列,常用的命令有lpop/rpop和blpop/brpop带阻塞版本。Laravel 5.3消息队列也使用lpop来获取消息,那么为什么不使用blpop的阻塞版本呢?

Blpop不需要一直轮询,也可以同时取多个队列。blpop高低30更方便实现队列的优先级。

安全队列和不安全队列

什么是不安全队列?比如客户端lpop(以lpop为例)从redis提取的作业(任务)还没有处理完,进程挂起或者遇到异常。因为此时服务器上没有副本,所以作业会丢失。这种队列不安全。

Laravel做了一个完善的机制来保证消息队列的可靠性,如果进程挂机或者处理失败,可以重试,比如取队列放入另一个集合进行“临时存储”。如代码所示,lpop用于获取队列,同时zadd到另一个集合,Redisla用于保证原子性。

公共静态函数pop(){返回“LUA”-从队列中弹出第一个作业.本地作业=redis.call('lpop ',KEYS[1])本地保留=false如果(作业~=false)则-增加尝试计数并将作业放在保留队列中.reserved=CJ son . decode(job)reserved['尝试']=reserved['尝试']1 reserved=CJ son . encode(reserved)redis . call(' zadd ',KEYS[2],ARGV[1],reserved)end return {job,reserved } LUA;}在Laravel队列的工作原理之前,已经整理了一篇博文。请参考https://www.jb51.net/article/131414.htm.

为什么不用blpop?

为什么不在这里使用blpop的屏蔽版本呢?

Blpop是lpop的封锁版本。如果没有来自队列的数据,它将在超时期间被阻塞,直到数据被推送到队列,这类似于http的长轮询。如果客户端在取出数据的那一刻挂机,还没有时间将数据临时存储到另一个集合中,那么数据就会丢失。

你可能会问为什么不用lua脚本来处理和保证原子性,就像lpop一样。笔者在github上有这个问题的答案。(https://github.com/laravel/framework/issues/22939)

我们知道redis lua脚本实际上是一个事务,作者的总体思路是MULTI/EXEC包装的blpop没有意义,此时“退化”为非阻塞版本。

Redis官方文件还指出:

多/执行事务中的BLPOP

BLPOP可以在流水线中使用(批量发送多个命令,读取多个回复),但在MULTI/EXEC块中使用没有意义。这种行为会阻止其他客户端执行LPUSH或RPUSH命令,因为它需要阻塞整个服务器以确保块执行的原子性。

因此,包装在MULTI/EXEC块中的BLPOP命令的行为类似于LPOP,向空列表返回nil,并向非空列表弹出列表元素,而无需任何阻塞操作。

因此,通过lua脚本操作blpop和zadd是没有意义的。结论是:因为没有使用阻塞特性,或者原子性不能保证。

摘要

以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。

版权声明:为什么不在Laravel中使用blpop来获取队列是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。