每日分享最新,最流行的软件开发知识与最新行业趋势,希望大家能够一键三连,多多支持,跪求关注,点赞,留言。
如何使用 Apache Kafka 实现请求-响应消息交换模式,优缺点,以及与 CQRS 和事件溯源的比较。
如何与 Apache Kafka 进行请求-响应通信?这是我经常收到的最常见的问题之一。这篇博文探讨了何时(不)使用这种消息交换模式、同步和异步通信之间的区别、与 CQRS 和事件溯源相比的优缺点,以及如何在数据流基础架构中实现请求-响应。
Apache Kafka 数据流中的消息队列模式
在我开始这篇文章之前,我想让你知道这个内容是关于“JMS、消息队列和 Apache Kafka”的博客系列的一部分:
我会尽快在此处链接其他帖子。
什么是请求-响应(Request-reply)消息交换模式?
请求-响应(有时称为请求-答复)是计算机在网络中用于相互通信的主要方法之一。
第一个应用程序发送一些数据的请求。第二个应用程序响应请求。它是一种消息交换模式,其中请求者向回复者系统发送请求消息,回复者系统接收并处理请求,最终返回消息作为响应。
请求-回复效率低下,并且根据用例可能会遭受很多延迟。HTTP 或更好的 gRPC 适用于某些用例。请求-回复 被 CQRS(命令和查询责任分离)模式“替换”为流数据的 Kafka。CQRS 在 JMS API 中是不可能的,因为 JMS 不提供状态功能并且缺乏事件溯源功能。让我们更深入地研究这些陈述。
请求-响应 (HTTP) 与数据流 (Kafka)
在讨论同步和异步通信之前,让我们探讨一下请求-响应和数据流背后的概念。传统上,这是两种不同的范式:
请求-响应 (HTTP):
大多数架构需要点对点通信(例如,服务器和移动应用程序之间)的请求-响应和连续数据处理的数据流。考虑到这一点,让我们看看 HTTP 与 Kafka 一起使用的用例。
同步与异步通信
请求-响应消息交换模式通常是纯粹同步实现的。然而,请求-响应也可以异步实现,响应在某个未知的稍后时间返回。
让我们看一下最流行的消息交换示例:REST、消息队列和数据流。
同步 Restful API (HTTP)
Web 服务是应用程序开发和企业应用程序集成中同步通信背后的主要技术。虽然多年前 WSDL 和 SOAP 占主导地位,但REST/HTTP 是当今几乎所有 Web 服务中的通信标准。
我不会在这篇文章中讨论“HTTP 与 REST”的争论。简而言之,REST(Representational state transfer)已被整个软件行业所采用,并且是一套被广泛接受的用于创建无状态、可靠的 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 消息队列与 Apache Kafka ”一文。
生产者和消费者相互解耦,异步通信。消息队列存储事件,直到它们被成功消费。
大多数消息队列中间件产品都提供了内置的请求-响应 API。它的通信是异步的。该实现使用相关 ID。
请求-响应 API(例如,在 JMS 中)通过从请求中获取回复端点来创建一个临时队列或主题,该队列或主题在请求中被引用以供消费者使用。ID 用于将请求与单个请求者分开。这些队列或主题也仅在请求者与回复会话处于活动状态时可用。
这种带有临时队列或主题的实现在 Kafka 中没有意义。我实际上已经看到企业试图这样做。卡夫卡不是那样工作的。结果是 Kafka 集群中有太多的分区和主题。结果是可扩展性和性能问题。
异步数据流 (Apache Kafka)
数据流持续处理来自数据源的摄取事件。此类数据应使用流处理技术进行增量处理,而无需访问所有数据。
异步通信范式类似于消息队列。与消息队列相反,数据流提供了事件的长期存储和历史信息的可重放性。结果是生产者和消费者之间真正的脱钩。在大多数 Apache Kafka 部署中,具有非常不同的通信范式和延迟能力的多个生产者和消费者发送和读取事件。
Apache Kafka 不提供内置的请求-响应 API。 正如有些人认为的那样,这不一定是坏事。数据流提供不同的设计模式。 这就是这篇博文的主要原因!让我们探索消息系统中请求-响应模式的权衡,并了解更适合数据流世界的替代方法。但是这篇文章也探讨了如何使用 Kafka 实现异步或同步请求-回复。
但请记住:不要重复使用您关于 HTTP 和 MQ 的“遗留知识”,并尝试使用 Apache Kafka 重新构建相同的模式。话虽如此,Kafka 也可以实现请求-响应。更多关于这方面的内容在以下部分中。
请求-回复与 CQRS 和事件溯源
CQRS (Command Query Responsibility Segregation)规定,每个方法要么是执行操作的命令,要么是向调用者返回数据的查询,但不能同时是两者。服务变得真正相互分离。
Martin Fowler 有一个很好的 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 方法:
爪哇1RequestReplyFuture < K , V , R > sendAndReceive ( ProducerRecord < K , V > 记录); 2RequestReplyFuture < K , V , R > sendAndReceive ( ProducerRecord < K , V > record , Duration replyTimeout );
结果是ListenableFuture异步填充的结果(或异常,超时)。结果还有一个sendFuture属性,它是调用的结果KafkaTemplate.send()。您可以使用这个未来来确定发送操作的结果。
Apache Kafka 的同步请求-响应
另一篇优秀的 DZone 文章讨论了使用 Spring Kafka模板的同步请求/回复。该示例显示了一个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 3rd 方应用程序) )。
这是连接 SAP 数据的示例。SAP 有数十种与 Kafka 集成的选项,包括 Kafka Connect 连接器、REST/HTTP、专有 API 或 3rd 方中间件。
无论您如何将数据获取到流数据中心,在右侧,Kafka REST API 用于通过 HTTP 公开事件。API 管理解决方案在Kafka 接口之上处理安全和货币化/计费要求:
在博客文章“ Apache Kafka 和 API 管理/API 网关 – 朋友、敌人还是敌人? ”中阅读有关此讨论的更多信息。它涵盖了 Apache Kafka 和 API 管理平台(如 Kong、MuleSoft Anypoint 或 google 的 Apigee)之间的关系。
使用 Apache Kafka 进行内部和外部数据共享的流交换
在讨论了 API、请求-响应通信和 Kafka 之间的关系之后,让我们来探讨一下市场上的一个重要趋势:Data Mesh(流行语)和用于实时数据共享的流交换(问题解决者)。
数据网格是一种新的架构范式,近来备受关注。没有任何一种技术可以完美地构建数据网格。像 Apache Kafka 这样的开放且可扩展的去中心化实时平台通常是 Data Mesh 基础架构的核心,并辅以许多其他数据平台来解决业务问题。
流原生数据共享而不是在中间使用请求-响应和 REST API 是许多用例的自然演变:
在“使用 Kafka 和动态数据网格进行流式数据交换”一文中了解更多信息。
一起使用数据流和请求响应!
大多数架构需要点对点通信(例如,服务器和移动应用程序之间)的请求-响应和连续数据处理的数据流。
可以使用 Apache Kafka 实现同步和异步请求-响应通信。但是,CQRS 和事件溯源在大多数情况下是更好、更自然的数据流方法。了解不同的选项及其权衡,并为工作使用正确的工具(在这种情况下,是正确的设计模式)。