RabbitMQ 和 Kafka 到底怎么選?
你知道的越多,不知道的就越多,業(yè)余的像一棵小草!
你來,我們一起精進(jìn)!你不來,我和你的競(jìng)爭對(duì)手一起精進(jìn)!
編輯:業(yè)余草
cnblogs.com/haolujun/p/9632835.html
推薦:https://www.xttblog.com/?p=5281
前言
開源社區(qū)有好多優(yōu)秀的隊(duì)列中間件,比如 RabbitMQ 和 Kafka,每個(gè)隊(duì)列都貌似有其特性,在進(jìn)行工程選擇時(shí),往往眼花繚亂,不知所措。對(duì)于 RabbitMQ 和 Kafka,到底應(yīng)該選哪個(gè)?
RabbitMQ 架構(gòu)
RabbitMQ 是一個(gè)分布式系統(tǒng),這里面有幾個(gè)抽象概念。
broker:每個(gè)節(jié)點(diǎn)運(yùn)行的服務(wù)程序,功能為維護(hù)該節(jié)點(diǎn)的隊(duì)列的增刪以及轉(zhuǎn)發(fā)隊(duì)列操作請(qǐng)求。 master queue:每個(gè)隊(duì)列都分為一個(gè)主隊(duì)列和若干個(gè)鏡像隊(duì)列。 mirror queue:鏡像隊(duì)列,作為 master queue 的備份。在 master queue 所在節(jié)點(diǎn)掛掉之后,系統(tǒng)把 mirror queue 提升為 master queue,負(fù)責(zé)處理客戶端隊(duì)列操作請(qǐng)求。注意,mirror queue 只做鏡像,設(shè)計(jì)目的不是為了承擔(dān)客戶端讀寫壓力。

如上圖所示,集群中有兩個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)上有一個(gè)broker,每個(gè)broker負(fù)責(zé)本機(jī)上隊(duì)列的維護(hù),并且borker之間可以互相通信。集群中有兩個(gè)隊(duì)列A和B,每個(gè)隊(duì)列都分為master queue和mirror queue(備份)。那么隊(duì)列上的生產(chǎn)消費(fèi)怎么實(shí)現(xiàn)的呢?
隊(duì)列消費(fèi)

如上圖有兩個(gè) consumer 消費(fèi)隊(duì)列 A,這兩個(gè) consumer 連在了集群的不同機(jī)器上。RabbitMQ 集群中的任何一個(gè)節(jié)點(diǎn)都擁有集群上所有隊(duì)列的元信息,所以連接到集群中的任何一個(gè)節(jié)點(diǎn)都可以,主要區(qū)別在于有的 consumer 連在 master queue 所在節(jié)點(diǎn),有的連在非 master queue 節(jié)點(diǎn)上。
因?yàn)?mirror queue 要和 master queue 保持一致,故需要同步機(jī)制,正因?yàn)橐恢滦缘南拗疲瑢?dǎo)致所有的讀寫操作都必須都操作在 master queue 上(想想,為啥讀也要從 master queue 中讀?和數(shù)據(jù)庫讀寫分離是不一樣的。),然后由 master 節(jié)點(diǎn)同步操作到 mirror queue 所在的節(jié)點(diǎn)。即使 consumer 連接到了非 master queue 節(jié)點(diǎn),該 consumer 的操作也會(huì)被路由到 master queue 所在的節(jié)點(diǎn)上,這樣才能進(jìn)行消費(fèi)。
隊(duì)列生產(chǎn)

原理和消費(fèi)一樣,如果連接到非 master queue 節(jié)點(diǎn),則路由過去。
所以,到這里小伙伴們就可以看到 RabbitMQ 的不足:由于 master queue 單節(jié)點(diǎn),導(dǎo)致性能瓶頸,吞吐量受限。雖然為了提高性能,內(nèi)部使用了 Erlang 這個(gè)語言實(shí)現(xiàn),但是終究擺脫不了架構(gòu)設(shè)計(jì)上的致命缺陷。
Kafka
說實(shí)話,Kafka 我覺得就是看到了 RabbitMQ 這個(gè)缺陷才設(shè)計(jì)出的一個(gè)改進(jìn)版,改進(jìn)的點(diǎn)就是:把一個(gè)隊(duì)列的單一 master 變成多個(gè) master,即一臺(tái)機(jī)器扛不住 qps,那么我就用多臺(tái)機(jī)器扛 qps,把一個(gè)隊(duì)列的流量均勻分散在多臺(tái)機(jī)器上不就可以了么?注意,多個(gè) master 之間的數(shù)據(jù)沒有交集,即一條消息要么發(fā)送到這個(gè) master queue,要么發(fā)送到另外一個(gè) master queue。
這里面的每個(gè) master queue 在 Kafka 中叫做 Partition,即一個(gè)分片。一個(gè)隊(duì)列有多個(gè)主分片,每個(gè)主分片又有若干副分片做備份,同步機(jī)制類似于 RabbitMQ。

如上圖,我們省略了不同的 queue,假設(shè)集群上只有一個(gè) queue(Kafka 中叫 Topic)。每個(gè)生產(chǎn)者隨機(jī)把消息發(fā)送到主分片上,之后主分片再同步給副分片。

隊(duì)列讀取的時(shí)候虛擬出一個(gè) Group 的概念,一個(gè) Topic 內(nèi)部的消息,只會(huì)路由到同 Group 內(nèi)的一個(gè) consumer 上,同一個(gè) Group 中的 consumer 消費(fèi)的消息是不一樣的;Group 之間共享一個(gè) Topic,看起來就是一個(gè)隊(duì)列的多個(gè)拷貝。
所以,為了達(dá)到多個(gè) Group 共享一個(gè) Topic 數(shù)據(jù),Kafka 并不會(huì)像 RabbitMQ 那樣消息消費(fèi)完畢立馬刪除,而是必須在后臺(tái)配置保存日期,即只保存最近一段時(shí)間的消息,超過這個(gè)時(shí)間的消息就會(huì)從磁盤刪除,這樣就保證了在一個(gè)時(shí)間段內(nèi), Topic 數(shù)據(jù)對(duì)所有 Group 可見(這個(gè)特性使得 Kafka 非常適合做一個(gè)公司的數(shù)據(jù)總線)。
隊(duì)列讀同樣是讀主分片,并且為了優(yōu)化性能,消費(fèi)者與主分片有一一的對(duì)應(yīng)關(guān)系,如果消費(fèi)者數(shù)目大于分片數(shù),則存在某些消費(fèi)者得不到消息。
由此可見,Kafka 絕對(duì)是為了高吞吐量設(shè)計(jì)的,比如設(shè)置分片數(shù)為 100,那么就有 100 臺(tái)機(jī)器去扛一個(gè) Topic 的流量,當(dāng)然比 RabbitMQ 的單機(jī)性能好。
總結(jié)
本文只做了 Kafka 和 RabbitMQ 的對(duì)比,但是開源隊(duì)列豈止這兩個(gè),ZeroMQ,RocketMQ,JMQ 等等,時(shí)間有限也就沒有細(xì)看,故不在本文比較范圍之內(nèi)。
所以,別再被這些五花八門的隊(duì)列迷惑了,從架構(gòu)上找出關(guān)鍵差別,并結(jié)合自己的實(shí)際需求(比如本文就只單單從吞吐量一個(gè)需求來考察)輕輕松松搞定選型。最后總結(jié)如下:
吞吐量較低:Kafka 和 RabbitMQ 都可以。 吞吐量高:Kafka。
本文內(nèi)容參考自 RabbitMQ 和 KafKa 官方文檔,所以真要搞懂一個(gè)中間件的原理最好去看官方文檔,文檔里面有詳細(xì)的設(shè)計(jì)方案,我們可以自己進(jìn)行設(shè)計(jì)方案的對(duì)比,從而找出符合自己實(shí)際情況的中間件。
