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中根据某年第几天计算出日期年月日的代码
Feb 24 PHP
PHP新手用的Insert和Update语句构造类
Mar 31 PHP
解析PHP将对象转换成数组的方法(兼容多维数组类型)
Jun 21 PHP
php设计模式之单例、多例设计模式的应用分析
Jun 30 PHP
浅谈discuz密码加密的方式
May 22 PHP
ThinkPHP中的常用查询语言汇总
Aug 22 PHP
PHP环境中Memcache的安装和使用
Nov 05 PHP
PHP面向对象程序设计高级特性详解(接口,继承,抽象类,析构,克隆等)
Dec 02 PHP
thinkphp jquery实现图片上传和预览效果
Jul 22 PHP
PHP开发中解决并发问题的几种实现方法分析
Nov 13 PHP
PHP聚合式迭代器接口IteratorAggregate用法分析
Dec 28 PHP
PHP递归统计系统中代码行数
Sep 19 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
Sony CFR 320 修复改造
2020/03/14 无线电
PHP实现的连贯操作、链式操作实例
2014/07/08 PHP
学习php设计模式 php实现访问者模式(Visitor)
2015/12/07 PHP
CI映射(加载)数据到view层的方法
2016/03/28 PHP
laravel中数据显示方法(默认值和下拉option默认选中)
2019/10/11 PHP
javascript编程起步(第六课)
2007/01/10 Javascript
Javascript匿名函数的一种应用 代码封装
2010/06/27 Javascript
getElementByIdx_x js自定义getElementById函数
2012/01/24 Javascript
使用forever管理nodejs应用教程
2014/06/03 NodeJs
零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门
2014/12/20 Javascript
js闭包实现按秒计数
2015/04/23 Javascript
Jquery easyui开启行编辑模式增删改操作
2016/01/14 Javascript
jQuery 更改checkbox的状态,无效的解决方法
2016/07/22 Javascript
NodeJS使用formidable实现文件上传
2016/10/27 NodeJs
js模式化窗口问题![window.dialogArguments]
2016/10/30 Javascript
Vue上传组件vue Simple Uploader的用法示例
2017/08/25 Javascript
学习使用ExpressJS 4.0中的新Router的用法
2018/11/06 Javascript
解决layer弹出层的内容页点击按钮跳转到新的页面问题
2019/09/14 Javascript
JavaScript中0、空字符串、'0'是true还是false的知识点分享
2019/09/16 Javascript
微信小程序中的列表切换功能实例代码详解
2020/06/09 Javascript
[53:15]Mineski vs iG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python实现提取谷歌音乐搜索结果的方法
2015/07/10 Python
python中的decorator的作用详解
2018/07/26 Python
基于python实现名片管理系统
2018/11/30 Python
Python线程之定位与销毁的实现
2019/02/17 Python
Python 分布式缓存之Reids数据类型操作详解
2020/06/24 Python
Python word文本自动化操作实现方法解析
2020/11/05 Python
Python字符串对齐、删除字符串不需要的内容以及格式化打印字符
2021/01/23 Python
使用简单的CSS3属性实现炫酷读者墙效果
2014/01/08 HTML / CSS
html5新增的属性和废除的属性简要概述
2013/02/20 HTML / CSS
html5中 media(播放器)的api使用指南
2014/12/26 HTML / CSS
世界上获奖最多的手机镜头:Olloclip
2018/03/03 全球购物
新加坡一家在线男士皮具品牌:Faire Leather Co.
2019/12/01 全球购物
超市促销实习自我鉴定
2013/09/23 职场文书
项目专员岗位职责
2013/12/04 职场文书
《少年王勃》教学反思
2014/04/27 职场文书