RabbitMQ vs Kafka,別再選錯(cuò)了?。?!
作為一名有著大量微服務(wù)系統(tǒng)處理經(jīng)驗(yàn)的軟件架構(gòu)師,我經(jīng)常遇到一個(gè)不斷重復(fù)的問題:“我應(yīng)該使用 RabbitMQ 還是 Kafka?”出于某種原因,許多開發(fā)人員認(rèn)為這些技術(shù)是可以互換的。雖然在某些情況下確實(shí)如此,但 RabbitMQ 還是 Kafka 之間存在根本上的差異。
因此,不同的場景需要不同的解決方案,選擇錯(cuò)誤的方案會(huì)嚴(yán)重影響我們的軟件開發(fā)設(shè)計(jì)以及后續(xù)維護(hù)軟件。
本文的目標(biāo)首先是介紹基本的異步消息傳遞模式。然后繼續(xù)介紹 RabbitMQ 和 Kafka 及其內(nèi)部結(jié)構(gòu)。
一、異步消息傳遞模式
異步消息傳遞是一種消息傳遞方案,其中生產(chǎn)者的消息生成與消費(fèi)者的消息處理分離。在消息傳遞系統(tǒng)中,我們通常會(huì)分為兩種主要的消息傳遞模式:隊(duì)列模式和發(fā)布/訂閱模式。
1.隊(duì)列模式
在隊(duì)列模式中,隊(duì)列暫時(shí)將生產(chǎn)者與消費(fèi)者解耦。多個(gè)生產(chǎn)者可以向同一個(gè)隊(duì)列發(fā)送消息。然后當(dāng)消費(fèi)者處理消息時(shí),消息會(huì)被鎖定然后從隊(duì)列中刪除,并且不再可用。
隊(duì)列模式通常就是一個(gè)消息只能被一個(gè)消費(fèi)者處理。
消息隊(duì)列
附帶說明一下,如果消費(fèi)者無法處理某個(gè)消息,消息平臺(tái)通常會(huì)將消息返回到隊(duì)列,以供其他消費(fèi)者使用。除了解耦之外,隊(duì)列還允許我們擴(kuò)展生產(chǎn)者和消費(fèi)者,并針對錯(cuò)誤處理提供容錯(cuò)能力。
2.發(fā)布/訂閱模式
在發(fā)布/訂閱模式中,單個(gè)消息可以由多個(gè)訂閱者同時(shí)接收和處理。
發(fā)布/訂閱
例如,此模式允許發(fā)布者通知所有訂閱者系統(tǒng)中發(fā)生了某些情況。在 RabbitMQ 中,關(guān)注工眾號(hào):碼猿技術(shù)專欄,回復(fù)關(guān)鍵詞:1111 獲取阿里內(nèi)部Java性能調(diào)優(yōu)手冊!主題是一種特定類型的 pub/sub 實(shí)現(xiàn)(確切地說是一種交換類型),但在本文中,我將主題稱為整個(gè) pub/sub 的表示。
一般來說,訂閱有兩種類型:
- 臨時(shí)訂閱,其中訂閱僅在使用者啟動(dòng)并運(yùn)行時(shí)才有效。一旦消費(fèi)者關(guān)閉,他們的訂閱和尚未處理的消息就會(huì)丟失。
- 持久訂閱,只要未顯式刪除,訂閱就會(huì)得到維護(hù)。當(dāng)消費(fèi)者關(guān)閉時(shí),消息平臺(tái)會(huì)維持訂閱,稍后可以恢復(fù)消息處理。
二、RabbitMQ
RabbitMQ 是消息代理的一種實(shí)現(xiàn) — 通常稱為服務(wù)總線。它本身支持上述兩種消息傳遞模式。消息代理的其他流行實(shí)現(xiàn)包括 ActiveMQ、ZeroMQ、Azure 服務(wù)總線和 Amazon Simple Queue Service (SQS)。所有這些實(shí)現(xiàn)都有很多共同點(diǎn),本文中描述的許多概念適用于其中的大多數(shù)。
1.Queues
RabbitMQ 支持開箱即用的經(jīng)典消息隊(duì)列。開發(fā)人員定義命名隊(duì)列,然后發(fā)布者可以將消息發(fā)送到該命名隊(duì)列。反過來,消費(fèi)者使用相同的隊(duì)列來檢索消息來處理它們。
2.Message exchanges
RabbitMQ 通過使用消息交換機(jī)來實(shí)現(xiàn) pub/sub。發(fā)布者將其消息發(fā)布到消息交換機(jī),不用知道這些消息的訂閱者是誰。
每個(gè)訂閱交換機(jī)的消費(fèi)者都會(huì)創(chuàng)建一個(gè)隊(duì)列,然后消息交換機(jī)將生成的消息排隊(duì)以供消費(fèi)者使用。它還可以根據(jù)各種路由規(guī)則過濾某些訂閱者的消息。
RabbitMQ message exchange
值得注意的是,RabbitMQ 支持臨時(shí)訂閱和持久訂閱。消費(fèi)者可以通過 RabbitMQ 的 API 決定他們想要使用的訂閱類型。
由于 RabbitMQ 的架構(gòu),我們還可以創(chuàng)建一種混合方法,其中一些訂閱者形成消費(fèi)者組,這些消費(fèi)者組以特定隊(duì)列上競爭消費(fèi)者的形式共同處理消息。通過這種方式,我們實(shí)現(xiàn)了發(fā)布/訂閱模式,同時(shí)還允許一些訂閱者擴(kuò)展以處理接收到的消息。
發(fā)布/訂閱和隊(duì)列相結(jié)合
三、Apache Kafka
Apache Kafka 是一個(gè)分布式流處理平臺(tái)。
與基于隊(duì)列和交換的 RabbitMQ 不同,Kafka 的存儲(chǔ)層是使用分區(qū)事務(wù)日志實(shí)現(xiàn)的。Kafka 還提供了 Streams API 來實(shí)時(shí)處理流,以及 Connectors API 來輕松與各種數(shù)據(jù)源集成。不過,這些超出了本文的范圍。
云服務(wù)商為 Kafka 的存儲(chǔ)層提供了替代解決方案。這些解決方案包括 Azure 事件中心,在某種程度上還包括 AWS Kinesis Data Streams。Kafka 的流處理功能還有特定于云的開源替代方案,同樣,這些也超出了本文的范圍。
1.Topics
Kafka 沒有實(shí)現(xiàn)隊(duì)列的概念。Kafka 將記錄集合存儲(chǔ)在稱為主題的類別中。
對于每個(gè)主題,Kafka 都會(huì)維護(hù)一個(gè)分區(qū)的消息日志。每個(gè)分區(qū)都是一個(gè)有序的、不可變的記錄序列,其中不斷附加消息。
Kafka 在消息到達(dá)時(shí)將其附加到這些分區(qū)。默認(rèn)情況下,它使用循環(huán)分區(qū)器在分區(qū)之間均勻地傳播消息。
生產(chǎn)者可以修改此行為以創(chuàng)建邏輯消息流。例如在多租戶應(yīng)用程序中,我們可能希望根據(jù)每條消息的租戶 ID 創(chuàng)建邏輯消息流。在物聯(lián)網(wǎng)場景中,我們可能希望將每個(gè)生產(chǎn)者的身份不斷映射到特定分區(qū)。確保來自同一邏輯流的所有消息映射到同一分區(qū),以保證它們按順序傳遞給消費(fèi)者。
Kafka producers
消費(fèi)者通過維護(hù)這些分區(qū)的偏移量(或索引)并按順序讀取它們來消費(fèi)消息。
單個(gè)消費(fèi)者可以使用多個(gè)主題,并且消費(fèi)者可以擴(kuò)展,直至與可用分區(qū)數(shù)量一致。
因此,在創(chuàng)建主題時(shí),應(yīng)仔細(xì)考慮該主題的消息傳遞的預(yù)期吞吐量。共同消費(fèi)某個(gè)主題的一組消費(fèi)者稱為消費(fèi)者組。Kafka 的 API 通常負(fù)責(zé)消費(fèi)者組中消費(fèi)者之間分區(qū)處理的平衡以及消費(fèi)者當(dāng)前分區(qū)偏移量的存儲(chǔ)。
Kafka consumers
2.使用 Kafka 實(shí)現(xiàn)消息傳遞
Kafka 的內(nèi)部實(shí)現(xiàn)其實(shí)很好地反映了 pub/sub 模式。
生產(chǎn)者可以向特定主題發(fā)送消息,多個(gè)消費(fèi)者組可以消費(fèi)同一條消息。每個(gè)消費(fèi)者組都可以單獨(dú)擴(kuò)展以處理負(fù)載。由于消費(fèi)者維護(hù)其分區(qū)偏移量,因此他們可以選擇持久訂閱(在重新啟動(dòng)時(shí)維持其偏移量)或臨時(shí)訂閱(即丟棄偏移量并在每次啟動(dòng)時(shí)從每個(gè)分區(qū)中的最新記錄重新啟動(dòng))。
Kafka 其實(shí)是不太適合隊(duì)列模式的消息傳遞。當(dāng)然我們可以創(chuàng)建一個(gè)只有一個(gè)消費(fèi)者組的主題來模擬經(jīng)典的消息隊(duì)列。但這有多個(gè)缺點(diǎn),在本文第 2 部分我們將詳細(xì)討論。
第 2 部分文章地址:https://betterprogramming.pub/rabbitmq-vs-kafka-1779b5b70c41
值得注意的是,無論消費(fèi)者是否消費(fèi)了這些消息,Kafka 都會(huì)將消息保留在分區(qū)中直至預(yù)先配置的時(shí)間段內(nèi)。這種保留意味著消費(fèi)者可以自由地重讀過去的消息。此外,開發(fā)人員還可以使用 Kafka 的存儲(chǔ)層來實(shí)現(xiàn)事件溯源和審計(jì)日志等機(jī)制。
四、最后
雖然 RabbitMQ 和 Kafka 有時(shí)可以互換,但它們的實(shí)現(xiàn)卻截然不同。因此,我們不能將它們視為同一類別工具的成員。一個(gè)是消息代理,另一個(gè)是分布式流平臺(tái)。
作為解決方案架構(gòu)師,我們應(yīng)該認(rèn)識(shí)到這些差異,并積極考慮針對給定場景應(yīng)使用哪些類型的解決方案。