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 相关文章推荐
php ob_flush,flush在ie中缓冲无效的解决方法
May 09 PHP
深入解析php之sphinx
May 15 PHP
解析:php调用MsSQL存储过程使用内置RETVAL获取过程中的return值
Jul 03 PHP
phpstrom使用xdebug配置方法
Dec 17 PHP
CI框架在CLI下执行占用内存过大问题的解决方法
Jun 17 PHP
php中使用session_set_save_handler()函数把session保存到MySQL数据库实例
Nov 06 PHP
PHP生成唯一订单号的方法汇总
Apr 16 PHP
php递归删除指定文件夹的方法小结
Apr 20 PHP
php模板引擎技术简单实现
Mar 15 PHP
PHP异常处理定义与使用方法分析
Jul 25 PHP
Yii框架中使用PHPExcel的方法分析
Jul 25 PHP
Yii框架的路由配置方法分析
Sep 09 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扩展程序实现守护进程
2015/04/16 PHP
PHP6连接SQLServer2005的三部曲
2016/04/15 PHP
srcElement表格样式
2006/09/03 Javascript
jquery插件实现鼠标经过图片右侧显示大图的效果(类似淘宝)
2013/02/04 Javascript
javascript事件冒泡详解和捕获、阻止方法
2014/04/12 Javascript
Bootstrap弹出框modal上层的输入框不能获得焦点问题的解决方法
2016/12/13 Javascript
通过sails和阿里大于实现短信验证
2017/01/04 Javascript
浅谈JavaScript中的apply/call/bind和this的使用
2017/02/26 Javascript
在 Angular 中实现搜索关键字高亮示例
2017/03/21 Javascript
js插件实现图片滑动验证码
2020/09/29 Javascript
AngularJs中$cookies简单用法分析
2019/05/30 Javascript
微信小程序之下拉列表实现方法解析(附完整源码)
2019/08/23 Javascript
layui 实现table翻页滚动条位置保持不变的例子
2019/09/05 Javascript
Bootstrap实现模态框效果
2019/09/30 Javascript
jquery轮播图插件使用方法详解
2020/07/31 jQuery
Python 类的继承实例详解
2017/03/25 Python
python初学之用户登录的实现过程(实例讲解)
2017/12/23 Python
解决Tensorflow使用pip安装后没有model目录的问题
2018/06/13 Python
Django上线部署之IIS的配置方法
2019/08/22 Python
pytorch多GPU并行运算的实现
2019/09/27 Python
python基于opencv检测程序运行效率
2019/12/28 Python
Pytorch 实现sobel算子的卷积操作详解
2020/01/10 Python
离线状态下在jupyter notebook中使用plotly实例
2020/04/24 Python
如何在python中判断变量的类型
2020/07/29 Python
CSS3教程:新增加的结构伪类
2009/04/02 HTML / CSS
以实惠的价格提供高品质的时尚:Newchic
2018/01/18 全球购物
工程概预算专业毕业生求职信
2013/10/04 职场文书
妇联主席先进事迹
2014/05/18 职场文书
计划生育宣传标语
2014/06/21 职场文书
2014年学习厉行节约反对浪费思想汇报
2014/09/10 职场文书
党员批评与自我批评思想汇报
2014/10/08 职场文书
2015年党小组工作总结
2015/05/26 职场文书
2016年小学“感恩教师”主题队日活动总结
2016/04/01 职场文书
2019企业给员工的慰问信
2019/06/24 职场文书
MYSQL 的10大经典优化案例场景实战
2021/09/14 MySQL
SpringBoot前端后端分离之Nginx服务器下载安装过程
2022/08/14 Servers