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 22 PHP
php实现保存submit内容之后禁止刷新
Mar 19 PHP
小谈php正则提取图片地址
Mar 27 PHP
PHP实现下载断点续传的方法
Nov 12 PHP
php使用parse_url和parse_str解析URL
Feb 22 PHP
PHP中static关键字以及与self关键字的区别
Jul 01 PHP
php+mysql实现无限级分类
Nov 11 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
Dec 25 PHP
PHP curl批处理及多请求并发实现方法分析
Aug 15 PHP
PHP让网站移动访问更加友好方法
Feb 14 PHP
ThinkPHP框架整合微信支付之JSAPI模式图文详解
Apr 09 PHP
PHP框架实现WebSocket在线聊天通讯系统
Nov 21 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去除字符串中空字符的常用方法小结
2015/03/17 PHP
使用PHP生成图片的缩略图的方法
2015/08/18 PHP
php一个文件搞定微信jssdk配置
2016/12/12 PHP
PHP Swoole异步Redis客户端实现方法示例
2019/10/24 PHP
css把超出的部分显示为省略号的方法兼容火狐
2008/07/23 Javascript
DOM下的节点属性和操作小结
2009/05/14 Javascript
JavaScript Title、alt提示(Tips)实现源码解读
2010/12/12 Javascript
让你的博文自动带上缩址的实现代码,方便发到微博客上
2010/12/28 Javascript
jsp js鼠标移动到指定区域显示选项卡离开时隐藏示例
2013/06/14 Javascript
window.print打印指定div指定网页指定区域的方法
2014/08/04 Javascript
你不知道的高性能JAVASCRIPT
2016/01/18 Javascript
JavaScript简单下拉菜单特效
2016/09/13 Javascript
jQuery 检查某个元素在页面上是否存在实例代码
2016/10/27 Javascript
谈谈IntersectionObserver懒加载的具体使用
2019/10/15 Javascript
python 连接各类主流数据库的实例代码
2018/01/30 Python
把csv文件转化为数组及数组的切片方法
2018/07/04 Python
python将控制台输出保存至文件的方法
2019/01/07 Python
Python qqbot 实现qq机器人的示例代码
2019/07/11 Python
详解Python设计模式之策略模式
2020/06/15 Python
python 贪心算法的实现
2020/09/18 Python
安装并免费使用Pycharm专业版(学生/教师)
2020/09/24 Python
用Python实现职工信息管理系统
2020/12/30 Python
Python将QQ聊天记录生成词云的示例代码
2021/02/10 Python
python中openpyxl和xlsxwriter对Excel的操作方法
2021/03/01 Python
护理工作感言
2014/01/16 职场文书
校园活动宣传方案
2014/03/28 职场文书
安全教育月活动总结
2014/05/05 职场文书
服务标语口号
2014/07/01 职场文书
机关领导干部作风整顿整改措施
2014/09/19 职场文书
客房服务员岗位职责
2015/02/09 职场文书
质量保证书怎么写
2015/02/27 职场文书
2015年度公共机构节能工作总结
2015/05/26 职场文书
2015年美容师个人工作总结
2015/10/14 职场文书
JS + HTML 罗盘式时钟的实现
2021/05/21 Javascript
Python实现天气查询软件
2021/06/07 Python
Python常遇到的错误和异常
2021/11/02 Python