在 MasstTransit 中发送、发布和请求/响应
Posted
技术标签:
【中文标题】在 MasstTransit 中发送、发布和请求/响应【英文标题】:Send, Publish and Request/Response in MasstTransit 【发布时间】:2021-11-06 09:44:31 【问题描述】:最近我尝试在我们的微服务生态系统中使用MassTransit。
根据 MassTransit 词汇和文件,我的理解是:
发布:将消息发送给 1 个或多个订阅者(Pub/Sub 模式)以传播消息。 发送:用于发送消息,如发布,发送消息,但它只用于一个接收者。与 Publish 的主要区别在于,在 Send 中,如果您的目的地没有收到消息,它将返回异常。 请求:使用请求/回复模式来发送消息并在不同的通道中获得响应,以便能够从接收方获取响应值。现在,我的问题是根据微服务的概念,遵循事件驱动的设计,我们使用 Publish 将消息(事件)传播到整个生态系统。但是这里 Send 的具体用法(用例)是什么?只是为了在接收者不存在的情况下获得异常?
我的下一个问题是,在微服务生态系统中同时使用 Publish、Send 和 Requests 是否是一种好方法?比如发布传播事件,发送命令(即发即弃),以及从目标获取响应的请求。
-- 更新 我还找到了here,Chris Patterson 清除了很多东西。这对我也有很大帮助。
【问题讨论】:
可能只是read this answer,因为我的回复差不多。 【参考方案1】:Send
和 Publish
之间的区别与意图有关。
正如您所说,Send
用于命令,Publish
用于事件。我曾经在 webMethods 作为集成引擎/服务总线上运行过一个大型企业系统,并且只使用了事件。我可以告诉你,这并不理想。如果命令和事件之间存在区别,那么对更多人来说会更有意义。无论如何,从技术上讲,需要将消息排入队列,而在那个级别上它并不重要,这就是为什么排队机制通常不会关心这种语义的原因。
用一个愚蠢的例子来说明这一点:Facebook 在我的时间轴上放置和事件,我的一个朋友在特定的日子过生日。我可以直接回复(发送消息),或者我可以在我的时间线上发布消息并希望我的朋友看到它。另一个愚蠢的例子:您向 PersonA 和 CC 4 其他人发送一封电子邮件,询问“请出示报告 ABC”。预计 PersonA 将生成报告或安排完成报告。如果同一封电子邮件作为收件人发送给所有五个人(没有抄送),那么谁来做呢?我知道,即使是Publish
,也可以有一个 1-1 的收件人/主题,但是如果另一个端点订阅了怎么办?这意味着什么?
所以发件人有责任确定Send
将消息发送到哪里,但仍可配置为订阅。对于我自己的服务总线,我使用IMessageRouteProvider 接口的实现。我曾经开发的系统中的一个实际示例是,收到的电子邮件必须将其正文转换为内容存储的图像(如果有记忆,IBM FileNet P8)。由于我不会进入的原因,系统每天晚上 20:00 停止并在早上 6:00 重新启动。这导致通常有大约 8000 封电子邮件需要转换。转换端点将在大约 2 秒内处理一次转换,但这仍需要一段时间才能完成。同时,Web 前端人员可以请求 PDF 文件转换为分页 TIFF 文件。现在,这些都排在队列的末尾,他们必须等待几个小时才能回来。解决方案是使用自己的队列实现另一个转换端点,并将 Web 前端配置为发送相同的消息类型,例如ConvertDocumentCommand
到那个“优先”队列进行处理。很容易做到。现在,如果那是一个发布,我将如何进行拆分?同一事件在不同情况下会到达 2 个不同的端点?好吧,您可以为您的系统拥有另一个订阅商店,但现在您需要同时维护两者。可能还有其他答案,例如将此逻辑编码到发送位,但这是一种设计选择,需要更改编码。
在我自己的Shuttle.Esb 服务总线中,我只有Send
和Publish
。对于请求/响应,发送者和接收者都有一个收件箱,并且会向接收者发送一个请求 (Send
),然后接收者可以回复(也是一个 Send
,但使用发送者的 URI)。
【讨论】:
感谢 Eben,您的回答很好,因此您认为 Send 我们能够在发件人端负责任地保持消息传递。它还可以帮助我们管理来自发件人的消息。好主意。所以你更喜欢在你的系统中同时使用 Publish 和 Send? @Mohammad,我确实同时使用了Send
和Publish
,是的。我发送一个命令并发布一个事件,按照惯例,在类后面加上Command
或Event
以明确区分。一个事件可能有零到 N 个订阅者。事件是您的系统通知世界并且任何人都可以处理的有趣的事情。通常,一个事件也只有一个逻辑发布者;否则,当从多个逻辑发布者接收到冲突的值时,确定真实性会变得很棘手(可能有例外)。【参考方案2】:
您的问题与 MassTransit 无关。 MassTransit 实现了众所周知的消息传递模式,这些模式在Enterprise Integration Patterns等流行资源上经过深思熟虑的描述
正如 Eben 在他的回答中所写,使用何种模式的决定是由意图驱动的。每种模式的消息传递机制也存在技术差异。
发送是给commands的,你告诉其他服务做点什么。您无需等待回复(即发即弃),尽管您可能会通过其他方式(例如事件)获得操作成功或失败的确认。
它是point-to-point channel 的实现,您还可以在其中实现竞争消费者以扩展处理,但这些将是同一服务的实例。
使用 RabbitMQ 的 MassTransit 是通过将消息发布到端点交换而不是消息类型交换来完成的,因此即使其他端点可以使用该消息,也不会获得该消息。
发布 适用于events。这是一种广播类型的交付或扇出。您可能正在发布没有人收听的事件,因此您并不真正知道谁将使用它们。你也不希望得到任何回应。
它是publish-subscribe channel 的实现。
MassTransit 与 RabbitMQ 为每个发布的消息类型创建交换并将消息发布到这些交换。消费者在他们的端点交换和消息交换之间创建绑定,因此每个消费者服务(不同的应用程序)都会在它们独立的队列中获取这些。
Request-response既可以用于需要确认的命令,也可以用于查询。
它是request-reply 消息模式的实现。
MassTransit 有 nice diagrams in the docs 解释 RabbitMQ 的机制。
这些消息传递模式经常以不同的组合和变体在复杂的分布式系统中使用。
【讨论】:
非常感谢您的回复,所以我猜我们使用发送来确保只有一个接收器表现得像火一样而忘记,但只接收 1 次。这说得通。顺便说一句,非常感谢您的好书“Hands-On Domain-Driven Design with .NET Core”。我已经阅读并从中学到了很多东西。非常感谢您的知识分享以上是关于在 MasstTransit 中发送、发布和请求/响应的主要内容,如果未能解决你的问题,请参考以下文章