每日分享最新,最流行的軟件開(kāi)發(fā)知識(shí)與最新行業(yè)趨勢(shì),希望大家能夠一鍵三連,多多支持,跪求關(guān)注,點(diǎn)贊,留言。
如何使用 Apache Kafka 實(shí)現(xiàn)請(qǐng)求-響應(yīng)消息交換模式,優(yōu)缺點(diǎn),以及與 CQRS 和事件溯源的比較。
如何與 Apache Kafka 進(jìn)行請(qǐng)求-響應(yīng)通信?這是我經(jīng)常收到的最常見(jiàn)的問(wèn)題之一。這篇博文探討了何時(shí)(不)使用這種消息交換模式、同步和異步通信之間的區(qū)別、與 CQRS 和事件溯源相比的優(yōu)缺點(diǎn),以及如何在數(shù)據(jù)流基礎(chǔ)架構(gòu)中實(shí)現(xiàn)請(qǐng)求-響應(yīng)。
Apache Kafka 數(shù)據(jù)流中的消息隊(duì)列模式
在我開(kāi)始這篇文章之前,我想讓你知道這個(gè)內(nèi)容是關(guān)于“JMS、消息隊(duì)列和 Apache Kafka”的博客系列的一部分:
- JMS 消息代理與 Apache Kafka 數(shù)據(jù)流的10 個(gè)比較標(biāo)準(zhǔn)
- 通過(guò)Apache Kafka 中的死信隊(duì)列 (DQL)進(jìn)行錯(cuò)誤處理的替代方案
- 這篇文章——使用 Apache Kafka實(shí)現(xiàn)請(qǐng)求-回復(fù)模式
- 即將推出——用于選擇正確消息系統(tǒng)的決策樹(shù)(JMS 與 Apache Kafka)
- 即將推出——從 JMS 消息代理到 Apache Kafka:集成、遷移和/或替換
我會(huì)盡快在此處鏈接其他帖子。
什么是請(qǐng)求-響應(yīng)(Request-reply)消息交換模式?
請(qǐng)求-響應(yīng)(有時(shí)稱為請(qǐng)求-答復(fù))是計(jì)算機(jī)在網(wǎng)絡(luò)中用于相互通信的主要方法之一。
第一個(gè)應(yīng)用程序發(fā)送一些數(shù)據(jù)的請(qǐng)求。第二個(gè)應(yīng)用程序響應(yīng)請(qǐng)求。它是一種消息交換模式,其中請(qǐng)求者向回復(fù)者系統(tǒng)發(fā)送請(qǐng)求消息,回復(fù)者系統(tǒng)接收并處理請(qǐng)求,最終返回消息作為響應(yīng)。
請(qǐng)求-回復(fù)效率低下,并且根據(jù)用例可能會(huì)遭受很多延遲。HTTP 或更好的 gRPC 適用于某些用例。請(qǐng)求-回復(fù) 被 CQRS(命令和查詢責(zé)任分離)模式“替換”為流數(shù)據(jù)的 Kafka。CQRS 在 JMS API 中是不可能的,因?yàn)?JMS 不提供狀態(tài)功能并且缺乏事件溯源功能。讓我們更深入地研究這些陳述。
請(qǐng)求-響應(yīng) (HTTP) 與數(shù)據(jù)流 (Kafka)
在討論同步和異步通信之前,讓我們探討一下請(qǐng)求-響應(yīng)和數(shù)據(jù)流背后的概念。傳統(tǒng)上,這是兩種不同的范式:
請(qǐng)求-響應(yīng) (HTTP):
- 通常是同步的
- 點(diǎn)對(duì)點(diǎn)
- 高延遲(與數(shù)據(jù)流相比)
- 預(yù)定義 API
- 連續(xù)加工
- 通常是異步的
- 事件驅(qū)動(dòng)
- 低延遲
- 通用事件
大多數(shù)架構(gòu)需要點(diǎn)對(duì)點(diǎn)通信(例如,服務(wù)器和移動(dòng)應(yīng)用程序之間)的請(qǐng)求-響應(yīng)和連續(xù)數(shù)據(jù)處理的數(shù)據(jù)流。考慮到這一點(diǎn),讓我們看看 HTTP 與 Kafka 一起使用的用例。
同步與異步通信
請(qǐng)求-響應(yīng)消息交換模式通常是純粹同步實(shí)現(xiàn)的。然而,請(qǐng)求-響應(yīng)也可以異步實(shí)現(xiàn),響應(yīng)在某個(gè)未知的稍后時(shí)間返回。
讓我們看一下最流行的消息交換示例:REST、消息隊(duì)列和數(shù)據(jù)流。
同步 Restful API (HTTP)
Web 服務(wù)是應(yīng)用程序開(kāi)發(fā)和企業(yè)應(yīng)用程序集成中同步通信背后的主要技術(shù)。雖然多年前 WSDL 和 SOAP 占主導(dǎo)地位,但REST/HTTP 是當(dāng)今幾乎所有 Web 服務(wù)中的通信標(biāo)準(zhǔn)。
我不會(huì)在這篇文章中討論“HTTP 與 REST”的爭(zhēng)論。簡(jiǎn)而言之,REST(Representational state transfer)已被整個(gè)軟件行業(yè)所采用,并且是一套被廣泛接受的用于創(chuàng)建無(wú)狀態(tài)、可靠的 Web API 的指南。遵循 REST 約束的 Web API 被非正式地描述為 RESTful。RESTful Web API 通常松散地基于 HTTP 方法。
通過(guò) HTTP 進(jìn)行的同步 Web 服務(wù)調(diào)用保持連接打開(kāi)并等待響應(yīng)傳遞或超時(shí)期限到期。
HTTP Web 服務(wù)的延遲比較高。使用 HTTP 時(shí),它需要為每個(gè)請(qǐng)求-響應(yīng)迭代設(shè)置和斷開(kāi) TCP 連接。需要明確的是:對(duì)于許多用例來(lái)說(shuō),延遲仍然足夠好。
另一個(gè)可能的缺點(diǎn)是 HTTP 請(qǐng)求可能會(huì)阻塞等待隊(duì)列頭請(qǐng)求被處理,并且如果有太多未完成的 HTTP 請(qǐng)求,可能需要在服務(wù)器上設(shè)置 HTTP 斷路器。
異步消息隊(duì)列(IBM MQ、RabbitMQ)
消息隊(duì)列范式是發(fā)布者/訂閱者設(shè)計(jì)模式的兄弟,通常是更廣泛的面向消息的中間件系統(tǒng)的一部分。大多數(shù)消息傳遞系統(tǒng)在其 API 中同時(shí)支持發(fā)布者/訂閱者和消息隊(duì)列模型,例如 JAVA 消息服務(wù) (JMS)。如果您不熟悉此討論,請(qǐng)閱讀“ JMS 消息隊(duì)列與 Apache Kafka ”一文。
生產(chǎn)者和消費(fèi)者相互解耦,異步通信。消息隊(duì)列存儲(chǔ)事件,直到它們被成功消費(fèi)。
大多數(shù)消息隊(duì)列中間件產(chǎn)品都提供了內(nèi)置的請(qǐng)求-響應(yīng) API。它的通信是異步的。該實(shí)現(xiàn)使用相關(guān) ID。
請(qǐng)求-響應(yīng) API(例如,在 JMS 中)通過(guò)從請(qǐng)求中獲取回復(fù)端點(diǎn)來(lái)創(chuàng)建一個(gè)臨時(shí)隊(duì)列或主題,該隊(duì)列或主題在請(qǐng)求中被引用以供消費(fèi)者使用。ID 用于將請(qǐng)求與單個(gè)請(qǐng)求者分開(kāi)。這些隊(duì)列或主題也僅在請(qǐng)求者與回復(fù)會(huì)話處于活動(dòng)狀態(tài)時(shí)可用。
這種帶有臨時(shí)隊(duì)列或主題的實(shí)現(xiàn)在 Kafka 中沒(méi)有意義。我實(shí)際上已經(jīng)看到企業(yè)試圖這樣做。卡夫卡不是那樣工作的。結(jié)果是 Kafka 集群中有太多的分區(qū)和主題。結(jié)果是可擴(kuò)展性和性能問(wèn)題。
異步數(shù)據(jù)流 (Apache Kafka)
數(shù)據(jù)流持續(xù)處理來(lái)自數(shù)據(jù)源的攝取事件。此類數(shù)據(jù)應(yīng)使用流處理技術(shù)進(jìn)行增量處理,而無(wú)需訪問(wèn)所有數(shù)據(jù)。
異步通信范式類似于消息隊(duì)列。與消息隊(duì)列相反,數(shù)據(jù)流提供了事件的長(zhǎng)期存儲(chǔ)和歷史信息的可重放性。結(jié)果是生產(chǎn)者和消費(fèi)者之間真正的脫鉤。在大多數(shù) Apache Kafka 部署中,具有非常不同的通信范式和延遲能力的多個(gè)生產(chǎn)者和消費(fèi)者發(fā)送和讀取事件。
Apache Kafka 不提供內(nèi)置的請(qǐng)求-響應(yīng) API。 正如有些人認(rèn)為的那樣,這不一定是壞事。數(shù)據(jù)流提供不同的設(shè)計(jì)模式。 這就是這篇博文的主要原因!讓我們探索消息系統(tǒng)中請(qǐng)求-響應(yīng)模式的權(quán)衡,并了解更適合數(shù)據(jù)流世界的替代方法。但是這篇文章也探討了如何使用 Kafka 實(shí)現(xiàn)異步或同步請(qǐng)求-回復(fù)。
但請(qǐng)記住:不要重復(fù)使用您關(guān)于 HTTP 和 MQ 的“遺留知識(shí)”,并嘗試使用 Apache Kafka 重新構(gòu)建相同的模式。話雖如此,Kafka 也可以實(shí)現(xiàn)請(qǐng)求-響應(yīng)。更多關(guān)于這方面的內(nèi)容在以下部分中。
請(qǐng)求-回復(fù)與 CQRS 和事件溯源
CQRS (Command Query Responsibility Segregation)規(guī)定,每個(gè)方法要么是執(zhí)行操作的命令,要么是向調(diào)用者返回?cái)?shù)據(jù)的查詢,但不能同時(shí)是兩者。服務(wù)變得真正相互分離。
Martin Fowler 有一個(gè)很好的 CQRS 圖表。
事件溯源是一種架構(gòu)模式,其中實(shí)體不使用直接序列化或?qū)ο箨P(guān)系映射來(lái)跟蹤其內(nèi)部狀態(tài),而是通過(guò)讀取事件并將其提交到事件存儲(chǔ)。
當(dāng)事件溯源與 CQRS 和域驅(qū)動(dòng)設(shè)計(jì)相結(jié)合時(shí),聚合根負(fù)責(zé)驗(yàn)證和應(yīng)用命令(通常通過(guò)從命令處理程序調(diào)用它們的實(shí)例方法),然后發(fā)布事件。
使用 CQRS,狀態(tài)會(huì)根據(jù)每個(gè)相關(guān)的事件消息進(jìn)行更新。因此,狀態(tài)總是已知的。查詢存儲(chǔ)在物化視圖(例如,Kafka Streams 中的 KTable)中的狀態(tài)是有效的。對(duì)于請(qǐng)求響應(yīng),服務(wù)器必須計(jì)算或確定每個(gè)請(qǐng)求的狀態(tài)。使用 CQRS,它只計(jì)算/更新一次,而不管相關(guān)發(fā)生時(shí)的狀態(tài)查詢數(shù)量如何。
這些原則完全適合數(shù)據(jù)流世界。Apache Kafka 是一種分布式存儲(chǔ),可將傳入事件附加到不可變提交日志中。開(kāi)箱即用的 Kafka 基礎(chǔ)設(shè)施中內(nèi)置了真正的事件解耦和可重放性。大多數(shù)具有領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的現(xiàn)代微服務(wù)架構(gòu)都是使用 Apache Kafka 構(gòu)建的,而不是 REST 或 MQ。
如果不需要,不要在 Kafka 中使用 Request-Response!
如果您構(gòu)建現(xiàn)代企業(yè)架構(gòu)和新應(yīng)用程序,請(qǐng)應(yīng)用最適合該技術(shù)的自然設(shè)計(jì)模式。請(qǐng)記住:數(shù)據(jù)流是一種不同于 Web 服務(wù)和消息隊(duì)列的技術(shù)!帶有事件溯源的 CQRS是 Kafka 世界中大多數(shù)用例的最佳模式。
如果你沒(méi)有必要,不要在 Kafka 中使用請(qǐng)求-響應(yīng)概念!Kafka 是為流數(shù)據(jù)和真正解耦各種生產(chǎn)者和消費(fèi)者而構(gòu)建的。
即使對(duì)于事務(wù)性工作負(fù)載也是如此。事務(wù)不需要同步通信。Kafka API 支持關(guān)鍵任務(wù)事務(wù)(盡管它本質(zhì)上是異步的和分布式的)。考慮進(jìn)行銀行付款。它從不是同步的,而是一個(gè)復(fù)雜的業(yè)務(wù)流程,在組織內(nèi)部和跨組織中包含許多獨(dú)立事件。
Apache Kafka 的同步與異步請(qǐng)求響應(yīng)
在我解釋過(guò)請(qǐng)求-響應(yīng)不應(yīng)該是構(gòu)建新的 Kafka 應(yīng)用程序時(shí)的第一個(gè)想法之后,這并不意味著它是不可能的。有時(shí),它是解決問(wèn)題的更好、更簡(jiǎn)單或更快的方法。因此,讓我們看一下使用 Kafka 實(shí)現(xiàn)同步和異步請(qǐng)求-響應(yīng)的示例。
請(qǐng)求-回復(fù)模式可以用 Kafka 來(lái)實(shí)現(xiàn)。但不一樣。嘗試像在 JMS 消息代理中那樣做(帶有臨時(shí)隊(duì)列等)最終會(huì)殺死 Kafka 集群(因?yàn)樗墓ぷ鞣绞讲煌1M管如此,使用的概念與 JMS API 中的概念相同,例如相關(guān) ID。
Apache Kafka 的異步請(qǐng)求-響應(yīng)
Spring 項(xiàng)目及其Kafka Spring Boot Kafka 模板庫(kù)有一個(gè)很好的使用 Kafka 構(gòu)建的異步請(qǐng)求-回復(fù)模式的示例。查看“ org.springframework.kafka.requestreply.ReplyingKafkaTemplate ”。它使用 Kafka API 輕松創(chuàng)建請(qǐng)求/回復(fù)應(yīng)用程序。該示例很有趣,因?yàn)樗鼘?shí)現(xiàn)了異步請(qǐng)求/回復(fù),如果您使用例如 JMS API,則編寫(xiě)起來(lái)會(huì)更復(fù)雜)。
Spring 的優(yōu)點(diǎn)在于 易于使用的模板和方法簽名的可用性。該框架允許使用沒(méi)有自定義代碼的設(shè)計(jì)模式來(lái)實(shí)現(xiàn)它們。例如,以下是使用 Kafka 進(jìn)行請(qǐng)求-回復(fù)的兩種 Java 方法:
爪哇1RequestReplyFuture < K , V , R > sendAndReceive ( ProducerRecord < K , V > 記錄); 2RequestReplyFuture < K , V , R > sendAndReceive ( ProducerRecord < K , V > record , Duration replyTimeout );
結(jié)果是ListenableFuture異步填充的結(jié)果(或異常,超時(shí))。結(jié)果還有一個(gè)sendFuture屬性,它是調(diào)用的結(jié)果KafkaTemplate.send()。您可以使用這個(gè)未來(lái)來(lái)確定發(fā)送操作的結(jié)果。
Apache Kafka 的同步請(qǐng)求-響應(yīng)
另一篇優(yōu)秀的 DZone 文章討論了使用 Spring Kafka模板的同步請(qǐng)求/回復(fù)。該示例顯示了一個(gè)Kafka 服務(wù),它通過(guò)同步請(qǐng)求-響應(yīng)行為計(jì)算兩個(gè)數(shù)字的總和以返回結(jié)果:
Spring 自動(dòng)在生產(chǎn)者記錄中設(shè)置相關(guān) ID。@SendTo此關(guān)聯(lián) ID 由消費(fèi)者端的注釋按原樣返回。
查看DZone 帖子以獲取完整的代碼示例。
Kafka 模板的 Spring 文檔有很多關(guān)于 Kafka 的請(qǐng)求/回復(fù)模式的詳細(xì)信息和代碼示例。使用 Spring,使用 Kafka 實(shí)現(xiàn)請(qǐng)求/回復(fù)模式非常簡(jiǎn)單。如果您不使用 Spring,您可以學(xué)習(xí)如何在您的框架中使用 Kafka 進(jìn)行請(qǐng)求-回復(fù)。 這就是開(kāi)源的美妙之處……
數(shù)據(jù)流和 Rest API 的結(jié)合
上面的示例展示了如何使用 Apache Kafka 實(shí)現(xiàn)請(qǐng)求-響應(yīng)模式。盡管如此,它仍然只是次優(yōu)方法,并且通常是流數(shù)據(jù)的反模式。 數(shù)據(jù) 流和請(qǐng)求響應(yīng) REST API 通常結(jié)合使用,以充分利用兩者。我寫(xiě)了一篇關(guān)于“使用 Apache Kafka 的 HTTP 和 REST API 的用例和架構(gòu)”的專門博客文章。
Apache Kafka 和 API 管理
一種非常常見(jiàn)的方法是使用 Kafka 生態(tài)系統(tǒng)大規(guī)模實(shí)時(shí)實(shí)施應(yīng)用程序,然后在頂部放置一個(gè) API 管理層以將事件作為 API 公開(kāi)給外部世界(另一個(gè)內(nèi)部業(yè)務(wù)域或 B2B 3rd 方應(yīng)用程序) )。
這是連接 SAP 數(shù)據(jù)的示例。SAP 有數(shù)十種與 Kafka 集成的選項(xiàng),包括 Kafka Connect 連接器、REST/HTTP、專有 API 或 3rd 方中間件。
無(wú)論您如何將數(shù)據(jù)獲取到流數(shù)據(jù)中心,在右側(cè),Kafka REST API 用于通過(guò) HTTP 公開(kāi)事件。API 管理解決方案在Kafka 接口之上處理安全和貨幣化/計(jì)費(fèi)要求:
在博客文章“ Apache Kafka 和 API 管理/API 網(wǎng)關(guān) – 朋友、敵人還是敵人? ”中閱讀有關(guān)此討論的更多信息。它涵蓋了 Apache Kafka 和 API 管理平臺(tái)(如 Kong、MuleSoft Anypoint 或 google 的 Apigee)之間的關(guān)系。
使用 Apache Kafka 進(jìn)行內(nèi)部和外部數(shù)據(jù)共享的流交換
在討論了 API、請(qǐng)求-響應(yīng)通信和 Kafka 之間的關(guān)系之后,讓我們來(lái)探討一下市場(chǎng)上的一個(gè)重要趨勢(shì):Data Mesh(流行語(yǔ))和用于實(shí)時(shí)數(shù)據(jù)共享的流交換(問(wèn)題解決者)。
數(shù)據(jù)網(wǎng)格是一種新的架構(gòu)范式,近來(lái)備受關(guān)注。沒(méi)有任何一種技術(shù)可以完美地構(gòu)建數(shù)據(jù)網(wǎng)格。像 Apache Kafka 這樣的開(kāi)放且可擴(kuò)展的去中心化實(shí)時(shí)平臺(tái)通常是 Data Mesh 基礎(chǔ)架構(gòu)的核心,并輔以許多其他數(shù)據(jù)平臺(tái)來(lái)解決業(yè)務(wù)問(wèn)題。
流原生數(shù)據(jù)共享而不是在中間使用請(qǐng)求-響應(yīng)和 REST API 是許多用例的自然演變:
在“使用 Kafka 和動(dòng)態(tài)數(shù)據(jù)網(wǎng)格進(jìn)行流式數(shù)據(jù)交換”一文中了解更多信息。
一起使用數(shù)據(jù)流和請(qǐng)求響應(yīng)!
大多數(shù)架構(gòu)需要點(diǎn)對(duì)點(diǎn)通信(例如,服務(wù)器和移動(dòng)應(yīng)用程序之間)的請(qǐng)求-響應(yīng)和連續(xù)數(shù)據(jù)處理的數(shù)據(jù)流。
可以使用 Apache Kafka 實(shí)現(xiàn)同步和異步請(qǐng)求-響應(yīng)通信。但是,CQRS 和事件溯源在大多數(shù)情況下是更好、更自然的數(shù)據(jù)流方法。了解不同的選項(xiàng)及其權(quán)衡,并為工作使用正確的工具(在這種情況下,是正確的設(shè)計(jì)模式)。