Laravel中为什么不使用blpop取队列详析


Posted in PHP onAugust 01, 2018

前言

Redis 的 list 数据结构常用来做消息队列,通常使用的命令有 lpop/rpop ,还有带阻塞版的 blpop/brpop 等。Laravel 5.3 消息队列也是用的 lpop 取消息,为什么不用阻塞版的 blpop 呢?

blpop 不用一直轮询,还可以同时取多个队列,blpop high low 30,更方便实现队列的优先级。

安全队列和不安全队列

什么是不安全的队列?比如客户端 lpop(统一以 lpop 为例) 从 redis 取出来的 job(任务)还没处理完进程挂掉了或者遇到了异常,由于此时服务器上已经没有副本了,这个 job 就丢失了。这种队列就是不安全的。

Laravel 正是为了保证消息队列的可靠,进程挂掉了或者处理失败还可以重试等,做了比较完善的机制,如取队列的同时把队列放入另一个集合中“暂存”起来。如代码所示,使用 lpop 取出队列,同时 zadd 到另一个集合,使用 redis lua 来保证原子性。

public static function pop()
{
 return <<<'LUA'
-- Pop the first job off of the queue...
local job = redis.call('lpop', KEYS[1])
local reserved = false
 
if(job ~= false) then
-- Increment the attempt count and place job on the reserved queue...
reserved = cjson.decode(job)
reserved['attempts'] = reserved['attempts'] + 1
reserved = cjson.encode(reserved)
redis.call('zadd', KEYS[2], ARGV[1], reserved)
end
 
return {job, reserved}
LUA;
}

具体 Laravel 队列工作原理之前有一篇博文进行了整理,请参考:https://3water.com/article/131414.htm

为什么不用 blpop?

这里为什么不使用阻塞版本的 blpop 呢?

blpop 是阻塞版的 lpop,如果队列没有数据过来,那么在超时时间内就会一直阻塞,直到 rpush 数据到队列,有点类似 http 的长轮询,假如客户端取出数据的这一刻挂了,还没来得及暂存到另外的集合中,那么这个数据就丢失了。

你可能会问为何不跟 lpop 一样用 lua 脚本来处理并保证原子性?这个问题作者在 github 上有回答。(https://github.com/laravel/framework/issues/22939)

Laravel中为什么不使用blpop取队列详析

我们知道 redis lua 脚本实际上就是事务,作者的大意也是说 MULTI/EXEC 包裹起来的 blpop 没有意义,这个时候它“退化”为非阻塞版的。

Redis 官方文档也有说明:

在MULTI/EXEC事务中的BLPOP

BLPOP 可以用于流水线(pipline,批量地发送多个命令并读入多个回复),但把它用在 MULTI / EXEC 块当中没有意义。因为这要求整个服务器被阻塞以保证块执行时的原子性,该行为阻止了其他客户端执行 LPUSH 或 RPUSH 命令。

因此,一个被包裹在 MULTI / EXEC 块内的 BLPOP 命令,行为表现得就像 LPOP 一样,对空列表返回 nil ,对非空列表弹出列表元素,不进行任何阻塞操作。

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
如何将一个表单同时提交到两个地方处理
Oct 09 PHP
解析:php调用MsSQL存储过程使用内置RETVAL获取过程中的return值
Jul 03 PHP
php+js实现异步图片上传实例分享
Jun 02 PHP
PHP中IP地址与整型数字互相转换详解
Aug 20 PHP
教你php如何实现验证码
Jan 20 PHP
Symfony2创建页面实例详解
Mar 18 PHP
php通过curl添加cookie伪造登陆抓取数据的方法
Apr 02 PHP
php使用Jpgraph创建折线图效果示例
Feb 15 PHP
php str_getcsv把字符串解析为数组的实现方法
Apr 05 PHP
利用PHP判断是否是连乘数字串的方法示例
Jul 03 PHP
phpcms配置列表页以及获得文章发布时间
Jul 04 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
Dec 20 PHP
Laravel5.5以下版本中如何自定义日志行为详解
Aug 01 #PHP
PHP实现随机数字、字母的验证码功能
Aug 01 #PHP
PHP使用XMLWriter读写xml文件操作详解
Jul 31 #PHP
laravel + vue实现的数据统计绘图(今天、7天、30天数据)
Jul 31 #PHP
PHP常用日期加减计算方法实例小结
Jul 31 #PHP
ThinkPHP5.0多个文件上传后找不到临时文件的修改方法
Jul 30 #PHP
PHP笛卡尔积实现算法示例
Jul 30 #PHP
You might like
php调用C代码的实现方法
2014/03/11 PHP
PHP里8个鲜为人知的安全函数分析
2014/12/09 PHP
php 微信公众平台开发模式实现多客服的实例代码
2016/11/07 PHP
PHP 超级全局变量相关总结
2020/06/30 PHP
JavaScript Ajax Json实现上下级下拉框联动效果实例代码
2013/11/23 Javascript
解决Extjs4中form表单提交后无法进入success函数问题
2013/11/26 Javascript
jquery操作select详解(取值,设置选中)
2014/02/07 Javascript
Javascript学习笔记之 函数篇(一) : 函数声明和函数表达式
2014/06/24 Javascript
使用jquery解析XML的方法
2014/09/05 Javascript
node.js中的buffer.Buffer.byteLength方法使用说明
2014/12/10 Javascript
JavaScript中Cookie操作实例
2015/01/09 Javascript
Jquery uploadify上传插件使用详解
2016/01/13 Javascript
JavaScript中实现键值对应的字典与哈希表结构的示例
2016/06/12 Javascript
JSONP跨域请求实例详解
2016/07/04 Javascript
深入理解javascript作用域第二篇之词法作用域和动态作用域
2016/07/24 Javascript
AngularJS创建自定义指令的方法详解
2016/11/03 Javascript
canvas实现动态小球重叠效果
2017/02/06 Javascript
layer.prompt输入层的例子
2019/09/24 Javascript
手把手带你搭建一个node cli的方法示例
2020/08/07 Javascript
google广告之另类js调用实现代码
2020/08/22 Javascript
[00:37]DOTA2上海特级锦标赛 OG战队宣传片
2016/03/03 DOTA
Django实现分页显示效果
2019/10/31 Python
Python之字典对象的几种创建方法
2020/09/30 Python
canvas绘制太极图的实现示例
2020/04/29 HTML / CSS
navabi英国:设计师大码女装
2019/06/25 全球购物
都柏林通行卡/城市通票:The Dublin Pass
2020/02/16 全球购物
电气工程及自动化专业自荐书范文
2013/12/18 职场文书
学生不讲诚信检讨书
2014/09/29 职场文书
小学生优秀评语
2014/12/29 职场文书
教师岗位职责范本
2015/04/02 职场文书
2019军训心得体会
2019/06/27 职场文书
让人瞬间清醒的句子,句句经典,字字如金
2019/07/08 职场文书
解决python存数据库速度太慢的问题
2021/04/23 Python
Feign调用全局异常处理解决方案
2021/06/24 Java/Android
Minikube搭建Kubernetes集群
2022/03/31 Servers
《最终幻想14》6.01版本4月5日推出 追加新任务新道具
2022/04/03 其他游戏