为什么使用 Redis 进行队列?

我的印象是 Redis 可以成为实现排队系统的良好候选者。到目前为止,我们一直在使用具有轮询功能的 MySQL 数据库或 RabbitMQ。使用 RabbitMQ,我们遇到了很多问题 - 客户端库非常差且有缺陷,我们不想投入太多的开发人员时间来修复它们,服务器管理控制台的一些问题等。而且,至少就目前而言,我们并没有抓住毫秒或认真推动性能,因此只要系统具有智能支持队列的架构,我们就可能处于良好状态。

好吧,这就是背景。本质上,我有一个非常经典、简单的队列模型 - 多个生产者生产工作,多个消费者消费工作,并且生产者和消费者都需要能够智能扩展。事实证明这是一个天真 PUBSUB 不起作用,因为我不想 全部 订阅者消费工作,我只想 订阅者接收作品。乍一看,在我看来就像 BRPOPLPUSH 是一个智能化的设计。

我们可以使用 BRPOPLPUSH 吗?

基本设计与 BRPOPLPUSH 是你有一个工作队列和一个进度队列。当消费者收到工作时,它会自动将项目推送到进度队列中,当它完成工作时,它会自动将项目推送到进度队列中。 LREM是吧。如果客户端死亡,这可以防止工作黑洞,并使监控变得相当轻松 - 例如,除了判断是否存在大量任务之外,我们还可以判断是否存在导致消费者花费很长时间来执行任务的问题。

它确保

  • 工作被交付给一位消费者
  • 工作最终会出现在进度队列中,因此如果消费者

缺点

  • 对我来说,我发现的最好的设计实际上并没有使用,这似乎很奇怪 PUBSUB 因为这似乎是大多数关于 Redis 排队的博客文章关注的重点。所以我觉得我错过了一些明显的东西。我认为使用的唯一方法 PUBSUB 不消耗任务两次的方法是简单地推送工作已到达的通知,然后消费者可以非阻塞地 RPOPLPUSH.
  • 一次不可能请求多个工作项,这似乎是一个性能问题。对于我们的情况来说,这并不是一个大问题,但它显然表明此操作不是为高吞吐量或这种情况而设计的
  • 简而言之: 我错过了什么愚蠢的事情吗?

还添加了 node.js 标签,因为这是我主要处理的语言。考虑到 Node 的单线程和非阻塞特性,Node 可能会在实现方面提供一些简化,但此外,我使用的 Node-Redis 库和解决方案也应该或可以对其优点和缺点敏感。

有帮助吗?

解决方案

如果要在Node.js中使用redis以便在Node.js中使用redise equeue,并且您不介意使用模块,然后您可以尝试 rsmq - 节点的redis简单消息队列。在这个问题被问到时,它不可用,但今天它是一个可行的选择。

如果你想实际实现队列,你可以在你的问题中说出自己,那么你可能想要阅读RSMQ的来源,因为它只是20个代码屏幕,这确实是你所要求的。

见:

其他提示

迄今为止我想在这里记录一些困难。

如何处理重新连接逻辑?

这是一个难题,在设计和实现消息队列时特别难的问题。消息必须在消费者离线时在某处排队,因此简单的PUB-SUB不够强大,消费者需要重新连接聆听状态。 阻塞弹出是困难的状态,因为它们是一个非幂等侦听状态。聆听应该是一个幂改为的操作,但在处理与阻塞流行音乐的断开连接时,您有乐趣思考在操作成功后是否发生断开并在操作失败之前发生了差别。这不是不可逾越的,但这是不可取的。

此外,聆听操作应尽可能简单。理想情况下,它应该具有这些属性:

  • 聆听是幂等。
  • 消费者是始终聆听,并且在侦听逻辑代码之外处理了节流逻辑。 rabbitmq通过让消费者绑定它可以拥有的unched消息的数量来封装这一点。
    特别是我采用了一个糟糕的设计,重新进入一个封锁的流行乐队取决于以前的操作的成功,这是脆性和需要难以思考的。

我现在喜欢Redis Pubsub + Rpoplpush解决方案。除了工作消耗,这使得工作的通知使我们提供了一个干净的聆听解决方案。 Pubsub只负责工作通知。 Rpoplpush的原子性质负责消费,并将工作委托给恰好一个消费者。首先,与阻塞流行的流行音乐相比,这种解决方案似乎是不必要的复杂性,但现在我发现并发症根本不必要;它正在解决一个难题。

但是,这个解决方案并不完全琐碎:

  • 消费者还应该检查重新连接的工作。
  • 无论如何,消费者可能想对新工作进行投票,以获得冗余。如果民意调查实际上,应该发出警告,因为这只应该发生在Pubsub上的消费与Rpoplpush上的民意调查之间。因此,许多民意调查成功表示损坏的订阅系统。

注意,Pubsub / Rpoplpush设计也具有缩放问题。 每个消费者收到每一个消息的轻量级通知,这意味着这不必要的瓶颈。我怀疑有可能使用频道来拆分工作,但这可能是一个棘手的设计,可以很好地锻炼。

因此选择使用 RabbitMQ 而不是 Redis 的最大原因是故障场景和集群。

这篇文章确实解释得最好,所以我只提供链接:

https://aphyr.com/posts/283-jepsen-redis

Redis哨兵和最近的Redis集群无法处理许多非常基本的故障场景,这使得它成为队列的糟糕选择。

RabbitMQ 有它自己的一系列问题,但是据说它在生产中非常可靠,并且是一个很好的消息队列。

这是兔子的帖子:

https://aphyr.com/posts/315-jepsen-rabbitmq

当您查看 CAP 理论(一致性、可用性和分区处理)时,您只能选择 3 个中的 2 个。我们正在利用 RMQ 进行消息负载的 CP(一致性和分区处理),如果我们不可用,也不是世界末日。为了不丢失消息,我们使用ignore进行分区处理,以免丢失消息。由于源管理 UUID,因此可以处理重复项。

许可以下: CC-BY-SA归因
scroll top