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导出oracle库的php代码
Apr 20 PHP
php的chr和ord函数实现字符加减乘除运算实现代码
Dec 05 PHP
PHP彩蛋信息介绍和阻止泄漏的方法(隐藏功能)
Aug 06 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
Aug 11 PHP
PHP图片处理之使用imagecopyresampled函数实现图片缩放例子
Nov 19 PHP
php实现读取手机客户端浏览器的类
Jan 09 PHP
PHP编写RESTful接口的方法
Feb 21 PHP
php使用SAE原生Mail类实现各种类型邮件发送的方法
Oct 10 PHP
thinkPHP模板中for循环与switch语句用法示例
Nov 30 PHP
php写app接口并返回json数据的实例(分享)
May 20 PHP
PHP检查URL包含特定字符串实例方法
Feb 11 PHP
php png失真的原因及解决办法
Nov 17 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
在任意字符集下正常显示网页的方法一
2007/04/01 PHP
PHP 地址栏信息的获取代码
2009/01/07 PHP
php+ajax实现无刷新分页
2015/11/18 PHP
Yii使用migrate命令执行sql语句的方法
2016/03/15 PHP
PHP hex2bin()函数用法讲解
2019/02/25 PHP
PHP将整数数字转换为罗马数字实例分享
2019/03/17 PHP
javascript EXCEL 操作类代码
2009/07/30 Javascript
jQuery的Ajax的自动完成功能控件简要说明
2013/02/22 Javascript
js之事件冒泡和事件捕获详细介绍
2013/10/28 Javascript
js实现页面跳转重定向的几种方式
2014/05/29 Javascript
JavaScript中的关联数组问题
2015/03/04 Javascript
jQuery 遍历函数详解
2015/07/05 Javascript
JavaScript知识点总结之如何提高性能
2016/01/15 Javascript
js判断一个字符串是以某个字符串开头的简单实例
2016/12/27 Javascript
JS解决移动web开发手机输入框弹出的问题
2017/03/31 Javascript
详解vue-cli 脚手架项目-package.json
2017/07/04 Javascript
angularjs 缓存的使用详解
2018/03/19 Javascript
如何获取TypeScript的声明文件.d.ts
2018/05/01 Javascript
JavaScript使用ul中li标签实现删除效果
2019/04/15 Javascript
浅谈JavaScript中等号、双等号、 三等号的区别
2020/08/06 Javascript
vue-cli 关闭热更新操作
2020/09/18 Javascript
nuxt 每个页面head标签内容设置方式
2020/11/05 Javascript
[04:11]DOTA2上海特级锦标赛主赛事首日TOP10
2016/03/03 DOTA
Python爬虫模拟登录带验证码网站
2016/01/22 Python
python flask实现分页效果
2017/06/27 Python
解决python3 json数据包含中文的读写问题
2018/05/10 Python
Python把csv数据写入list和字典类型的变量脚本方法
2018/06/15 Python
详解Python3 pandas.merge用法
2019/09/05 Python
Python3连接Mysql8.0遇到的问题及处理步骤
2020/02/17 Python
详解python tkinter包获取本地绝对路径(以获取图片并展示)
2020/09/04 Python
台湾旅游网站:灿星旅游
2018/10/11 全球购物
五十岁生日宴会答谢词
2014/01/15 职场文书
酒店优秀员工事迹材料
2014/06/02 职场文书
详解Redis实现限流的三种方式
2021/04/27 Redis
发工资啦!教你用Python实现邮箱自动群发工资条
2021/05/10 Python
Go web入门Go pongo2模板引擎
2022/05/20 Golang