Redis Pub/Sub 支持竞争性消费者吗?

48

我有2个服务,它们都需要订阅同一个频道。

这2个服务是负载均衡的。每个服务运行在多个服务器上。

那么,我如何确保每个服务的只有1个实例消费该频道的消息。

Redis是否支持这一点?

谢谢

4个回答

61

发布/订阅模式不能按那种方式工作-消息会发送到所有已连接的订阅客户端。但是,您可以将其设置为通知列表更新的频道。这样,所有客户端都会收到消息,但只有一个客户端可以使用LPOP从列表中获取该项。


15
发送消息时,只需运行两个命令 - 一个RPUSH和一个PUBLISH。当客户端使用SUBSCRIBE接收消息时,让它调用列表上的LPOP。如果LPOP未返回任何内容,则表示另一个工作程序已处理该消息,因此可以将其忽略。 - Tom Clarkson
4
如果您不想更改发布者,您需要在订阅者端标记消息状态 - 类似于SETNX service1receivedmessage1 1结合EXPIRE使用应该可以解决问题 - 如果服务的另一个实例已经设置了标志,SETNX将返回0。 - Tom Clarkson
这是一个非常聪明的解决方案。因此,订阅者正在相互交流,以确保服务仅执行一次,尽管所有服务器都收到了消息。谢谢。如果Redis可以在发布/订阅内部支持竞争消费者,那就太好了。 - jordan
10
如果你想在 Redis 上使用生产者/消费者模式,你不需要使用 pub/sub。只需将生产者(LPUSH)工作推到一个列表中,然后让你的消费者(BRPOP)从该列表中取出任务(如果你希望消费者为不同类型的请求服务于多个不同的队列,则可以使用多个列表)。BRPOP会有效地阻塞直到有事件发生,并且每个事件只会发送给并唤醒一个消费者。将其视为类似于select()系统调用的高级抽象层。(BRPOP还像select()一样接受可选的超时值)。 - Jim Dennis
1
我需要使用发布/订阅模式,因为我的生产者不知道有多少个消费者存在。这只是一个通知。任何对此感兴趣的人都可以订阅它。但我的情况更加复杂。一个消费者可能会在多个服务器上启动多个实例。我需要确保每个消费者的唯一实例处理通知。 - jordan
显示剩余2条评论

38

另一种方法是使用您的服务实例中的B*POP。如果有很多客户端针对列表运行B*POP,每当您对其进行LPUSH操作时,其中一个客户端将获取数据,但仅限于一个。


5

0

我通过编写由请求ID(UUID)键入的值来临时实现了这一点。请求者在发布之前使用set写入该值,消费者将尝试删除此项,只有成功删除该项的消费者才被视为将处理请求的消费者。我还没有在大规模上测试过它,所以可能它不能满足我想要的规模。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接