如何与 Apache Kafka 进行请求-响应通信?这是我经常收到的最常见的问题之一。这篇博文探讨了何时(不)使用这种消息交换模式、同步和异步通信之间的区别、与 CQRS 和事件源相比的优缺点,以及如何在数据流基础设施中实现请求-响应。
Apache Kafka 数据流中的消息队列模式
在我开始这篇文章之前,我想让你知道这篇文章是关于“JMS、消息队列和 Apache Kafka”的博客系列的一部分:
JMS 消息代理与 Apache Kafka 数据流的10 个比较标准
通过Apache Kafka 中的死信队列 (DQL)进行错误处理的备选方案
这篇文章——使用 Apache Kafka实现请求-回复模式
即将到来——选择正确消息系统的决策树(JMS 与 Apache Kafka)
即将到来——从 JMS 消息代理到 Apache Kafka:集成、迁移和/或替换
我将在其他帖子可用后立即将其链接到此处。
什么是请求-响应(Request-reply)消息交换模式?
请求-响应(有时称为请求-回复)是计算机在网络中相互通信的主要方法之一。
第一个应用程序发送一些数据请求。第二个应用程序响应请求。它是一种消息交换模式,其中请求者将请求消息发送到应答器系统,应答器系统接收并处理请求,最终返回消息作为响应。
请求-回复效率低下,并且根据用例可能会出现大量延迟。HTTP 或更好的 gRPC 适用于某些用例。请求-回复 被 CQRS(命令和查询责任隔离)模式“替换”为 Kafka 用于流式数据。CQRS 不可能与 JMS API 一起使用,因为 JMS 不提供状态功能并且缺少事件溯源功能。让我们更深入地研究这些陈述。
请求-响应 (HTTP) 与数据流 (Kafka)
在讨论同步和异步通信之前,让我们探讨一下请求-响应和数据流背后的概念。传统上,这是两种不同的范例:
请求-响应(HTTP):
通常是同步的
点对点
高延迟(与数据流相比)
预定义的API
数据流(卡夫卡):
连续加工
经常是异步的
事件驱动
低延迟
通用事件
大多数架构需要点对点通信(例如,服务器和移动应用程序之间)的请求-响应和连续数据处理的数据流。考虑到这一点,让我们看一下将 HTTP 与 Kafka 一起使用的用例。
同步与异步通信
请求-响应消息交换模式通常是完全同步实现的。但是,请求-响应也可以异步实现,响应会在以后某个未知的时间返回。
让我们看一下最流行的消息交换示例:REST、消息队列和数据流。
同步 Restful API (HTTP)
Web 服务是应用程序开发和企业应用程序集成中同步通信背后的主要技术。虽然多年前 WSDL 和 SOAP 占主导地位,但REST / HTTP 是当今几乎所有 Web 服务的通信标准。
我不会在这篇文章中讨论“HTTP 与 REST”的争论。简而言之,REST(表述性状态转移)已在整个软件行业得到广泛应用,并且是一套被广泛接受的指南,用于创建无状态、可靠的 Web API。遵守 REST 约束的 Web API 被非正式地描述为 RESTful。RESTful Web API 通常松散地基于 HTTP 方法。
通过 HTTP 的同步 Web 服务调用保持连接打开并等待响应被传递或超时期限到期。
HTTP Web 服务的延迟相对较高。它需要在使用 HTTP 时为每个请求-响应迭代建立和拆除 TCP 连接。需要明确的是:延迟对于许多用例来说仍然足够好。
另一个可能的缺点是 HTTP 请求可能会阻塞等待队列请求的头部被处理,并且如果有太多未完成的 HTTP 请求,可能需要在服务器上设置 HTTP 断路器。
异步消息队列(IBM MQ、RabbitMQ)
消息队列范例是发布者/订阅者设计模式的兄弟,通常是更广泛的面向消息的中间件系统的一部分。大多数消息传递系统在其 API 中同时支持发布者/订阅者和消息队列模型,例如 Java 消息服务 (JMS)。如果您不熟悉此讨论,请阅读“ JMS Message Queue vs. Apache Kafka ”一文。
生产者和消费者相互解耦,异步通信。消息队列存储事件,直到它们被成功消费。
大多数消息队列中间件产品都提供内置的请求-响应 API。它的通信是异步的。该实现使用相关 ID。
请求-响应 API(例如,在 JMS 中)创建一个临时队列或主题,该队列或主题在请求中引用,供消费者通过从请求中获取回复端点来使用。ID 用于将请求与单个请求者分开。这些队列或主题也仅在请求者与回复会话处于活动状态时可用。
这种带有临时队列或主题的实现在 Kafka 中没有意义。我实际上已经看到企业试图这样做。卡夫卡不是那样工作的。结果是 Kafka 集群中的分区和主题过多。结果是可扩展性和性能问题。
异步数据流 (Apache Kafka)
数据流持续处理从数据源提取的事件。此类数据应使用流处理技术进行增量处理,而无需访问所有数据。
异步通信范例就像消息队列。与消息队列相反,数据流提供了事件的长期存储和历史信息的可重放性。结果是生产者和消费者之间真正脱钩。在大多数 Apache Kafka 部署中,多个具有非常不同的通信范例和延迟能力的生产者和消费者发送和读取事件。
Apache Kafka 不提供内置的请求-响应 API。 这不一定像某些人认为的那样是坏事。数据流提供了不同的设计模式。 这就是这篇博文的主要原因!让我们探索消息系统中请求-响应模式的权衡,并了解更适合数据流世界的替代方法。但这篇文章还探讨了如何使用 Kafka 实现异步或同步请求-回复。
但请记住:不要重复使用您关于 HTTP 和 MQ 的“遗留知识”并尝试使用 Apache Kafka 重新构建相同的模式。话虽如此,Kafka 也可以实现请求-响应。有关更多信息,请参见以下部分。
请求-回复与 CQRS 和事件溯源
CQRS(命令查询责任分离)指出每个方法都应该是执行操作的命令或将数据返回给调用者的查询,但不能同时是两者。服务变得真正相互分离。
Martin Fowler 有一个很好的 CQRS 图。
CQRS事件溯源是一种架构模式,其中实体不使用直接序列化或对象关系映射来跟踪其内部状态,而是通过读取事件并将事件提交到事件存储。
当事件溯源与 CQRS 和领域驱动设计相结合时,聚合根负责验证和应用命令(通常通过从命令处理程序调用它们的实例方法)然后发布事件。
使用 CQRS,状态会根据每个相关事件消息进行更新。因此,状态总是已知的。查询存储在物化视图(例如,Kafka Streams 中的 KTable)中的状态是高效的。对于请求响应,服务器必须计算或确定每个请求的状态。使用 CQRS,无论相关发生时状态查询的数量如何,它都只计算/更新一次。
这些原则非常适合数据流世界。Apache Kafka 是一种分布式存储,可将传入事件附加到不可变的提交日志中。开箱即用的 Kafka 基础架构内置了真正的事件解耦和可重放性。大多数采用领域驱动设计的现代微服务架构都是使用 Apache Kafka 构建的,而不是 REST 或 MQ。
如果不需要,请不要在 Kafka 中使用 Request-Response!
如果您构建现代企业架构和新应用程序,请应用最适合该技术的自然设计模式。请记住:数据流是一种不同于 Web 服务和消息队列的技术!具有事件源的 CQRS是 Kafka 世界中大多数用例的最佳模式。
如果您真的不需要,请不要在 Kafka 中使用请求-响应概念!Kafka 是为流数据和各种生产者和消费者之间真正的解耦而构建的。
即使对于事务性工作负载也是如此。事务不需要同步通信。Kafka API 支持关键任务事务(尽管它本质上是异步和分布式的)。考虑进行银行付款。它从来不是同步的,而是一个复杂的业务流程,在组织内部和组织之间有许多独立的事件。
Apache Kafka 的同步与异步请求-响应
在我解释了请求-响应不应该是构建新的 Kafka 应用程序时的第一个想法之后,这并不意味着它是不可能的。有时,它是解决问题的更好、更简单或更快的方法。因此,让我们看一下使用 Kafka 实现同步和异步请求-响应的示例。
请求-回复模式可以用 Kafka 实现。但不同的是。尝试像在 JMS 消息代理中那样做(使用临时队列等)最终会杀死 Kafka 集群(因为它的工作方式不同)。尽管如此,所使用的概念在底层与 JMS API 中是相同的,例如相关 ID。
使用 Apache Kafka 的异步请求-响应
Spring 项目及其Kafka Spring Boot Kafka 模板库有一个很好的使用 Kafka 构建的异步请求-回复模式的例子。查看“ org.springframework.kafka.requestreply.ReplyingKafkaTemplate ”。它使用 Kafka API 轻松创建请求/回复应用程序。该示例很有趣,因为它实现了异步请求/回复,如果您使用的是 JMS API,则编写起来会更复杂)。
Spring 的优点在于 易于使用的模板和方法签名的可用性。该框架允许使用设计模式而无需自定义代码来实现它们。例如,这里有两种用于 Kafka 请求-回复的 Java 方法:
爪哇
1个
RequestReplyFuture < K , V , R > sendAndReceive ( ProducerRecord < K , V > record );
2个
RequestReplyFuture < K , V , R > sendAndReceive ( ProducerRecord < K , V > record , Duration replyTimeout );
结果是用ListenableFuture结果异步填充的 a (或异常,超时)。结果还有一个sendFuture属性,就是调用的结果KafkaTemplate.send()。您可以使用这个未来来确定发送操作的结果。
使用 Apache Kafka 进行同步请求-响应
另一篇优秀的 DZone 文章讨论了使用 Spring Kafka模板的同步请求/回复。该示例显示了一个Kafka 服务计算两个数字的总和,同步请求-响应行为返回结果:
使用 Spring 和 Apache Kafka 同步请求响应
Spring 自动在生产者记录中设置一个关联 ID。@SendTo该相关 ID 由消费者端的注释按原样返回。
查看DZone 帖子以获取完整的代码示例。
Kafka 模板的 Spring 文档有很多关于 Kafka 请求/回复模式的细节和代码示例。使用 Spring,使用 Kafka 实现请求/回复模式非常简单。如果您不使用 Spring,您可以学习如何在您的框架中使用 Kafka 进行请求-回复。 这就是开源的魅力……
数据流和 Rest API 的结合
上面的示例展示了如何使用 Apache Kafka 实现请求-响应模式。尽管如此,它仍然只是次优方法,并且通常是流数据的反模式。
数据 流和请求-响应 REST API 通常结合使用以充分利用两者。我专门写了一篇关于“使用 Apache Kafka 的 HTTP 和 REST API 的用例和架构”的博客文章。
Apache Kafka 和 API 管理
一种非常常见的方法是使用 Kafka 生态系统实时大规模地实施应用程序,然后在顶部放置一个 API 管理层以将事件作为 API 公开给外部世界(另一个内部业务领域或 B2B 第三方应用程序) ).
下面是一个连接 SAP 数据的例子。SAP 有数十种与 Kafka 集成的选项,包括 Kafka Connect 连接器、REST/HTTP、专有 API 或第三方中间件。
无论您如何将数据放入流式数据中心,在右侧,Kafka REST API 用于通过 HTTP 公开事件。API 管理解决方案在Kafka 接口之上处理安全和货币化/计费要求:
SAP 与 Apache Kafka 集成 - R3 ERP S4 Hana Ariba Concur BAPI iDoc REST SOAP Web 服务 Java
在博客文章“ Apache Kafka 和 API 管理/API 网关——朋友、敌人还是朋友? ”中阅读有关此讨论的更多信息。它涵盖了 Apache Kafka 与 API 管理平台(如 Kong、MuleSoft Anypoint 或 Google 的 Apigee)之间的关系。
使用 Apache Kafka 进行内部和外部数据共享的 Stream Exchange
在讨论了 API、请求-响应通信和 Kafka 之间的关系之后,让我们探讨一下市场上的一个重要趋势:Data Mesh(流行语)和用于实时数据共享的流交换(问题解决者)。
Data Mesh 是一种新的架构范例,近来引起了广泛关注。没有任何一种技术可以完美地构建数据网格。像 Apache Kafka 这样开放且可扩展的去中心化实时平台通常是 Data Mesh 基础设施的核心,辅之以许多其他数据平台来解决业务问题。