Laravel中为什么不使用blpop取队列详析

前言

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://www.jb51.net/article/131414.htm

为什么不用 blpop?

这里为什么不使用阻塞版本的 blpop 呢?

blpop 是阻塞版的 lpop,如果队列没有数据过来,那么在超时时间内就会一直阻塞,直到 rpush 数据到队列,有点类似 http 的长轮询,假如客户端取出数据的这一刻挂了,还没来得及暂存到另外的集合中,那么这个数据就丢失了。

你可能会问为何不跟 lpop 一样用 lua 脚本来处理并保证原子性?这个问题作者在 github 上有回答。(https://github.com/laravel/framework/issues/22939

我们知道 redis lua 脚本实际上就是事务,作者的大意也是说 MULTI/EXEC 包裹起来的 blpop 没有意义,这个时候它“退化”为非阻塞版的。

Redis 官方文档也有说明:

在MULTI/EXEC事务中的BLPOP

BLPOP 可以用于流水线(pipline,批量地发送多个命令并读入多个回复),但把它用在 MULTI / EXEC 块当中没有意义。因为这要求整个服务器被阻塞以保证块执行时的原子性,该行为阻止了其他客户端执行 LPUSH 或 RPUSH 命令。

因此,一个被包裹在 MULTI / EXEC 块内的 BLPOP 命令,行为表现得就像 LPOP 一样,对空列表返回 nil ,对非空列表弹出列表元素,不进行任何阻塞操作。

因此通过 lua 脚本操作 blpop 和 zadd 也没有意义,结论就是:因为没用到阻塞的特性,或者无法保证原子性。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Laravel 4.2 中队列服务(queue)使用感受

    这半个月,我参与重写了一个微信公众号后端系统,首次使用了laravel 4.2,以及laravel引以为傲的队列服务(queue). 由于整个系统涉及到多端交互,又有大量语音传输.处理的业务,我们在一些地方发现响应时间过长.之前的系统基于node.js和mongoDB,由于node天生就是异步,有守护进程,所以并没有出现过这个问题,而这次重写必然要引入异步流程了.Queue进入了我们的视线. 根据这一页几乎还全是英文的"中文文档" ,laravel恰好在4.2版本中刚刚引入了redis

  • Laravel中利用队列发送邮件的方法示例

    前言 本文主要给大家介绍了关于Laravel中队列发送邮件的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 批量处理任务的场景在我们开发中是经常使用的,比如邮件群发,消息通知,短信,秒杀等等,我们需要将这个耗时的操作放在队列中来处理,从而大幅度缩短Web请求和相应的时间.下面讲解下Laravel中队列的使用 1.配置文件 config/queue.php <?php return [ 'default' => env('QUEUE_DRIVER', 'sync'),

  • 浅谈Laravel队列实现原理解决问题记录

    问题 公司项目使用Laravel的开发的两个项目在同一个测试服务器部署,公用同一个redis.在使用laravel中的队列时,产生冲突干扰. 查找问题原因 在laravel 队列的操作类Illuminate\Queue\RedisQueue.php中可以看到pushRaw()方法: // 将一任务推入队列中 public function pushRaw($payload, $queue = null, array $options = []) { $this->getConnection()-

  • 浅析Laravel5中队列的配置及使用

    前言 队列常常用于两种场景,一种是高并发的情况,一种是耗时的操作,可以将任务放到队列中去,消费者从队列取任务执行,当然还有失败的情况如何处理,以及延迟,重试,更复杂的情况还有优先级的实现. 在Laravel 5中使用队列非常简单,并且失败处理,延迟,重试的方法都已经实现,下面简单尝试了一下Laravel的队列服务. Laravel默认支持以下几种队列服务:sync, database, beanstalkd, sqs, redis,本例使用redis作为队列服务,需先配置好Redis服务. 1.

  • 源码分析 Laravel 重复执行同一个队列任务的原因

    前言 laravel 的队列服务对各种不同的后台队列服务提供了统一的 API.队列允许你延迟执行消耗时间的任务,比如发送一封邮件.这样可以有效的降低请求响应的时间. 发现问题 在 Laravel 中使用 Redis 处理队列任务,框架提供的功能非常强大,但是最近遇到一个问题,就是发现一个任务被多次执行,这是为什么呢? 先说原因: 因为在 Laravel 中如果一个队列(任务)执行时间大于 60 秒,就会被认为执行失败并重新加入队列中,这样就会导致重复执行同一个任务. 这个任务的逻辑就是给用户推送

  • 关于 Laravel Redis 多个进程同时取队列问题详解

    前言 最近在工作中遇到了一个问题,开启多个进程处理队列会重复读取 Redis 中队列吗?是否因此导致重复执行任务?下面就来通过示例代码详细介绍下. 使用 Supervisor 监听 Laravel 队列任务,其中 Supervisor 的配置如下: [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/xxx.cn/artisan queue:work --que

  • Laravel框架队列原理与用法分析

    本文实例讲述了Laravel框架队列原理与用法.分享给大家供大家参考,具体如下: 最近有朋友有朋友问laravel队列的实现原理和经验,刚好用过所以整理了一下分享给大家. laravel队列配置参见:http://d.laravel-china.org/docs/5.1/queues 原理分析 创建分发任务方法 class TestController extends Controller { //其他方法 //发送消息 public function SendMessage(Request $

  • Laravel使用消息队列需要注意的一些问题

    前言 消息队列对于大型的Web项目来说是必不可少的一个模块,通过消息队列可以解决大并发和多种语言通信接口等问题.对于大并发的问题,可以将耗时的任务或者不能同时大量并行的任务封装起来传输到消息队列中,由处理程序不断从消息队列中提取消息并进行处理,这样通过消息队列的缓冲可以使得在大并发情况下不再阻塞,如果性能不够用还可以添加多个处理任务从消息队列中获取消息进行处理.比如数据库的操作,当对数据库的读.写操作过多时就会存在锁表等问题,读的问题可以通过缓存等方案解决,写的问题就需要消息队列来解决.而且,在

  • PHP的Laravel框架中使用消息队列queue及异步队列的方法

    queue配置 首先说明一下我之前的项目中如何使用queue的. 我们现在的项目都是用的symfony,老一点的项目用的symfony1.4,新一点的项目用的都是symfony2.symfony用起来整体感觉还是很爽的,尤其symfony2,整体上来讲使用了很多java里面框架的设计思想.但是他不支持queue.在symfony,我们使用queue也经历了几个过程.最开始使用张堰同学的httpsqs.这个简单使用,但是存在单点.毕竟我们的项目还是正式对外服务的,所以我们研究了Apache旗下的开

  • Laravel中为什么不使用blpop取队列详析

    前言 Redis 的 list 数据结构常用来做消息队列,通常使用的命令有 lpop/rpop ,还有带阻塞版的 blpop/brpop 等.Laravel 5.3 消息队列也是用的 lpop 取消息,为什么不用阻塞版的 blpop 呢? blpop 不用一直轮询,还可以同时取多个队列,blpop high low 30,更方便实现队列的优先级. 安全队列和不安全队列 什么是不安全的队列?比如客户端 lpop(统一以 lpop 为例) 从 redis 取出来的 job(任务)还没处理完进程挂掉了

  • Laravel中简约却不简单的Macroable宏指令详解

    百度百科的定义: 计算机科学里的宏(Macro),是一种批量处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串).这种替换在预编译时进行,称作宏展开. 我一开始接触宏是在大学上计算机基础课程时,老师讲office时说的.那时老师介绍宏操作时没太在意,只记得这一操作很强大,它能使日常工作变得更容易. 今天我们讲讲Laravel中的宏操作 首先完整的源码 <?php namespace Illuminat

  • TypeScript中import type与import的区别详析

    目录 背景 import type vs import 使用 import type 的好处 参考链接 总结 背景 这周遇到了一个比较奇怪的问题:如何在 TypeScript 中根据某个 enum 的取值来执行后续逻辑? 按理来说应该很简单,这是 enum 的定义: export enum MyEnum { DEFAULT = 0, SOME_VALUE = 1, SOME_OTHER_VALUE = 2, } 然后在另一个项目中,通过 import type 来引入: import type

  • Laravel中批量赋值Mass-Assignment的真正含义详解

    前言 很多人初次遇到 批量赋值 的时候,很容易理解成 批量添加多条数据,实际并非如此.下面话不多说了,请看下面的例子. 假设用户表 users 结构如下,且通过 is_admin 字段值为 1 或 0 来判断用户是否为 管理员,其中 is_admin 字段默认值为 0: +----+-----------+------------------+----------+--------------------------------------------------------------+ |

  • Javascript中click与blur事件的顺序详析

    一.现象 最近在开发中碰到了一个需求,具体需求如下图. 这是一个很常见的需求,input框负责在点击回车和失焦的时候确认输入.button负责清除输入,input绑定代码为: input.addEventListener('blur',function(){ console.log('input blur'); }); input.addEventListener('keyup',function(){ console.log('input keyup'); }); "X"绑定的代码为

  • Linux中改变文件权限的chmod命令详析

    前言 Linux的chmod命令是用来改变文件权限的,对于文件或者目录的普通权限,共有 3 种,分别为: r:读取: w:写入: x:执行. 今天为大家详细介绍下chmod命令的意义和用法 chmod命令 改变文件权限 一.符号模式 命令格式: chmod [who] operator [permission] filename who包含的选项及其含义: u 文件属主权限. g 属组用户权限. o 其他用户权限. a 所有用户(文件属主.属组用户及其他用户). operator包含的选项及其含

  • python中时间转换datetime和pd.to_datetime详析

    前言 我们在python对数据进行操作时,经常会选取某一时间段的数据进行分析.这里为大家介绍两个我经常用到的用来选取某一时间段数据的函数:datetime( )和pd.to_datetime( ). (一)datetime( ) (1)获取指定的时间和日期.datetime(%Y,%m,%d,%H,%M,%S) datetime共有6个参数,分别代表的是年月日时分秒.其中年月日是必须要传入的参数,时分秒可以不传入,默认全为零. eg: (2)将Str和Unicode转化为datetimedate

  • C++中4种强制类型转换的区别详析

    前言 C++即支持C风格的类型转换,又有自己风格的类型转换.C风格的转换格式很简单,但是有不少缺点的: 1.转换太过随意,可以在任意类型之间转换.你可以把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成一个派生类对象的指针,这些转换之间的差距是非常巨大的,但是传统的C语言风格的类型转换没有区分这些. 2.C风格的转换没有统一的关键字和标示符.对于大型系统,做代码排查时容易遗漏和忽略. C++风格完美的解决了上面两个问题.1.对类型转换做了细分,提供了四

  • Vue3.0中Ref与Reactive的区别示例详析

    目录 Ref与Reactive Ref Reactive Ref与Reactive的区别 shallowRef 与shallowReactive toRaw ---只修改数据不渲染页面 markRaw --- 不追踪数据 toRef --- 跟数据源关联 不修改UI toRefs ---设置多个toRef属性值 customRef ---自定义一个ref ref 捆绑页面的标签 总结 Ref与Reactive Ref Ref 用来创建基础类型的响应式数据,模板默认调用value显示数据.方法中修

随机推荐