美文网首页Redis
Redis延迟队列

Redis延迟队列

作者: 吳下阿蒙 | 来源:发表于2018-08-27 08:09 被阅读116次

不同的微服务之间做异步通迅时通常会使用Kafka,它非常适用于对消费次序或时间没有强一致性需要的场景。如果消息需要在指定的时间才可以被消费,Kafka并没有原生支持此类消费场景,需要较复杂的实现。我们把支持此类场景的队列称为延迟队列

逻辑上,延迟队列中的消息按延迟时间排序

延迟队列的主要特性是进入队列的消息会被推迟到指定的时间才出队被消费。而对于Kafka队列,消息入队后会排在队尾等待被消费,并不能指定出队时间。因此,延迟队列中的一条消息,除了消息本身外,还需要附加一个“何时出队”的信息。

例如,如果我把这篇文章设置为2018年3月14日发布,Medium可以把这如下的消息加入到延迟队列中;等到2018年3月14日这条消息才会出队,触发发布这篇文章的流程。

{
    "time": "2018-03-14T00:00:00Z",
    "message": "发布《Redis延迟队列》"
}

既然Kafka不支持延迟队列,我们有什么选择呢?

  • Java Collections Framework中包含的DelayQueue便是延迟队列的实现。然而这毕竟只是一个数据结构,基于它建设一个队列服务的工作量不少。
  • RabbitMQ通过RabbitMQ Delayed Message Plugin可支持延迟队列。可惜我司的基础设施中没有RabbitMQ。
  • Redis的Sorted Set可被用于实现简单的延迟队列。利用Redis的Lua支持我们也可以将基建设成一个功能全面的延迟队列服务。

下文将介绍如何使用Redis的Sorted Set实现简单的延迟队列。

Sorted Set是一个有序的集合,集合内元素的排序基于其加入集合时指定的score。通过ZRANGEBYSCORE命令,我们可以取得score在指定区间内的元素。将集合中的元素做为消息,score视为延迟的时间,这便是一个延迟队列的模型。

生产者通过ZADD将消息发送到队列中:

127.0.0.1:6379> ZADD delay-queue 1520985600 "publish article"

消费者通过ZRANGEBYSCORE获取消息。如果时间未到,将得不到消息;当时间已到或已超时,都可以得到消息:

127.0.0.1:6379> ZRANGEBYSCORE delay-queue -inf 1520985599
(empty list or set)
127.0.0.1:6379> ZRANGEBYSCORE delay-queue -inf 1520985600 WITHSCORES
1) "publish article"
2) "1520985600"
127.0.0.1:6379> ZRANGEBYSCORE delay-queue -inf 1520985601 WITHSCORES
1) "publish article"
2) "1520985600"

使用ZRANGEBYSCORE取得消息后,消息并没有从集合中删出。需要调用ZREM删除消息:

127.0.0.1:6379> ZREM delay-queue "publish article"

美中不足的是,消费者组合使用ZRANGEBYSCOREZREM的过程不是原子的,当有多个消费者时会存在竞争,可能使得一条消息被消费多次。此时需要使用Lua脚本保证消费操作的原子性:

local message = redis.call('ZRANGEBYSCORE', KEYS[1], '-inf', ARGV[1], 'WITHSCORES', 'LIMIT', 0, 1);
if #message > 0 then
  redis.call('ZREM', KEYS[1], message[1]);
  return message;
else
  return {};
end

相关文章

  • 通过redis的有序集合[zset] 实现延迟队列

    php使用redis的有序集合zset实现延迟队列 我们通过redis的有序集合zset来实现简单的延迟队列,将消...

  • Laravel源码分析 - Redis延迟队列(一)

    延迟队列,首先它是一个队列。然后其任务可以延迟被执行。实现队列,以及延迟队列的方式有很多种,基于Redis的方式也...

  • Delayer 基于 Redis 的延迟消息队列中间件

    Delayer 基于 Redis 的延迟消息队列中间件,采用 Golang 开发。 参考 有赞延迟队列设计 中的部...

  • Redis延迟队列

    不同的微服务之间做异步通迅时通常会使用Kafka,它非常适用于对消费次序或时间没有强一致性需要的场景。如果消息需要...

  • Redis 延迟任务队列

    使用 Redis 的列表结构可以实现执行一种任务的FIFO队列,也可以实现通过调用不同回调函数的来执行多重不同的任...

  • Redis 延迟任务队列

    背景 在业务发展过程中,会出现一些需要延时处理的场景,比如: a.订单下单之后超过30分钟用户未支付,需要取消订单...

  • Redis实现延迟消息队列

    消息队列是应用中常用的一个技术点,通常我们可以借助消息队列中间件来实现,但是并不是所有的情况下,都需要使用到MQ。...

  • [Delayq] golang延时队列

    DelayQ 项目地址 基于 Redis 的延迟消息队列中间件,采用 Golang 开发,支持 PHP、Golan...

  • 你真的知道怎么实现一个延迟队列吗?

    目录 前言 延迟队列定义 应用场景 实现方案Redis zsetTimeWheel时间轮结构时间轮运行逻辑 总结 ...

  • RabbitMq 延迟队列

    一、延迟队列 延迟队列就是比普通队列多了一个延迟属性。单从字面意思,可以理解为这个队列是延迟的,但我们普遍默认的,...

网友评论

    本文标题:Redis延迟队列

    本文链接:https://www.haomeiwen.com/subject/rcaaiftx.html