目錄 (1)流派1:有Broker的暴力路由 (2)流派2:有Broker的復雜路由 (3)流派3:無Broker的通信流派 (4)總結 作者:愛釣魚的桌子哥,資深架構師 平時經常會看到很多人寫文章分析Kafka、RabbitMQ、RocketMQ等各種MQ之間的性能比較,功能比較,但是實際上從MQ消息隊列的門派上來說,這些MQ其實是分屬不同的門派的。 那么這不同的門派之間,到底有什么區(qū)別呢? (1)流派1:有Broker的暴力路由 這個流派最典型的就是Kafka了,Kafka實際上為了提升性能,簡化了MQ功能模型,僅僅提供了一些最基礎的MQ相關的功能,但是大幅度優(yōu)化和提升了吞吐量。 首先,這個流派一定是有一個Broker角色的,也就是說,Kafka需要部署一套服務器集群,每臺機器上都有一個Kafka Broker進程,這個進程就負責接收請求,存儲數據,發(fā)送數據。 Kafka的生產消費模型做的相對是比較暴力簡單的,就是簡單的數據流模型。 簡單來說,他有一個概念,叫做“Topic”,你可以往這個“Topic”里寫數據,然后讓別人從這里來消費。 這個Topic可以劃分為多個Partition,每個Partition放一臺機器上,存儲一部分數據。 在寫消息到Topic的時候,會自動把你這個消息給分發(fā)到某一個Partition上去。 然后消費消息的時候,有一個Consumer Group的概念,你部署在多臺機器上的Consumer可以組成一個Group,一個Partition只能給一個Consumer消費,一個Cosumer可以消費多個Partition,這是最最核心的一點。 通過這個模型,保證一個Topic里的每條消息,只會交給Consumer Group里的一個Consumer來消費,形成了一個Queue(隊列)的效果。 假如你想要有一個Queue的效果,也就是希望不停的往Queue里寫數據,然后多個消費者消費,每條消息就只能給一個消費者,那么通過Kafka來實現,其實就是生產者寫多個Partition,每個Partition只能給Consumer Group中的一個Consumer來消費。如下圖所示: 如果要實現Publish/Subscribe的模型呢?就是說生產者發(fā)送的每條消息,都要讓所有消費都消費到,怎么實現? 那就讓每個消費者都是一個獨立的消費組,這樣每條消息都會發(fā)送給所有的消費組,每個消費組里那唯一的一個消費者一定會消費到所有的消息。 但是除此之外,Kafka就沒有任何其他的消費功能了,就是如此簡單,所以屬于一種比較暴力直接的流派。 它就是簡單的消費模型,實現最基礎的Queue和Pub/Sub兩種消費模型,但是內核中大幅度優(yōu)化和提升了性能以及吞吐量。 所以Kafka天生適合的場景,就是大數據領域的實時數據計算的場景。 因為在大數據的場景下,通常是弱業(yè)務的場景,沒有太多復雜的業(yè)務系統(tǒng)交互,而主要是大量的數據流入Kafka,然后進行實時計算。 所以就是需要簡單的消費模型,但是必須在內核中對吞吐量和性能進行大幅度的優(yōu)化。 因此Kafka技術通常是在大數據的實時數據計算領域中使用的,比如說每秒處理幾十萬條消息,甚至每秒處理上百萬條消息。 (2)流派2:有Broker的復雜路由 第二個流派,就是RabbitMQ為代表的流派,他強調的不是說如何提升性能和吞吐量,關注的是說要提供非常強大、復雜而且完善的消息路由功能。 所以對于RabbitMQ而言,他就不是那么簡單的Topic-Partition的消費模型了。 在RabbitMQ中引入了一個非常核心的概念,叫做Exchange,這個Exchange就是負責根據復雜的業(yè)務規(guī)則把消息路由到內部的不同的Queue里去。 舉個例子,如果要實現最簡單的隊列功能,就是讓exchange往一個queue里寫數據,然后多個消費者來消費這個queue里的數據,每條消息只能給一個消費者,那么可以是類似下面的方式。 如果想要實現Pub/Sub的模型,就是一條消息要被所有的消費者給消費到,那么就可以讓每個消費者都有一個自己的Queue,然后綁定到一個Exchange上去。 接著,這個Exchange就設定把消息路由給所有的Queue即可,如下面這樣。 此時Exchange可以把每條消息都路由給所有的Queue,每個Consumer都可以從自己的Queue里拿到所有的消息。 RabbitMQ這種流派,其實最核心的是,基于Exchange這個概念,他可以做很多復雜的事情。 比如:如果你想要某個Consumer只能消費到某一類數據,那么Exchange可以把消息里比如帶“XXX”前綴的消息路由給某個Queue。或者你可以限定某個Consumer就只能消費某一部分數據。總之在這里你可以做很多的限制,設置復雜的路由規(guī)則。 但是也正是因為引入了這種復雜的消費模型,支持復雜的路由功能,導致RabbitMQ在內核以及架構設計上沒法像Kafka做的那么的輕量級、高性能、可擴展、高吞吐,所以RabbitMQ在吞吐量上要比Kafka低一個數量級。 所以這種流派的MQ,往往適合用在Java業(yè)務系統(tǒng)中,不同的業(yè)務系統(tǒng)需要進行復雜的消息路由。 比如說業(yè)務系統(tǒng)A發(fā)送了10條消息,其中3條消息是給業(yè)務系統(tǒng)B的,7條消息是給業(yè)務系統(tǒng)C的,要實現這種復雜的路由模型,就必須依靠RabbitMQ來實現。 當然,對于這種業(yè)務系統(tǒng)之間的消息流轉而言,可能不需要那么高的吞吐量,可能每秒業(yè)務系統(tǒng)之間也就轉發(fā)幾十條或者幾百條消息,那么就完全適合采用RabbitMQ來實現。 (3)流派3:無Broker的通信流派 ZeroMQ代表的是第三種MQ。說白了,他是不需要在服務器上部署的,就是一個客戶端的庫而已。 也就是說,他主要是封裝了底層的Socket網絡通訊,然后一個系統(tǒng)要發(fā)送一條消息給另外一個消息消費 。 通過ZeroMQ,本質就是底層ZeroMQ發(fā)送一條消息到另外一個系統(tǒng)上去。 所以ZeroMQ是去中心化的,不需要跟Kafka、RabbitMQ一樣在服務器上部署的。 他主要是用來進行業(yè)務系統(tǒng)之間的網絡通信的,有點類似于比如你是一個分布式系統(tǒng)架構,那么此時分布式架構中的各個子系統(tǒng)互相之間要通信,你是基于Dubbo RPC?還是Spring Cloud HTTP? 可能上述兩種你都不想要,就是要基于原始的Socket進行網絡通信,簡單的收發(fā)消息而已。 此時就可以使用ZeroMQ作為分布式系統(tǒng)之間的消息通信,如下面那樣。 (4)總結 其實現在基本上MQ主要就是這三個流派,很多小眾的MQ一般很少有人會用。 而且用MQ的場景主要就是兩大類:
所以一般業(yè)務系統(tǒng)之間通信就是會采用RabbitMQ/RocketMQ,需要復雜的消息路由功能的支撐。 大數據的實時計算場景會采用Kafka,需要簡單的消費模型,但是超高的吞吐量。 至于ZeroMQ,一般來說,少數分布式系統(tǒng)中子系統(tǒng)之間的分布式通信時會采用,作為輕量級的異步化的通信組件。 作者簡介: |
|