【问题标题】:Asynchronous Message-Passing and Microservices异步消息传递和微服务
【发布时间】:2023-08-14 09:58:01
【问题描述】:

我正在计划开发一个基于微服务的架构应用程序,我在阅读 Ronnie Mitra 的《微服务架构》一书时决定使用 kafka 进行内部通信;马特麦克拉蒂;迈克·阿蒙森; Irakli Nadareishvili 他们说:

让微服务直接与消息代理交互(例如 RabbitMQ 等)很少是一个好主意。如果两个微服务是 通过消息队列通道直接通信,他们共享一个 数据空间(通道),我们已经详细讨论过 两个微服务共享一个数据空间的弊端。相反,我们 可以做的是将消息传递封装在一个独立的后面 可以提供消息传递能力的微服务,在一个松散的 耦合方式,连接到所有感兴趣的微服务。

我使用 Netflix Eureka 进行服务注册和发现,Zuul 作为边缘服务器和 Hystrix。 这么说,在实践中,我该如何实现那种微服务呢?如何使我的微服务独立于通信通道(在本例中为 Kafka)? 实际上我直接与频道交互,所以我的发布者/订阅者和 kafka 之间没有额外的层。

2018 年 6 月 2 日更新

更准确地说,我们有几个微服务:一个是发布关于某个主题的新闻(activemq、kafka...),另一个微服务订阅该主题并对传入的消息进行一些操作.所以我们有这些服务耦合到消息代理(到通道)......我们在我们的代码中“嵌入”了消息代理的 api,例如,如果我们想更改消息代理,我们必须更改所有使用消息代理 API 的微服务。因此,他们建议使用作为各种消息的“调度程序”的微服务(在图片中我假设是事件中心)。这样,它是唯一与通道交互的组件。

【问题讨论】:

  • 你能解释一下“如果两个微服务通过消息队列通道直接通信,它们共享一个数据空间(通道)”
  • @techagrammer 我更新了问题。

标签: java spring-boot apache-kafka microservices


【解决方案1】:

在服务架构中,使您的代码不受通信渠道限制的正确方法是对自给自足的消息进行适当建模。历史性的例子是文档模式下的 WSDL、EDIFACT、HATEOAS 等。从这个角度来看,使用 spring-boot 和 kafka 的微服务只是大型机统治世界以来相同旧事物的不同实现。

基本上,如果您将应用视为黑盒异步服务器;应用程序所做的一切都是接收事件并产生新事件。在应用程序中如何引发事件应该无关紧要。 Http 请求、jms 消息中的 xml、kafka 中的 json 等等 - 所有这些都只是传递事件的一种方式,应用程序的业务层应该只响应事件的内容。

因此,业务层通常围绕一些作为有效负载交付的自定义模型/域构建。业务层由与通信通道(kafka 侦听器、http 侦听器等)对话的侦听器/生产者层调用/触发。除了记录和执行安全性之外,您不应该在应用程序中使用通信通道逻辑。我已经看到了由原始 jms 连接或解析请求的 url 驱动的业务逻辑的不幸示例。如果您的代码中有此内容,则说明您未能正确构建代码。

但是说起来容易做起来难。有些人擅长这个级别的建模,有些人永远学不会。

除了尝试和失败,别无他法。

【讨论】:

    【解决方案2】:

    一般前言 - 如果您不需要,请不要这样做。如果您正在处理大量事件和事件备份问题等,那么引入队列系统可能是一个很大的改进。但是如果您没有遇到任何问题,您可能最好使用较低复杂性的直接服务通信。

    回到你的问题 - 听起来你想抽象你与队列的通信,因为你担心用不同的系统替换队列 - 这是正确的吗?

    在这种情况下,您可以按照您的建议进行 - 在中间开发一项新服务。这伴随着物理服务的所有包袱(包括部署、扩展等)。

    或者第二种选择是编写一个客户端库,以您想要的方式抽象队列,并允许您在需要参与队列的所有服务中重用它。这样,您不必为此目的物理部署另一个服务,但您仍然可以完全控制您的队列接口应该是什么样子,并且您有一段代码来合并更改(至少朝着队列)。如果您确定库的面向应用程序的一面足够稳定,这将起作用。

    但是,当您不确定是否需要所有复杂性时,不要在第一次迭代中执行任何这些操作。 (过度工程是一件危险的事情)

    【讨论】:

    • +1 用于在通信通道上引入包装器,它提供了在 JMS 之间切换的灵活性。
    【解决方案3】:

    您应该创建一个接口,比如说“队列”,它提供您想要从 Kafka 或 RabbitMQ 获得的所有功能,即创建差异。类似 Queue 接口的 KafkaQueue 和 RabbitMQQueue 的 impl,并注入您想要在系统中使用的正确 impl。

    如果你使用新的队列系统,你现有的代码不会改变

    在这种情况下,创建另一个微服务是额外的开销

    【讨论】: