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 相关文章推荐
用 PHP5 轻松解析 XML
Dec 04 PHP
php 正则表达式小结
Aug 31 PHP
php simplexmlElement操作xml的命名空间实现代码
Jan 04 PHP
YII模块实现绑定二级域名的方法
Jul 09 PHP
PHP基于php_imagick_st-Q8.dll实现JPG合成GIF图片的方法
Jul 11 PHP
PHP ignore_user_abort函数详细介绍和使用实例
Jul 15 PHP
PHP面向对象程序设计之类常量用法实例
Aug 20 PHP
thinkPHP实现将excel导入到数据库中的方法
Apr 22 PHP
php简单实现多语言切换的方法
May 09 PHP
php parse_str() 函数的定义和用法
May 23 PHP
浅析PHP数据导出知识点
Feb 17 PHP
php防止表单重复提交实例讲解
Feb 11 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 clearstatcache()函数详解
2010/03/02 PHP
基于PHP magic_quotes_gpc的使用方法详解
2013/06/24 PHP
php中的比较运算符详解
2013/10/28 PHP
PHP下载远程文件到本地存储的方法
2015/03/24 PHP
Laravel定时任务的每秒执行代码
2019/10/22 PHP
phpStorm2020 注册码
2020/09/17 PHP
URL编码转换,escape() encodeURI() encodeURIComponent()
2006/12/27 Javascript
拖动布局之保存布局页面cookies篇
2010/10/29 Javascript
jQuery数组处理代码详解(含实例演示)
2012/02/03 Javascript
javascript 文件的同步加载与异步加载实现原理
2012/12/13 Javascript
通过js为元素添加多项样式,浏览器全兼容写法
2014/08/30 Javascript
Javascript核心读书有感之语言核心
2015/02/01 Javascript
jQuery根据元素值删除数组元素的方法
2015/06/24 Javascript
jquery实现表单获取短信验证码代码
2017/03/13 Javascript
深入理解node.js之path模块
2017/05/03 Javascript
JavaScript脚本语言是什么_动力节点Java学院整理
2017/06/26 Javascript
vue多次循环操作示例
2019/02/08 Javascript
Vue组件系列开发之模态框
2019/04/18 Javascript
浅谈vue中组件绑定事件时是否加.native
2019/11/09 Javascript
python中zip()方法应用实例分析
2016/04/16 Python
Python简单实现TCP包发送十六进制数据的方法
2016/04/16 Python
Opencv+Python 色彩通道拆分及合并的示例
2018/12/08 Python
Python udp网络程序实现发送、接收数据功能示例
2019/12/09 Python
python如何使用socketserver模块实现并发聊天
2019/12/14 Python
python时间日期操作方法实例小结
2020/02/06 Python
python 实现在shell窗口中编写print不向屏幕输出
2020/02/19 Python
pytorch 使用加载训练好的模型做inference
2020/02/20 Python
详解Python中的编码问题(encoding与decode、str与bytes)
2020/09/30 Python
美国奢侈品购物平台:Orchard Mile
2018/05/02 全球购物
临床医学专业毕业生的自我评价
2013/10/17 职场文书
采购部岗位职责
2013/11/24 职场文书
班组安全员工作职责
2014/02/01 职场文书
财务担保书范文
2014/04/02 职场文书
童年读书笔记
2015/06/26 职场文书
安全事故隐患排查治理制度
2015/08/05 职场文书
mysql中整数数据类型tinyint详解
2021/12/06 MySQL