Redis任务队列

在处理Web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的更长一些。通过将待执行的相关信息放入队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能完成的操作,这种将工作交给任务处理器来执行的做法被称为任务队列(task queue)。

先进先出队列

可以使用Redis的列表结构存储任务的相关信息,并使用RPUSH将待执行任务的相关信息推入列表右端,使用阻塞版本的弹出命令BLPOP从队列中弹出待执行任务的相关信息(因为任务处理器除了执行任务不需要再执行其他工作,而命令的最大阻塞时限为30秒)。

多个可执行任务:
因为BLPOP命令每次只会从队列里面弹出一份数据,所以数据不会重复处理。在一些情况下,为每种任务单独使用一个队列的做法并不少见,但是在另外一些情况下,如果一个队列能够处理多种不同类型的任务,那么事情就会方便很多,比如可以让进程监视用户提供的多个队列,并从已知的已注册回调函数里面,选出一个函数来处理JSON编码的函数调用,只需要将传入参信息序列化成字符串传入即可发送一个任务,提供一个处理任务的方法回调即可执行任务。

任务优先级:
在使用队列的时候,程序可能会需要让特定的操作优先于其他操作执行,即高优先级的任务需要在低优先级的任务之前执行。BLPOP将弹出第一个非空列表的第一个元素,所以我们只需要将所有任务队列名数组按照优先级降序排序,让任务队列名数组作为BLPOP的入参即可实现上述功能(当然这种如果高优先级任务的生成速率大于消费速率,那么低优先级的任务就永远不会执行)。

延迟任务

使用列表结构可以实现只能执行一种任务的队列,也可以实现通过调用不同回调函数来执行不同任务的队列,甚至还可以实现简单的优先级队列,但是有些时候,这些特性还不足以满足我们的需求。
有序集合队列(ZSET queue)存储的每个被延迟的任务都是一个包含4个值得JSON列表,这4个值分别是:唯一标识符(UUID)、处理任务的队列的名字、处理任务的回调函数的名字、传给回调函数的参数。在有序集合里面,任务的分值会被设置为任务的执行时间,而立即可执行的任务将被直接插入任务队列里面。
因为Redis没有提供直接的方法可以阻塞有序集合直到元素的分值低于当前Unix时间戳位置,所以我们需要自己来查找有序集合里面分值低于当前Unix时间戳的任务。因为所有被延迟的任务都存储在同一个有序集合队列里面,所以程序只需要获取有序集合里面排名第一的元素以及该元素的分值就可以了:如果队列里面没有任何任务,或者任务的执行时间尚未来临,那么程序将在短暂等待之后重试;如果任务的执行时间已到,那么程序将根据任务包含的标识符来获取一个细粒度锁,接着从有序集合里面移除要被执行的任务,并将它添加到适当的任务队列里面。通过将可执行的任务添加到任务队列里面而不是直接执行它们,我们可以吧获取可执行任务的进程数量限制在一两个之内,而不必根据工作进程的数量来决定运行多少个获取进程,这减少了获取可执行任务所需的花销。
因为有序集合不具备列表的阻塞弹出机制,所以程序需要不断地进行循环,并尝试从队列中获取要被执行的任务,虽然这一操作会增大网络和处理器的负载,但因为我们只会运行一两个这样的程序,所以这并不会消耗太多资源。如果想要进一步减少函数的运行开销,那么可以通过在函数里面增加一个自适应方法 (adaptive method) ,让函数在一段时间内都没有发现可执行的任务时,自动延长休眠时间,或者根据下一个任务的执行时间来决定休眠的时长,并将休眠时长的最大值限制为 100ms ,从而确保任务可以被及时执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值