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生成静态页面详解
Nov 19 PHP
生成php程序的php代码
Apr 07 PHP
php 什么是PEAR?(第三篇)
Mar 19 PHP
php读取文件内容的几种方法详解
Jun 26 PHP
PHP中的魔术方法总结和使用实例
May 11 PHP
PHP结合jQuery实现找回密码
Jul 22 PHP
php cookie用户登录的详解及实例代码
Jan 03 PHP
php+webSoket实现聊天室示例代码(附源码)
Feb 17 PHP
用PHP去掉文件头的Unicode签名(BOM)方法
Jun 22 PHP
完美的php分页类
Oct 24 PHP
Yii2.0 RESTful API 基础配置教程详解
Dec 26 PHP
thinkphp3.2同时连接两个数据库的简单方法
Aug 13 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模拟SQL Server的两个日期处理函数
2006/10/09 PHP
mysql4.1以上版本连接时出现Client does not support authentication protocol问题解决办法
2007/03/15 PHP
PHP的mysqli_ssl_set()函数讲解
2019/01/23 PHP
php设计模式之组合模式实例详解【星际争霸游戏案例】
2020/03/27 PHP
PHP使用POP3读取邮箱接收邮件的示例代码
2020/07/08 PHP
PHP实现计算器小功能
2020/08/28 PHP
用javascript动态调整iframe高度的代码
2007/04/10 Javascript
JavaScript 解析读取XML文档 实例代码
2009/07/07 Javascript
js 模拟气泡屏保效果代码
2010/07/10 Javascript
基于jquery的Repeater实现代码
2010/07/17 Javascript
js判读浏览器是否支持html5的canvas的代码
2013/11/18 Javascript
JavaScript中诡异的delete操作符
2015/03/12 Javascript
js实现Select列表各项上移和下移的方法
2015/08/14 Javascript
精彩的Bootstrap案例分享 重点在注释!(选项卡、栅格布局)
2016/07/01 Javascript
Vue+Vux项目实践完整代码
2017/11/30 Javascript
微信小程序实现卡片左右滑动效果的示例代码
2019/05/01 Javascript
vue-drag-chart 拖动/缩放图表组件的实例代码
2020/04/10 Javascript
js验证账户名是否重复
2020/05/26 Javascript
vue使用echarts实现水平柱形图实例
2020/09/09 Javascript
antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
2021/01/08 Vue.js
[52:37]完美世界DOTA2联赛循环赛 Forest vs DM BO2第一场 10.29
2020/10/29 DOTA
MySQLdb ImportError: libmysqlclient.so.18解决方法
2014/08/21 Python
python PyTorch参数初始化和Finetune
2018/02/11 Python
对python生成业务报表的实例详解
2019/02/03 Python
解决python和pycharm安装gmpy2 出现ERROR的问题
2020/08/28 Python
德国柯吉澳趣味家居:Koziol
2017/08/24 全球购物
关于Java String的一道面试题
2013/09/29 面试题
自学考试自我鉴定范文
2013/09/26 职场文书
初中政治教学反思
2014/01/17 职场文书
感恩之星事迹材料
2014/05/03 职场文书
高一课前三分钟演讲稿
2014/09/13 职场文书
2016党员学习《反对自由主义》心得体会
2016/01/22 职场文书
教师学期述职自我鉴定
2019/08/16 职场文书
手写Spirit防抖函数underscore和节流函数lodash
2022/03/22 Javascript
《吸血鬼幸存者》新内容发布 追加多个全新模式
2022/04/07 其他游戏
Python简易开发之制作计算器
2022/04/28 Python