当前位置: 首页 > 网络应用技术

重新实现消息队列和延迟消息队列

时间:2023-03-08 10:36:47 网络应用技术

  当涉及到Redis时,更有可能考虑使用缓存。实际上,Redis还可以实现一些简单的消息队列用途。我们可以使用列表数据结构来实现队列。

  lpush(左推)

  存放在队列的左侧

  rpush(右推)

  存放在队列的右侧

  LPOP(左流行)

  取出队列的左侧

  RPOP(右POP)

  从队列的右侧取出

  以上四个命令可以允许列表来帮助我们实现队列或堆栈。队列的特征首先是先进的,并且堆栈的特征是提前的。

  因此,队列的实现可以使用lpush + rpop或rpush + lpop,

  堆栈的实现是LPUSH + LPOP或RPUSH + RPOP。

  首先,我们使用rpush到一个名为Notify-Queue的队列,添加五个元素,即1 2 3 4 5,这是作为生产者的消息

  现在,生产者使用RPUSH,消费者需要使用LPOP。您可以看到下图。最后的队列中没有新闻,但是流行音乐一直是空的

  当使用上面的LPOP消费消息时,您可以看到,每次流行消息时,我们都会阅读一个空信息。

  以上是手动执行命令,但是如果书面代码程序不断弹出数据(删除数据),则会导致空心查询(无用的读取)。

  客户的CPU消费量和Redis的Qps均和仍然无用的操作,这些无用的操作都可能导致其他客户对REDIS的缓慢响应做出反应。

  由于空旋转查询将使客户端的资源消耗和更高的资源消耗,因此我们可以在接收空气数据时让客户处于1S处休眠状态,然后在1秒钟后拉数据。这可以减少消费量。

  该解决方案还存在缺陷,也就是说,新闻消费的延迟有所增加。如果只有一个消费者,则延迟是1秒,也就是说,在空轮查询之后,它恰好是休眠状态,但目前有新闻。您仍然必须等到1到1。

  如果有多个消费者,因为每个消费者的睡眠时间都会被切断,它将减少一些延迟,但是有没有办法变得更好,可以延迟几乎0吗?

  REDIS的队列数据中实际上有两个命令,也就是说,阻止阅读,

  blpop(阻止左POP)

  BRPOP(阻止右POP)

  当障碍没有数据读取队列时,它将进入休眠状态。一旦新闻传来,它就会立即响应并读取数据。因此,使用BLPOP/BRPOP替换LPOP/RPOP可以解决新闻延迟的问题。

  继续加入团队3属性,6、7、8

  使用BLPOP读取队列。最后一个参数是阻止阅读的等待时间。如果没有这次超出消息,它将返回零。目前,您可以继续重复BLPOP操作。

  当客户端使用阻止读数时,如果阻塞时间太长,则该服务通常将用作免费连接,以便主动断开其连接以减少有用的连接以占据资源。目前,客户将引发例外。

  因此,请注意,当客户使用阻止时,有必要捕获异常捕获以进行相应的治疗,例如重试。

  与上面的相同,与上述相同,但是从命令行client redis-cli到Java语言,RPUSH释放了一个或多个线程。

  blpop消耗的另一个或多个线程完成的代码是:https://github.com/qiaomengnan16/redis-demo/tree/tree/min/min/redis-queue

  延迟队列是指发送新闻后的时间,然后消费者会消费而不是发送,而是可以立即阅读它,

  ZSET可以帮助我们做到这一点。首先,可以按分数对ZSET进行排序,分数可以节省时间戳,因此每次我们发布消息时,使用当前的时间戳和延迟时间戳。

  后来,当消费者通过拦截ZSET的数据取消消息时,满足当前时间的消息(即,数据的数据小于当前时间戳,分数小于当前时间戳。,说明您必须等待一会儿才能消费)。

  密钥命令ZADD(发布者),ZrangeBysCore(订阅者),ZREM(订阅者消耗数据后删除数据)

  我们使用ZADD添加了4个数据,即1、2和3秒(伪言,这实际上是一个分数),只能消耗,并且有一个可以在10秒内消费的Kafka。

  如果现在已经达到了第三秒,我们将数据的数据大于ZSET中的数据的数据大于1秒和小于3秒,因为此间隔中的数据正是我们可以消耗的。我们可以看到,我们已经取出了3个符合条件的数据。

  如果您一次只能消耗一个数据,则可以添加一个限制条件。您可以看到以下图中可以消耗的第一个数据。Redis

  同时,它与List的LPOP/和BLPOP不同(它们弹出并自动删除原始队列中的数据),

  尽管获得了数据,但如果您不使用ZREM进行删除,则该数据将由其他人读取,因为他始终存在于ZSET中,

  但是,ZREM可能首先已被其他人删除(消费),因此需要根据ZREM的回报值是否大于0来判断该代码。我们是否在此消息中夺取成功,然后在成功后进行正确的消费。

  完整代码地址:https://github.com/qiaomengnan16/redis-demo/main/redis-dlayed-queue

  在上面实现的延迟队列中,存在一个问题:当ZREM法官是否抓住此数据时,可能不会被抓住。这样,它可能不会在几轮中掌握。

  让ZrangeBysCore和ZREM进行原子操作,可以避免多线程竞争,并且浪费了无法抓住的资源。

  一些专业的队列中间零件将更加复杂,并增加操作和维护成本。例如,RabbitMQ,您需要在发送消息之前创建一个交换开关,然后创建队列。然后交换和队列具有绑定。-键可以匹配交换,最后到达队列,

  如果场景很简单,您可以使用Redis实现队列,但是应该指出的是,Redis没有专业队列的特征,也没有ACK保证。也就是说,可靠性仍然需要采用专业队列中间件的ACK和其他机制作为保证。