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 相关文章推荐
给apache2.2加上mod_encoding模块後 php5.2.0 处理url出现bug
Apr 12 PHP
PHP之生成GIF动画的实现方法
Jun 07 PHP
php防止sql注入示例分析和几种常见攻击正则表达式
Jan 12 PHP
Codeigniter中禁止A Database Error Occurred错误提示的方法
Jun 12 PHP
ThinkPHP3.1新特性之字段合法性检测详解
Jun 19 PHP
PHP采集静态页面并把页面css,img,js保存的方法
Dec 23 PHP
php三种实现多线程类似的方法
Oct 30 PHP
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
Nov 25 PHP
PHP+Ajax实现无刷新分页实例详解(附demo源码下载)
Apr 07 PHP
php文件类型MIME对照表(比较全)
Oct 07 PHP
ThinkPHP5.0多个文件上传后找不到临时文件的修改方法
Jul 30 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
Mar 30 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获取ip的三个属性区别介绍(HTTP_X_FORWARDED_FOR,HTTP_VIA,REMOTE_ADDR)
2012/09/23 PHP
php 删除目录下N分钟前创建的所有文件的实现代码
2013/08/10 PHP
ThinkPHP之getField详解
2014/06/20 PHP
PHP数字和字符串ID互转函数(类似优酷ID)
2014/06/30 PHP
ThinkPHP 404页面的设置方法
2015/01/14 PHP
解读PHP中上传文件的处理问题
2016/05/29 PHP
php操作路径的经典方法(必看篇)
2016/10/04 PHP
简明json介绍
2008/09/28 Javascript
jquery ajax abort()的使用方法
2010/10/28 Javascript
jquery制作 随机弹跳的小球特效
2015/02/01 Javascript
Javascript中call和apply函数的比较和使用实例
2015/02/03 Javascript
Javascript URI 解析介绍
2015/03/15 Javascript
JS小数运算出现多为小数问题的解决方法
2016/06/02 Javascript
javascript中Date对象应用之简易日历实现
2016/07/12 Javascript
vue中如何使用ztree
2018/02/06 Javascript
微信小程序上传帖子的实例代码(含有文字图片的微信验证)
2020/07/11 Javascript
[02:43]DOTA2英雄基础教程 圣堂刺客
2013/12/09 DOTA
[01:52]2020年DOTA2 TI10夏季活动预告片
2020/07/15 DOTA
跟老齐学Python之使用Python查询更新数据库
2014/11/25 Python
在django中使用自定义标签实现分页功能
2017/07/04 Python
Python中矩阵库Numpy基本操作详解
2017/11/21 Python
浅谈Pandas中map, applymap and apply的区别
2018/04/10 Python
Windows下python3.7安装教程
2018/07/31 Python
numpy中loadtxt 的用法详解
2018/08/03 Python
Django实现分页显示效果
2019/10/31 Python
Django xadmin安装及使用详解
2020/10/26 Python
html5 利用重力感应实现摇一摇换颜色可用来做抽奖等等
2014/05/07 HTML / CSS
大学生毕业自荐信
2013/10/10 职场文书
财务管理职业生涯规划书
2014/02/26 职场文书
英语教育专业毕业生求职信
2014/08/28 职场文书
运动会闭幕词
2015/01/28 职场文书
颐和园导游词400字
2015/01/30 职场文书
追悼词范文大全
2015/06/23 职场文书
用Python爬取各大高校并可视化帮弟弟选大学,弟弟直呼牛X
2021/06/11 Python
AJAX实现指定部分页面刷新效果
2021/10/16 Javascript
Oracle锁表解决方法的详细记录
2022/06/05 Oracle