首页 > 解决方案 > Pub-Sub 模式和消息代理,如何确保所有订阅者完成对事件的处理

问题描述

首先,我知道有像 NATS 这样的优秀(轻量级)消息代理。如果这是一份工作,我当然会选择经过验证的解决方案,这更多是出于好奇心和理解的意愿。

假设我想构建一个像 CRM 这样的系统,并且我想将它基于微服务,以便它易于扩展并且可以适应工作负载。因为微服务应该是解耦的。进来了 pub-sub。为了使发布订阅按预期工作(发布者和订阅者的解耦),我需要一个消息传递系统。假设我想用 node.js 来实现这一点(充分意识到有很多更快的方法可以完成这项工作)。

我的“问题”或可能只是认知失败是围绕如何确保所有订阅者收到他们订阅的主题的消息?

客户端/前端向代理发送事件请求。代理可能会验证消息并将其放入预期的队列中。有 2 个微服务订阅了此队列。代理现在只是发送队列中最旧的事件以及对两个微服务的回调。

当其中一个微服务明显慢于另一个时,这不会导致问题吗?

我的意思是,只要我不想发回表明任务已由所有订阅者完成的确认消息,它就应该工作。客户端不知道事件请求涉及多少服务,因此无法跟踪它。所以需要经纪人来做。

这是否意味着,我需要将其包含在消息代理中?它会跟踪给定事件的订阅服务计算状态吗?

标签: javascriptnode.jsarchitecturemessage-queuepublish-subscribe

解决方案


经过更多的研究并在床上醒着几个小时后,我得出的结论是,如果发布者想要接收响应/确认以跟踪已发送的状态,那么让多个订阅者订阅一个主题/主题应该被认为是不好的做法请求/消息/事件。

经过更多思考,我得出的结论是,同一主题的多个订阅服务很可能永远不需要 - 至少在我的场景中,只要我正确设计服务。我能想到的唯一方案是在稍后的时间点添加某些功能,而不涉及已经部署的服务。这感觉像是对不合适的服务设计的修复。

然后我想无论如何我该如何管理它并想出了3种方法。

一、标准结构

标准的发布-订阅结构 我想不需要进一步的解释。一些方法的细节不要介意,这只是一个头脑风暴的版本,绝对不理想。显示模式就足够了。

方法 1 - 聚合器收集响应

聚合器方法 由于代理跟踪每个订阅者,它总是知道(或可以轻松计算)预期响应的数量。因此,它可以将响应消息重定向到聚合器主题,该主题在发送/发布需要响应或成功消息的消息时自动创建(想想一些客户数据的更新 - 您显然想知道消息已收到通过并成功处理)。

当然,即使只有一个响应返回,聚合器也可能总是介于两者之间。这将减少要覆盖的案件数量。聚合器基本上是某种代理。尽管如此,它仍然增加了 Broker 的复杂性。

方法 2 - 代理发布确认消息

发布确认消息 首先:不要介意右边的连接混乱。它对我来说是一个草图,但远非整洁。

正在发布的每条消息都会由 Broker 以确认消息来回答。该消息被放置在消息单独的主题堆栈中。由于 Broker 知道每个 Subject 有多少个订阅者,它可以发回一个 Publisher 应该期望多少个响应。一般来说,确认消息也有助于通知发布者他们的消息/事件/请求是否被接受(在这里考虑身份验证和授权模式)。

只要发布者始终需要响应,这将起作用。如果它没有消息可能会停留很长一段时间。超时可以解决这个问题。

方法 3 - 传输协议响应

传输协议响应 这与方法 2 非常相似,不同之处在于传输协议用于通知发布者有关已发送请求的状态和预期的潜在响应数量。

由于大多数(如果不是所有)适用于这种拓扑的协议都提供了某种方式的响应消息,并且无论如何都应该使用这些方式来验证消息是否已经成功发送,所以答案还可以包含一个有效负载,通知客户端不要仅与成功转移有关,还与预期的响应数有关。

结论

我想说聚合器方法的开销太大,它需要更多的额外代码,而不仅仅是使用传输协议或消息系统本身。聚合器很有趣,因为客户端可以完全忽略服务,因此是解耦的。

消息系统的使用对于日志记录(潜在的调试)和 Sagas 的实现(事件链)也很有趣。

笔记

我不提倡将这些方法中的任何一种作为最佳实践。我只想用我的研究结果来回答我自己的问题。


推荐阅读