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 批量更新网页内容实现代码
Jan 05 PHP
php 图片加水印与上传图片加水印php类
May 12 PHP
php自动获取字符串编码函数mb_detect_encoding
May 31 PHP
10条PHP高级技巧[修正版]
Aug 02 PHP
PHP性能优化工具篇Benchmark类调试执行时间
Dec 06 PHP
php使用mkdir创建多级目录入门例子
May 10 PHP
php创建session的方法实例详解
Jan 27 PHP
php中switch与ifelse的效率区别及适用情况分析
Feb 12 PHP
laravel migrate初学常见错误的解决方法
Oct 11 PHP
PHP获取当前系统时间的方法小结
Oct 03 PHP
ThinkPHP5&amp;5.1框架关联模型分页操作示例
Aug 03 PHP
Laravel5.1 框架Request请求操作常见用法实例分析
Jan 04 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
支持oicq头像的留言簿(二)
2006/10/09 PHP
WordPress中创建用户角色的相关PHP函数使用详解
2015/12/25 PHP
php实现获取农历(阴历)、节日、节气的类与用法示例
2017/11/20 PHP
判断iframe是否加载完成的完美方法
2010/01/07 Javascript
javascript检测浏览器flash版本的实现代码
2011/12/06 Javascript
排序算法的javascript实现与讲解(99js手记)
2014/09/28 Javascript
JavaScript常用验证函数实例汇总
2014/11/25 Javascript
JavaScript实现图片自动加载的瀑布流效果
2016/04/11 Javascript
总结javascript中的六种迭代器
2016/08/16 Javascript
jQGrid动态填充select下拉框的选项值(动态填充)
2016/11/28 Javascript
Node.js如何响应Ajax的POST请求并且保存为JSON文件详解
2017/03/10 Javascript
微信小程序实现倒计时调用相机自动拍照功能
2018/06/10 Javascript
vue单页缓存存在的问题及解决方案(小结)
2018/09/25 Javascript
微信小程序模板template简单用法示例
2018/12/04 Javascript
移动端自适应flexible.js的使用方法(不用三大框架,仅写一个单html页面使用)推荐
2019/04/02 Javascript
Vue2.0实现组件之间数据交互和通信操作示例
2019/05/16 Javascript
微信小程序列表时间戳转换实现过程解析
2019/10/12 Javascript
Vue3为什么这么快
2020/09/23 Javascript
node.js如何根据URL返回指定的图片详解
2020/10/21 Javascript
[01:23]一分钟告诉你 DOTA2为什么叫信仰2
2014/06/20 DOTA
让python 3支持mysqldb的解决方法
2017/02/14 Python
pyspark 读取csv文件创建DataFrame的两种方法
2018/06/07 Python
Python操作Excel插入删除行的方法
2018/12/10 Python
Python3爬虫学习入门教程
2018/12/11 Python
使用python将多个excel文件合并到同一个文件的方法
2019/07/09 Python
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
SQL Server数据库笔试题和答案
2016/02/04 面试题
汽车维修专业个人求职信范文
2014/01/01 职场文书
会计辞职信范文
2014/01/15 职场文书
总会计师岗位职责
2014/02/19 职场文书
最经典的大学生职业生涯规划范文
2014/03/05 职场文书
2014年党员承诺书范文
2014/05/20 职场文书
大学运动会加油稿200字(5篇)
2014/09/27 职场文书
英文投诉信格式
2015/07/03 职场文书
婚礼答谢词范文
2015/09/29 职场文书
JPA 通过Specification如何实现复杂查询
2021/11/23 Java/Android