一、消息隊(duì)列為什么使用
分析:一個(gè)用消息隊(duì)列的人,不知道為啥用,這就有點(diǎn)尷尬。沒有復(fù)習(xí)這點(diǎn),很容易被問蒙,然后就開始胡扯了。
回答:這個(gè)問題,咱只答三個(gè)最主要的應(yīng)用場景(不可否認(rèn)還有其他的,但是只答三個(gè)主要的),即以下六個(gè)字:解耦、異步、削峰
1.1解耦
傳統(tǒng)模式:

傳統(tǒng)模式的缺點(diǎn):
系統(tǒng)間耦合性太強(qiáng),如上圖所示,系統(tǒng)A在代碼中直接調(diào)用系統(tǒng)B和系統(tǒng)C的代碼,如果將來D系統(tǒng)接入,系統(tǒng)A還需要修改代碼,過于麻煩!
中間件模式:

中間件模式的的優(yōu)點(diǎn):
將消息寫入消息隊(duì)列,需要消息的系統(tǒng)自己從消息隊(duì)列中訂閱,從而系統(tǒng)A不需要做任何修改
1.2 異步
傳統(tǒng)模式:

傳統(tǒng)模式的缺點(diǎn):
一些非必要的業(yè)務(wù)邏輯以同步的方式運(yùn)行,太耗費(fèi)時(shí)間。
?
中間件模式:

中間件模式的的優(yōu)點(diǎn):
將消息寫入消息隊(duì)列,非必要的業(yè)務(wù)邏輯以異步的方式運(yùn)行,加快響應(yīng)速度
1.3 削峰
傳統(tǒng)模式:

傳統(tǒng)模式的缺點(diǎn):
并發(fā)量大的時(shí)候,所有的請求直接懟到數(shù)據(jù)庫,造成數(shù)據(jù)庫連接異常
?
中間件模式:

中間件模式的的優(yōu)點(diǎn):
系統(tǒng)A慢慢的按照數(shù)據(jù)庫能處理的并發(fā)量,從消息隊(duì)列中慢慢拉取消息。在生產(chǎn)中,這個(gè)短暫的高峰期積壓是允許的。
二、消息隊(duì)列的缺點(diǎn)
(1)系統(tǒng)可用性降低:你想啊,本來其他系統(tǒng)只要運(yùn)行好好的,那你的系統(tǒng)就是正常的?,F(xiàn)在你非要加個(gè)消息隊(duì)列進(jìn)去,那消息隊(duì)列掛了,你的系統(tǒng)不是呵呵了。因此,系統(tǒng)可用性降低
(2)系統(tǒng)復(fù)雜性增加:要多考慮很多方面的問題,比如一致性問題、如何保證消息不被重復(fù)消費(fèi),如何保證保證消息可靠傳輸。因此,需要考慮的東西更多,系統(tǒng)復(fù)雜性增大。
三、消息隊(duì)列為什么是高可用的
一個(gè)典型的Kafka集群中包含若干Producer(可以是web前端產(chǎn)生的Page View,或者是服務(wù)器日志,系統(tǒng)CPU、Memory等),若干broker(Kafka支持水平擴(kuò)展,一般broker數(shù)量越多,集群吞吐率越高),若干Consumer Group,以及一個(gè)Zookeeper集群。Kafka通過Zookeeper管理集群配置,選舉leader,以及在Consumer Group發(fā)生變化時(shí)進(jìn)行rebalance。Producer使用push模式將消息發(fā)布到broker,Consumer使用pull模式從broker訂閱并消費(fèi)消息。
至于rabbitMQ,也有普通集群和鏡像集群模式,自行去了解,比較簡單,兩小時(shí)即懂。要求,在回答高可用的問題時(shí),應(yīng)該能邏輯清晰的畫出自己的MQ集群架構(gòu)或清晰的敘述出來。
四、消息隊(duì)列如何保證不被重復(fù)消費(fèi)
(1)比如,你拿到這個(gè)消息做數(shù)據(jù)庫的insert操作。那就容易了,給這個(gè)消息做一個(gè)唯一主鍵,那么就算出現(xiàn)重復(fù)消費(fèi)的情況,就會(huì)導(dǎo)致主鍵沖突,避免數(shù)據(jù)庫出現(xiàn)臟數(shù)據(jù)。
(2)再比如,你拿到這個(gè)消息做redis的set的操作,那就容易了,不用解決,因?yàn)槟銦o論set幾次結(jié)果都是一樣的,set操作本來就算冪等操作。
(3)如果上面兩種情況還不行,上大招。準(zhǔn)備一個(gè)第三方介質(zhì),來做消費(fèi)記錄。以redis為例,給消息分配一個(gè)全局id,只要消費(fèi)過該消息,將<id,message>以K-V形式寫入redis。那消費(fèi)者開始消費(fèi)前,先去redis中查詢有沒消費(fèi)記錄即可。
五、消息隊(duì)列如何保證可靠性傳輸
分析:我們在使用消息隊(duì)列的過程中,應(yīng)該做到消息不能多消費(fèi),也不能少消費(fèi)。如果無法做到可靠性傳輸,可能給公司帶來千萬級(jí)別的財(cái)產(chǎn)損失。同樣的,如果可靠性傳輸在使用過程中,沒有考慮到,這不是給公司挖坑么,你可以拍拍屁股走了,公司損失的錢,誰承擔(dān)。還是那句話,認(rèn)真對(duì)待每一個(gè)項(xiàng)目,不要給公司挖坑。
回答:其實(shí)這個(gè)可靠性傳輸,每種MQ都要從三個(gè)角度來分析:生產(chǎn)者弄丟數(shù)據(jù)、消息隊(duì)列弄丟數(shù)據(jù)、消費(fèi)者弄丟數(shù)據(jù)
RabbitMQ
(1)生產(chǎn)者丟數(shù)據(jù)從生產(chǎn)者弄丟數(shù)據(jù)這個(gè)角度來看,RabbitMQ提供transaction和confirm模式來確保生產(chǎn)者不丟消息。transaction機(jī)制就是說,發(fā)送消息前,開啟事務(wù)(channel.txSelect()),然后發(fā)送消息,如果發(fā)送過程中出現(xiàn)什么異常,事物就會(huì)回滾(channel.txRollback()),如果發(fā)送成功則提交事物(channel.txCommit())。
然而缺點(diǎn)就是吞吐量下降了。因此,按照博主的經(jīng)驗(yàn),生產(chǎn)上用confirm模式的居多。一旦channel進(jìn)入confirm模式,所有在該信道上面發(fā)布的消息都將會(huì)被指派一個(gè)唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊(duì)列之后,rabbitMQ就會(huì)發(fā)送一個(gè)Ack給生產(chǎn)者(包含消息的唯一ID),這就使得生產(chǎn)者知道消息已經(jīng)正確到達(dá)目的隊(duì)列了.如果rabiitMQ沒能處理該消息,則會(huì)發(fā)送一個(gè)Nack消息給你,你可以進(jìn)行重試操作。處理Ack和Nack的代碼如下所示(說好不上代碼的,偷偷上了):

(2)消息隊(duì)列丟數(shù)據(jù)處理消息隊(duì)列丟數(shù)據(jù)的情況,一般是開啟持久化磁盤的配置。這個(gè)持久化配置可以和confirm機(jī)制配合使用,你可以在消息持久化磁盤后,再給生產(chǎn)者發(fā)送一個(gè)Ack信號(hào)。這樣,如果消息持久化磁盤之前,rabbitMQ陣亡了,那么生產(chǎn)者收不到Ack信號(hào),生產(chǎn)者會(huì)自動(dòng)重發(fā)。
那么如何持久化呢,這里順便說一下吧,其實(shí)也很容易,就下面兩步
1、將queue的持久化標(biāo)識(shí)durable設(shè)置為true,則代表是一個(gè)持久的隊(duì)列2、發(fā)送消息的時(shí)候?qū)eliveryMode=2
這樣設(shè)置以后,rabbitMQ就算掛了,重啟后也能恢復(fù)數(shù)據(jù)
(3)消費(fèi)者丟數(shù)據(jù)消費(fèi)者丟數(shù)據(jù)一般是因?yàn)椴捎昧俗詣?dòng)確認(rèn)消息模式。這種模式下,消費(fèi)者會(huì)自動(dòng)確認(rèn)收到信息。這時(shí)rahbitMQ會(huì)立即將消息刪除,這種情況下如果消費(fèi)者出現(xiàn)異常而沒能處理該消息,就會(huì)丟失該消息。至于解決方案,采用手動(dòng)確認(rèn)消息即可。
kafka
這里先引一張kafka Replication的數(shù)據(jù)流向圖Producer在發(fā)布消息到某個(gè)Partition時(shí),先通過ZooKeeper找到該P(yáng)artition的Leader,然后無論該Topic的Replication Factor為多少(也即該P(yáng)artition有多少個(gè)Replica),Producer只將該消息發(fā)送到該P(yáng)artition的Leader。Leader會(huì)將該消息寫入其本地Log。每個(gè)Follower都從Leader中pull數(shù)據(jù)。
針對(duì)上述情況,得出如下分析(1)生產(chǎn)者丟數(shù)據(jù)在kafka生產(chǎn)中,基本都有一個(gè)leader和多個(gè)follwer。follwer會(huì)去同步leader的信息。因此,為了避免生產(chǎn)者丟數(shù)據(jù),做如下兩點(diǎn)配置
第一個(gè)配置要在producer端設(shè)置acks=all。這個(gè)配置保證了,follwer同步完成后,才認(rèn)為消息發(fā)送成功。
在producer端設(shè)置retries=MAX,一旦寫入失敗,這無限重試
(2)消息隊(duì)列丟數(shù)據(jù)針對(duì)消息隊(duì)列丟數(shù)據(jù)的情況,無外乎就是,數(shù)據(jù)還沒同步,leader就掛了,這時(shí)zookpeer會(huì)將其他的follwer切換為leader,那數(shù)據(jù)就丟失了。針對(duì)這種情況,應(yīng)該做兩個(gè)配置。
replication.factor參數(shù),這個(gè)值必須大于1,即要求每個(gè)partition必須有至少2個(gè)副本
min.insync.replicas參數(shù),這個(gè)值必須大于1,這個(gè)是要求一個(gè)leader至少感知到有至少一個(gè)follower還跟自己保持聯(lián)系
這兩個(gè)配置加上上面生產(chǎn)者的配置聯(lián)合起來用,基本可確保kafka不丟數(shù)據(jù)
(3)消費(fèi)者丟數(shù)據(jù)這種情況一般是自動(dòng)提交了offset,然后你處理程序過程中掛了。kafka以為你處理好了。再強(qiáng)調(diào)一次offset是干嘛的offset:指的是kafka的topic中的每個(gè)消費(fèi)組消費(fèi)的下標(biāo)。簡單的來說就是一條消息對(duì)應(yīng)一個(gè)offset下標(biāo),每次消費(fèi)數(shù)據(jù)的時(shí)候如果提交offset,那么下次消費(fèi)就會(huì)從提交的offset加一那里開始消費(fèi)。比如一個(gè)topic中有100條數(shù)據(jù),我消費(fèi)了50條并且提交了,那么此時(shí)的kafka服務(wù)端記錄提交的offset就是49(offset從0開始),那么下次消費(fèi)的時(shí)候offset就從50開始消費(fèi)。解決方案也很簡單,改成手動(dòng)提交即可。
六、消息隊(duì)列如何保證的順序性?
分析:其實(shí)并非所有的公司都有這種業(yè)務(wù)需求,但是還是對(duì)這個(gè)問題要有所復(fù)習(xí)。
回答:針對(duì)這個(gè)問題,通過某種算法,將需要保持先后順序的消息放到同一個(gè)消息隊(duì)列中(kafka中就是partition,rabbitMq中就是queue)。然后只用一個(gè)消費(fèi)者去消費(fèi)該隊(duì)列。
有的人會(huì)問:那如果為了吞吐量,有多個(gè)消費(fèi)者去消費(fèi)怎么辦?
這個(gè)問題,沒有固定回答的套路。比如我們有一個(gè)微博的操作,發(fā)微博、寫評(píng)論、刪除微博,這三個(gè)異步操作。如果是這樣一個(gè)業(yè)務(wù)場景,那只要重試就行。比如你一個(gè)消費(fèi)者先執(zhí)行了寫評(píng)論的操作,但是這時(shí)候,微博都還沒發(fā),寫評(píng)論一定是失敗的,等一段時(shí)間。等另一個(gè)消費(fèi)者,先執(zhí)行寫評(píng)論的操作后,再執(zhí)行,就可以成功。
總之,針對(duì)這個(gè)問題,我的觀點(diǎn)是保證入隊(duì)有序就行,出隊(duì)以后的順序交給消費(fèi)者自己去保證,沒有固定套路。
十、各類MQ比較
(1)RabbitMQ
是使用Erlang編寫的一個(gè)開源的消息隊(duì)列,本身支持很多的協(xié)議:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它變的非常重量級(jí),更適合于企業(yè)級(jí)的開發(fā)。同時(shí)實(shí)現(xiàn)了一個(gè)經(jīng)紀(jì)人(Broker)構(gòu)架,這意味著消息在發(fā)送給客戶端時(shí)先在中心隊(duì)列排隊(duì)。對(duì)路由(Routing),負(fù)載均衡(Load balance)或者數(shù)據(jù)持久化都有很好的支持。
(2)Redis
是一個(gè)Key-Value的NoSQL數(shù)據(jù)庫,開發(fā)維護(hù)很活躍,雖然它是一個(gè)Key-Value數(shù)據(jù)庫存儲(chǔ)系統(tǒng),但它本身支持MQ功能,所以完全可以當(dāng)做一個(gè)輕量級(jí)的隊(duì)列服務(wù)來使用。對(duì)于RabbitMQ和Redis的入隊(duì)和出隊(duì)操作,各執(zhí)行100萬次,每10萬次記錄一次執(zhí)行時(shí)間。測試數(shù)據(jù)分為128Bytes、512Bytes、1K和10K四個(gè)不同大小的數(shù)據(jù)。實(shí)驗(yàn)表明:入隊(duì)時(shí),當(dāng)數(shù)據(jù)比較小時(shí)Redis的性能要高于RabbitMQ,而如果數(shù)據(jù)大小超過了10K,Redis則慢的無法忍受;出隊(duì)時(shí),無論數(shù)據(jù)大小,Redis都表現(xiàn)出非常好的性能,而RabbitMQ的出隊(duì)性能則遠(yuǎn)低于Redis。
(3)ZeroMQ
號(hào)稱最快的消息隊(duì)列系統(tǒng),尤其針對(duì)大吞吐量的需求場景。ZMQ能夠?qū)崿F(xiàn)RabbitMQ不擅長的高級(jí)/復(fù)雜的隊(duì)列,但是開發(fā)人員需要自己組合多種技術(shù)框架,技術(shù)上的復(fù)雜度是對(duì)這MQ能夠應(yīng)用成功的挑戰(zhàn)。ZeroMQ具有一個(gè)獨(dú)特的非中間件的模式,你不需要安裝和運(yùn)行一個(gè)消息服務(wù)器或中間件,因?yàn)槟愕膽?yīng)用程序?qū)缪萘诉@個(gè)服務(wù)角色。你只需要簡單的引用ZeroMQ程序庫,可以使用NuGet安裝,然后你就可以愉快的在應(yīng)用程序之間發(fā)送消息了。但是ZeroMQ僅提供非持久性的隊(duì)列,也就是說如果down機(jī),數(shù)據(jù)將會(huì)丟失。其中,Twitter的Storm中使用ZeroMQ作為數(shù)據(jù)流的傳輸。
(4)ActiveMQ
是Apache下的一個(gè)子項(xiàng)目。 類似于ZeroMQ,它能夠以代理人和點(diǎn)對(duì)點(diǎn)的技術(shù)實(shí)現(xiàn)隊(duì)列。同時(shí)類似于RabbitMQ,它少量代碼就可以高效地實(shí)現(xiàn)高級(jí)應(yīng)用場景。RabbitMQ、ZeroMQ、ActiveMQ均支持常用的多種語言客戶端 C++、Java、.Net,、Python、 Php、 Ruby等。
(5)Jafka/Kafka
Kafka是Apache下的一個(gè)子項(xiàng)目,是一個(gè)高性能跨語言分布式Publish/Subscribe消息隊(duì)列系統(tǒng),而Jafka是在Kafka之上孵化而來的,即Kafka的一個(gè)升級(jí)版。具有以下特性:快速持久化,可以在O(1)的系統(tǒng)開銷下進(jìn)行消息持久化;高吞吐,在一臺(tái)普通的服務(wù)器上既可以達(dá)到10W/s的吞吐速率;完全的分布式系統(tǒng),Broker、Producer、Consumer都原生自動(dòng)支持分布式,自動(dòng)實(shí)現(xiàn)復(fù)雜均衡;支持Hadoop數(shù)據(jù)并行加載,對(duì)于像Hadoop的一樣的日志數(shù)據(jù)和離線分析系統(tǒng),但又要求實(shí)時(shí)處理的限制,這是一個(gè)可行的解決方案。Kafka通過Hadoop的并行加載機(jī)制來統(tǒng)一了在線和離線的消息處理,這一點(diǎn)也是本課題所研究系統(tǒng)所看重的。Apache Kafka相對(duì)于ActiveMQ是一個(gè)非常輕量級(jí)的消息系統(tǒng),除了性能非常好之外,還是一個(gè)工作良好的分布式系統(tǒng)。
(7)開發(fā)語言對(duì)比
Kafka:Scala
rabbitmq:Erlang
zeromq:c
rocketmq:java
activemq:java
(8)支持的協(xié)議對(duì)比
Kafka:自己定義的一套...(基于TCP)
rabbitmq:AMQP
zeromq:TCP、UDP
rocketmq:自己定義的一套...
activemq:OpenWire、STOMP、REST、XMPP、AMQP
(9)消息存儲(chǔ)對(duì)比
Kafka:內(nèi)存、磁盤、數(shù)據(jù)庫。支持大量堆積。
kafka的最小存儲(chǔ)單元是分區(qū),一個(gè)topic包含多個(gè)分區(qū),kafka創(chuàng)建主題時(shí),這些分區(qū)會(huì)被分配在多個(gè)服務(wù)器上,通常一個(gè)broker一臺(tái)服務(wù)器。 分區(qū)首領(lǐng)會(huì)均勻地分布在不同的服務(wù)器上,分區(qū)副本也會(huì)均勻的分布在不同的服務(wù)器上,確保負(fù)載均衡和高可用性,當(dāng)新的broker加入集群的時(shí)候,部分副本會(huì)被移動(dòng)到新的broker上。 根據(jù)配置文件中的目錄清單,kafka會(huì)把新的分區(qū)分配給目錄清單里分區(qū)數(shù)最少的目錄。 默認(rèn)情況下,分區(qū)器使用輪詢算法把消息均衡地分布在同一個(gè)主題的不同分區(qū)中,對(duì)于發(fā)送時(shí)指定了key的情況,會(huì)根據(jù)key的hashcode取模后的值存到對(duì)應(yīng)的分區(qū)中。
rabbitmq:內(nèi)存、磁盤。支持少量堆積。
rabbitmq的消息分為持久化的消息和非持久化消息,不管是持久化的消息還是非持久化的消息都可以寫入到磁盤。 持久化的消息在到達(dá)隊(duì)列時(shí)就寫入到磁盤,并且如果可以,持久化的消息也會(huì)在內(nèi)存中保存一份備份,這樣可以提高一定的性能,當(dāng)內(nèi)存吃緊的時(shí)候會(huì)從內(nèi)存中清除。非持久化的消息一般只存在于內(nèi)存中,在內(nèi)存吃緊的時(shí)候會(huì)被換入到磁盤中,以節(jié)省內(nèi)存。
引入鏡像隊(duì)列機(jī)制,可將重要隊(duì)列“復(fù)制”到集群中的其他broker上,保證這些隊(duì)列的消息不會(huì)丟失。配置鏡像的隊(duì)列,都包含一個(gè)主節(jié)點(diǎn)master和多個(gè)從節(jié)點(diǎn)slave,如果master失效,加入時(shí)間最長的slave會(huì)被提升為新的master,除發(fā)送消息外的所有動(dòng)作都向master發(fā)送,然后由master將命令執(zhí)行結(jié)果廣播給各個(gè)slave,rabbitmq會(huì)讓master均勻地分布在不同的服務(wù)器上,而同一個(gè)隊(duì)列的slave也會(huì)均勻地分布在不同的服務(wù)器上,保證負(fù)載均衡和高可用性。
zeromq:消息發(fā)送端的內(nèi)存或者磁盤中。不支持持久化。
rocketmq:磁盤。支持大量堆積。
commitLog文件存放實(shí)際的消息數(shù)據(jù),每個(gè)commitLog上限是1G,滿了之后會(huì)自動(dòng)新建一個(gè)commitLog文件保存數(shù)據(jù)。ConsumeQueue隊(duì)列只存放offset、size、tagcode,非常小,分布在多個(gè)broker上。ConsumeQueue相當(dāng)于CommitLog的索引文件,消費(fèi)者消費(fèi)時(shí)會(huì)從consumeQueue中查找消息在commitLog中的offset,再去commitLog中查找元數(shù)據(jù)。
ConsumeQueue存儲(chǔ)格式的特性,保證了寫過程的順序?qū)懕P(寫CommitLog文件),大量數(shù)據(jù)IO都在順序?qū)懲粋€(gè)commitLog,滿1G了再寫新的。加上rocketmq是累計(jì)4K才強(qiáng)制從PageCache中刷到磁盤(緩存),所以高并發(fā)寫性能突出。
activemq:內(nèi)存、磁盤、數(shù)據(jù)庫。支持少量堆積。
(10)消息事務(wù)對(duì)比
Kafka:支持
rabbitmq:支持。 客戶端將信道設(shè)置為事務(wù)模式,只有當(dāng)消息被rabbitMq接收,事務(wù)才能提交成功,否則在捕獲異常后進(jìn)行回滾。使用事務(wù)會(huì)使得性能有所下降 zeromq:不支持 rocketmq:支持
activemq:支持
(11)負(fù)載均衡對(duì)比
Kafka:支持負(fù)載均衡。
1>一個(gè)broker通常就是一臺(tái)服務(wù)器節(jié)點(diǎn)。對(duì)于同一個(gè)Topic的不同分區(qū),Kafka會(huì)盡力將這些分區(qū)分布到不同的Broker服務(wù)器上,zookeeper保存了broker、主題和分區(qū)的元數(shù)據(jù)信息。分區(qū)首領(lǐng)會(huì)處理來自客戶端的生產(chǎn)請求,kafka分區(qū)首領(lǐng)會(huì)被分配到不同的broker服務(wù)器上,讓不同的broker服務(wù)器共同分擔(dān)任務(wù)。
每一個(gè)broker都緩存了元數(shù)據(jù)信息,客戶端可以從任意一個(gè)broker獲取元數(shù)據(jù)信息并緩存起來,根據(jù)元數(shù)據(jù)信息知道要往哪里發(fā)送請求。
2>kafka的消費(fèi)者組訂閱同一個(gè)topic,會(huì)盡可能地使得每一個(gè)消費(fèi)者分配到相同數(shù)量的分區(qū),分?jǐn)傌?fù)載。
3>當(dāng)消費(fèi)者加入或者退出消費(fèi)者組的時(shí)候,還會(huì)觸發(fā)再均衡,為每一個(gè)消費(fèi)者重新分配分區(qū),分?jǐn)傌?fù)載。
kafka的負(fù)載均衡大部分是自動(dòng)完成的,分區(qū)的創(chuàng)建也是kafka完成的,隱藏了很多細(xì)節(jié),避免了繁瑣的配置和人為疏忽造成的負(fù)載問題。
4>發(fā)送端由topic和key來決定消息發(fā)往哪個(gè)分區(qū),如果key為null,那么會(huì)使用輪詢算法將消息均衡地發(fā)送到同一個(gè)topic的不同分區(qū)中。如果key不為null,那么會(huì)根據(jù)key的hashcode取模計(jì)算出要發(fā)往的分區(qū)。
rabbitmq:對(duì)負(fù)載均衡的支持不好。
1>消息被投遞到哪個(gè)隊(duì)列是由交換器和key決定的,交換器、路由鍵、隊(duì)列都需要手動(dòng)創(chuàng)建。
rabbitmq客戶端發(fā)送消息要和broker建立連接,需要事先知道broker上有哪些交換器,有哪些隊(duì)列。通常要聲明要發(fā)送的目標(biāo)隊(duì)列,如果沒有目標(biāo)隊(duì)列,會(huì)在broker上創(chuàng)建一個(gè)隊(duì)列,如果有,就什么都不處理,接著往這個(gè)隊(duì)列發(fā)送消息。假設(shè)大部分繁重任務(wù)的隊(duì)列都創(chuàng)建在同一個(gè)broker上,那么這個(gè)broker的負(fù)載就會(huì)過大。(可以在上線前預(yù)先創(chuàng)建隊(duì)列,無需聲明要發(fā)送的隊(duì)列,但是發(fā)送時(shí)不會(huì)嘗試創(chuàng)建隊(duì)列,可能出現(xiàn)找不到隊(duì)列的問題,rabbitmq的備份交換器會(huì)把找不到隊(duì)列的消息保存到一個(gè)專門的隊(duì)列中,以便以后查詢使用)
使用鏡像隊(duì)列機(jī)制建立rabbitmq集群可以解決這個(gè)問題,形成master-slave的架構(gòu),master節(jié)點(diǎn)會(huì)均勻分布在不同的服務(wù)器上,讓每一臺(tái)服務(wù)器分?jǐn)傌?fù)載。slave節(jié)點(diǎn)只是負(fù)責(zé)轉(zhuǎn)發(fā),在master失效時(shí)會(huì)選擇加入時(shí)間最長的slave成為master。
當(dāng)新節(jié)點(diǎn)加入鏡像隊(duì)列的時(shí)候,隊(duì)列中的消息不會(huì)同步到新的slave中,除非調(diào)用同步命令,但是調(diào)用命令后,隊(duì)列會(huì)阻塞,不能在生產(chǎn)環(huán)境中調(diào)用同步命令。
2>當(dāng)rabbitmq隊(duì)列擁有多個(gè)消費(fèi)者的時(shí)候,隊(duì)列收到的消息將以輪詢的分發(fā)方式發(fā)送給消費(fèi)者。每條消息只會(huì)發(fā)送給訂閱列表里的一個(gè)消費(fèi)者,不會(huì)重復(fù)。
這種方式非常適合擴(kuò)展,而且是專門為并發(fā)程序設(shè)計(jì)的。
如果某些消費(fèi)者的任務(wù)比較繁重,那么可以設(shè)置basicQos限制信道上消費(fèi)者能保持的最大未確認(rèn)消息的數(shù)量,在達(dá)到上限時(shí),rabbitmq不再向這個(gè)消費(fèi)者發(fā)送任何消息。
3>對(duì)于rabbitmq而言,客戶端與集群建立的TCP連接不是與集群中所有的節(jié)點(diǎn)建立連接,而是挑選其中一個(gè)節(jié)點(diǎn)建立連接。
但是rabbitmq集群可以借助HAProxy、LVS技術(shù),或者在客戶端使用算法實(shí)現(xiàn)負(fù)載均衡,引入負(fù)載均衡之后,各個(gè)客戶端的連接可以分?jǐn)偟郊旱母鱾€(gè)節(jié)點(diǎn)之中。
(12)客戶端均衡算法對(duì)比
1)輪詢法。按順序返回下一個(gè)服務(wù)器的連接地址。
2)加權(quán)輪詢法。給配置高、負(fù)載低的機(jī)器配置更高的權(quán)重,讓其處理更多的請求;而配置低、負(fù)載高的機(jī)器,給其分配較低的權(quán)重,降低其系統(tǒng)負(fù)載。
3)隨機(jī)法。隨機(jī)選取一個(gè)服務(wù)器的連接地址。
4)加權(quán)隨機(jī)法。按照概率隨機(jī)選取連接地址。
5)源地址哈希法。通過哈希函數(shù)計(jì)算得到的一個(gè)數(shù)值,用該數(shù)值對(duì)服務(wù)器列表的大小進(jìn)行取模運(yùn)算。
6)最小連接數(shù)法。動(dòng)態(tài)選擇當(dāng)前連接數(shù)最少的一臺(tái)服務(wù)器的連接地址。
zeromq:去中心化,不支持負(fù)載均衡。本身只是一個(gè)多線程網(wǎng)絡(luò)庫。
rocketmq:支持負(fù)載均衡。
一個(gè)broker通常是一個(gè)服務(wù)器節(jié)點(diǎn),broker分為master和slave,master和slave存儲(chǔ)的數(shù)據(jù)一樣,slave從master同步數(shù)據(jù)。
1>nameserver與每個(gè)集群成員保持心跳,保存著Topic-Broker路由信息,同一個(gè)topic的隊(duì)列會(huì)分布在不同的服務(wù)器上。
2>發(fā)送消息通過輪詢隊(duì)列的方式發(fā)送,每個(gè)隊(duì)列接收平均的消息量。發(fā)送消息指定topic、tags、keys,無法指定投遞到哪個(gè)隊(duì)列(沒有意義,集群消費(fèi)和廣播消費(fèi)跟消息存放在哪個(gè)隊(duì)列沒有關(guān)系)。
tags選填,類似于 Gmail 為每封郵件設(shè)置的標(biāo)簽,方便服務(wù)器過濾使用。目前只支 持每個(gè)消息設(shè)置一個(gè) tag,所以也可以類比為 Notify 的 MessageType 概念。
keys選填,代表這條消息的業(yè)務(wù)關(guān)鍵詞,服務(wù)器會(huì)根據(jù) keys 創(chuàng)建哈希索引,設(shè)置后, 可以在 Console 系統(tǒng)根據(jù) Topic、Keys 來查詢消息,由于是哈希索引,請盡可能 保證 key 唯一,例如訂單號(hào),商品 Id 等。
3>rocketmq的負(fù)載均衡策略規(guī)定:Consumer數(shù)量應(yīng)該小于等于Queue數(shù)量,如果Consumer超過Queue數(shù)量,那么多余的Consumer 將不能消費(fèi)消息。這一點(diǎn)和kafka是一致的,rocketmq會(huì)盡可能地為每一個(gè)Consumer分配相同數(shù)量的隊(duì)列,分?jǐn)傌?fù)載。
activemq:支持負(fù)載均衡。可以基于zookeeper實(shí)現(xiàn)負(fù)載均衡。
(13)集群方式對(duì)比
Kafka:天然的‘Leader-Slave’無狀態(tài)集群,每臺(tái)服務(wù)器既是Master也是Slave。
分區(qū)首領(lǐng)均勻地分布在不同的kafka服務(wù)器上,分區(qū)副本也均勻地分布在不同的kafka服務(wù)器上,所以每一臺(tái)kafka服務(wù)器既含有分區(qū)首領(lǐng),同時(shí)又含有分區(qū)副本,每一臺(tái)kafka服務(wù)器是某一臺(tái)kafka服務(wù)器的Slave,同時(shí)也是某一臺(tái)kafka服務(wù)器的leader。
kafka的集群依賴于zookeeper,zookeeper支持熱擴(kuò)展,所有的broker、消費(fèi)者、分區(qū)都可以動(dòng)態(tài)加入移除,而無需關(guān)閉服務(wù),與不依靠zookeeper集群的mq相比,這是最大的優(yōu)勢。
rabbitmq:支持簡單集群,'復(fù)制'模式,對(duì)高級(jí)集群模式支持不好。
rabbitmq的每一個(gè)節(jié)點(diǎn),不管是單一節(jié)點(diǎn)系統(tǒng)或者是集群中的一部分,要么是內(nèi)存節(jié)點(diǎn),要么是磁盤節(jié)點(diǎn),集群中至少要有一個(gè)是磁盤節(jié)點(diǎn)。
在rabbitmq集群中創(chuàng)建隊(duì)列,集群只會(huì)在單個(gè)節(jié)點(diǎn)創(chuàng)建隊(duì)列進(jìn)程和完整的隊(duì)列信息(元數(shù)據(jù)、狀態(tài)、內(nèi)容),而不是在所有節(jié)點(diǎn)上創(chuàng)建。
引入鏡像隊(duì)列,可以避免單點(diǎn)故障,確保服務(wù)的可用性,但是需要人為地為某些重要的隊(duì)列配置鏡像。
zeromq:去中心化,不支持集群。
rocketmq:常用 多對(duì)'Master-Slave' 模式,開源版本需手動(dòng)切換Slave變成Master
Name Server是一個(gè)幾乎無狀態(tài)節(jié)點(diǎn),可集群部署,節(jié)點(diǎn)之間無任何信息同步。
Broker部署相對(duì)復(fù)雜,Broker分為Master與Slave,一個(gè)Master可以對(duì)應(yīng)多個(gè)Slave,但是一個(gè)Slave只能對(duì)應(yīng)一個(gè)Master,Master與Slave的對(duì)應(yīng)關(guān)系通過指定相同的BrokerName,不同的BrokerId來定義,BrokerId為0表示Master,非0表示Slave。Master也可以部署多個(gè)。每個(gè)Broker與Name Server集群中的所有節(jié)點(diǎn)建立長連接,定時(shí)注冊Topic信息到所有Name Server。
Producer與Name Server集群中的其中一個(gè)節(jié)點(diǎn)(隨機(jī)選擇)建立長連接,定期從Name Server取Topic路由信息,并向提供Topic服務(wù)的Master建立長連接,且定時(shí)向Master發(fā)送心跳。Producer完全無狀態(tài),可集群部署。
Consumer與Name Server集群中的其中一個(gè)節(jié)點(diǎn)(隨機(jī)選擇)建立長連接,定期從Name Server取Topic路由信息,并向提供Topic服務(wù)的Master、Slave建立長連接,且定時(shí)向Master、Slave發(fā)送心跳。Consumer既可以從Master訂閱消息,也可以從Slave訂閱消息,訂閱規(guī)則由Broker配置決定。
客戶端先找到NameServer,然后通過NameServer再找到 Broker。
一個(gè)topic有多個(gè)隊(duì)列,這些隊(duì)列會(huì)均勻地分布在不同的broker服務(wù)器上。rocketmq隊(duì)列的概念和kafka的分區(qū)概念是基本一致的,kafka同一個(gè)topic的分區(qū)盡可能地分布在不同的broker上,分區(qū)副本也會(huì)分布在不同的broker上。
rocketmq集群的slave會(huì)從master拉取數(shù)據(jù)備份,master分布在不同的broker上。
activemq:支持簡單集群模式,比如'主-備',對(duì)高級(jí)集群模式支持不好。
(14)管理界面對(duì)比
Kafka:一般 rabbitmq:好 zeromq:無 rocketmq:無 activemq:一般
(15)可用性對(duì)比
Kafka:非常高(分布式)
rabbitmq:高(主從)
zeromq:高。
rocketmq:非常高(分布式)
activemq:高(主從)
(16)消息重復(fù)對(duì)比
Kafka:支持at least once、at most once
rabbitmq:支持at least once、at most once
zeromq:只有重傳機(jī)制,但是沒有持久化,消息丟了重傳也沒有用。既不是at least once、也不是at most once、更不是exactly only once
rocketmq:支持at least once
activemq:支持at least once
(17)吞吐量TPS對(duì)比
Kafka:極大 Kafka按批次發(fā)送消息和消費(fèi)消息。發(fā)送端將多個(gè)小消息合并,批量發(fā)向Broker,消費(fèi)端每次取出一個(gè)批次的消息批量處理。 rabbitmq:比較大 zeromq:極大 rocketmq:大 rocketMQ接收端可以批量消費(fèi)消息,可以配置每次消費(fèi)的消息數(shù),但是發(fā)送端不是批量發(fā)送。 activemq:比較大
(18)訂閱形式和消息分發(fā)對(duì)比
Kafka:基于topic以及按照topic進(jìn)行正則匹配的發(fā)布訂閱模式。
【發(fā)送】
發(fā)送端由topic和key來決定消息發(fā)往哪個(gè)分區(qū),如果key為null,那么會(huì)使用輪詢算法將消息均衡地發(fā)送到同一個(gè)topic的不同分區(qū)中。如果key不為null,那么會(huì)根據(jù)key的hashcode取模計(jì)算出要發(fā)往的分區(qū)。
【接收】
1>consumer向群組協(xié)調(diào)器broker發(fā)送心跳來維持他們和群組的從屬關(guān)系以及他們對(duì)分區(qū)的所有權(quán)關(guān)系,所有權(quán)關(guān)系一旦被分配就不會(huì)改變除非發(fā)生再均衡(比如有一個(gè)consumer加入或者離開consumer group),consumer只會(huì)從對(duì)應(yīng)的分區(qū)讀取消息。
2>kafka限制consumer個(gè)數(shù)要少于分區(qū)個(gè)數(shù),每個(gè)消息只會(huì)被同一個(gè) Consumer Group的一個(gè)consumer消費(fèi)(非廣播)。
3>kafka的 Consumer Group訂閱同一個(gè)topic,會(huì)盡可能地使得每一個(gè)consumer分配到相同數(shù)量的分區(qū),不同 Consumer Group訂閱同一個(gè)主題相互獨(dú)立,同一個(gè)消息會(huì)被不同的 Consumer Group處理。
rabbitmq:提供了4種:direct, topic ,Headers和fanout。
【發(fā)送】
先要聲明一個(gè)隊(duì)列,這個(gè)隊(duì)列會(huì)被創(chuàng)建或者已經(jīng)被創(chuàng)建,隊(duì)列是基本存儲(chǔ)單元。
由exchange和key決定消息存儲(chǔ)在哪個(gè)隊(duì)列。
direct>發(fā)送到和bindingKey完全匹配的隊(duì)列。
topic>路由key是含有"."的字符串,會(huì)發(fā)送到含有“*”、“#”進(jìn)行模糊匹配的bingKey對(duì)應(yīng)的隊(duì)列。
fanout>與key無關(guān),會(huì)發(fā)送到所有和exchange綁定的隊(duì)列
headers>與key無關(guān),消息內(nèi)容的headers屬性(一個(gè)鍵值對(duì))和綁定鍵值對(duì)完全匹配時(shí),會(huì)發(fā)送到此隊(duì)列。此方式性能低一般不用
【接收】
rabbitmq的隊(duì)列是基本存儲(chǔ)單元,不再被分區(qū)或者分片,對(duì)于我們已經(jīng)創(chuàng)建了的隊(duì)列,消費(fèi)端要指定從哪一個(gè)隊(duì)列接收消息。
當(dāng)rabbitmq隊(duì)列擁有多個(gè)消費(fèi)者的時(shí)候,隊(duì)列收到的消息將以輪詢的分發(fā)方式發(fā)送給消費(fèi)者。每條消息只會(huì)發(fā)送給訂閱列表里的一個(gè)消費(fèi)者,不會(huì)重復(fù)。
這種方式非常適合擴(kuò)展,而且是專門為并發(fā)程序設(shè)計(jì)的。
如果某些消費(fèi)者的任務(wù)比較繁重,那么可以設(shè)置basicQos限制信道上消費(fèi)者能保持的最大未確認(rèn)消息的數(shù)量,在達(dá)到上限時(shí),rabbitmq不再向這個(gè)消費(fèi)者發(fā)送任何消息。
zeromq:點(diǎn)對(duì)點(diǎn)(p2p)
rocketmq:基于topic/messageTag以及按照消息類型、屬性進(jìn)行正則匹配的發(fā)布訂閱模式
【發(fā)送】
發(fā)送消息通過輪詢隊(duì)列的方式發(fā)送,每個(gè)隊(duì)列接收平均的消息量。發(fā)送消息指定topic、tags、keys,無法指定投遞到哪個(gè)隊(duì)列(沒有意義,集群消費(fèi)和廣播消費(fèi)跟消息存放在哪個(gè)隊(duì)列沒有關(guān)系)。
tags選填,類似于 Gmail 為每封郵件設(shè)置的標(biāo)簽,方便服務(wù)器過濾使用。目前只支 持每個(gè)消息設(shè)置一個(gè) tag,所以也可以類比為 Notify 的 MessageType 概念。
keys選填,代表這條消息的業(yè)務(wù)關(guān)鍵詞,服務(wù)器會(huì)根據(jù) keys 創(chuàng)建哈希索引,設(shè)置后, 可以在 Console 系統(tǒng)根據(jù) Topic、Keys 來查詢消息,由于是哈希索引,請盡可能 保證 key 唯一,例如訂單號(hào),商品 Id 等。
【接收】
1>廣播消費(fèi)。一條消息被多個(gè)Consumer消費(fèi),即使Consumer屬于同一個(gè)ConsumerGroup,消息也會(huì)被ConsumerGroup中的每個(gè)Consumer都消費(fèi)一次。
2>集群消費(fèi)。一個(gè) Consumer Group中的Consumer實(shí)例平均分?jǐn)傁M(fèi)消息。例如某個(gè)Topic有 9 條消息,其中一個(gè)Consumer Group有3個(gè)實(shí)例,那么每個(gè)實(shí)例只消費(fèi)其中的 3 條消息。即每一個(gè)隊(duì)列都把消息輪流分發(fā)給每個(gè)consumer。
activemq:點(diǎn)對(duì)點(diǎn)(p2p)、廣播(發(fā)布-訂閱)
點(diǎn)對(duì)點(diǎn)模式,每個(gè)消息只有1個(gè)消費(fèi)者;
發(fā)布/訂閱模式,每個(gè)消息可以有多個(gè)消費(fèi)者。
【發(fā)送】
點(diǎn)對(duì)點(diǎn)模式:先要指定一個(gè)隊(duì)列,這個(gè)隊(duì)列會(huì)被創(chuàng)建或者已經(jīng)被創(chuàng)建。
發(fā)布/訂閱模式:先要指定一個(gè)topic,這個(gè)topic會(huì)被創(chuàng)建或者已經(jīng)被創(chuàng)建。
【接收】
點(diǎn)對(duì)點(diǎn)模式:對(duì)于已經(jīng)創(chuàng)建了的隊(duì)列,消費(fèi)端要指定從哪一個(gè)隊(duì)列接收消息。
發(fā)布/訂閱模式:對(duì)于已經(jīng)創(chuàng)建了的topic,消費(fèi)端要指定訂閱哪一個(gè)topic的消息。
(19)順序消息對(duì)比
Kafka:支持。
設(shè)置生產(chǎn)者的max.in.flight.requests.per.connection為1,可以保證消息是按照發(fā)送順序?qū)懭敕?wù)器的,即使發(fā)生了重試。
kafka保證同一個(gè)分區(qū)里的消息是有序的,但是這種有序分兩種情況
1>key為null,消息逐個(gè)被寫入不同主機(jī)的分區(qū)中,但是對(duì)于每個(gè)分區(qū)依然是有序的
2>key不為null , 消息被寫入到同一個(gè)分區(qū),這個(gè)分區(qū)的消息都是有序。
rabbitmq:不支持
zeromq:不支持
rocketmq:支持
activemq:不支持
(20)消息確認(rèn)對(duì)比
Kafka:支持。
1>發(fā)送方確認(rèn)機(jī)制
ack=0,不管消息是否成功寫入分區(qū)
ack=1,消息成功寫入首領(lǐng)分區(qū)后,返回成功
ack=all,消息成功寫入所有分區(qū)后,返回成功。
2>接收方確認(rèn)機(jī)制
自動(dòng)或者手動(dòng)提交分區(qū)偏移量,早期版本的kafka偏移量是提交給Zookeeper的,這樣使得zookeeper的壓力比較大,更新版本的kafka的偏移量是提交給kafka服務(wù)器的,不再依賴于zookeeper群組,集群的性能更加穩(wěn)定。
rabbitmq:支持。
1>發(fā)送方確認(rèn)機(jī)制,消息被投遞到所有匹配的隊(duì)列后,返回成功。如果消息和隊(duì)列是可持久化的,那么在寫入磁盤后,返回成功。支持批量確認(rèn)和異步確認(rèn)。
2>接收方確認(rèn)機(jī)制,設(shè)置autoAck為false,需要顯式確認(rèn),設(shè)置autoAck為true,自動(dòng)確認(rèn)。
當(dāng)autoAck為false的時(shí)候,rabbitmq隊(duì)列會(huì)分成兩部分,一部分是等待投遞給consumer的消息,一部分是已經(jīng)投遞但是沒收到確認(rèn)的消息。如果一直沒有收到確認(rèn)信號(hào),并且consumer已經(jīng)斷開連接,rabbitmq會(huì)安排這個(gè)消息重新進(jìn)入隊(duì)列,投遞給原來的消費(fèi)者或者下一個(gè)消費(fèi)者。
未確認(rèn)的消息不會(huì)有過期時(shí)間,如果一直沒有確認(rèn),并且沒有斷開連接,rabbitmq會(huì)一直等待,rabbitmq允許一條消息處理的時(shí)間可以很久很久。
zeromq:支持。
rocketmq:支持。
activemq:支持。
(21)消息回溯對(duì)比
Kafka:支持指定分區(qū)offset位置的回溯。
rabbitmq:不支持
zeromq:不支持
rocketmq:支持指定時(shí)間點(diǎn)的回溯。
activemq:不支持
(22)消息重試對(duì)比
Kafka:不支持,但是可以實(shí)現(xiàn)。
kafka支持指定分區(qū)offset位置的回溯,可以實(shí)現(xiàn)消息重試。
rabbitmq:不支持,但是可以利用消息確認(rèn)機(jī)制實(shí)現(xiàn)。
rabbitmq接收方確認(rèn)機(jī)制,設(shè)置autoAck為false。
當(dāng)autoAck為false的時(shí)候,rabbitmq隊(duì)列會(huì)分成兩部分,一部分是等待投遞給consumer的消息,一部分是已經(jīng)投遞但是沒收到確認(rèn)的消息。如果一直沒有收到確認(rèn)信號(hào),并且consumer已經(jīng)斷開連接,rabbitmq會(huì)安排這個(gè)消息重新進(jìn)入隊(duì)列,投遞給原來的消費(fèi)者或者下一個(gè)消費(fèi)者。
zeromq:不支持,
rocketmq:支持。
消息消費(fèi)失敗的大部分場景下,立即重試99%都會(huì)失敗,所以rocketmq的策略是在消費(fèi)失敗時(shí)定時(shí)重試,每次時(shí)間間隔相同。
1>發(fā)送端的 send 方法本身支持內(nèi)部重試,重試邏輯如下:
a)至多重試3次;
b)如果發(fā)送失敗,則輪轉(zhuǎn)到下一個(gè)broker;
c)這個(gè)方法的總耗時(shí)不超過sendMsgTimeout 設(shè)置的值,默認(rèn) 10s,超過時(shí)間不在重試。
2>接收端。
Consumer消費(fèi)消息失敗后,要提供一種重試機(jī)制,令消息再消費(fèi)一次。Consumer 消費(fèi)消息失敗通??梢苑譃橐韵聝煞N情況:
1.由于消息本身的原因,例如反序列化失敗,消息數(shù)據(jù)本身無法處理(例如話費(fèi)充值,當(dāng)前消息的手機(jī)號(hào)被
注銷,無法充值)等。定時(shí)重試機(jī)制,比如過10s秒后再重試。
2.由于依賴的下游應(yīng)用服務(wù)不可用,例如 db 連接不可用,外系統(tǒng)網(wǎng)絡(luò)不可達(dá)等。
即使跳過當(dāng)前失敗的消息,消費(fèi)其他消息同樣也會(huì)報(bào)錯(cuò)。這種情況可以sleep 30s,再消費(fèi)下一條消息,減輕 Broker 重試消息的壓力。
activemq:不支持
(23)并發(fā)度對(duì)比
Kafka:高
一個(gè)線程一個(gè)消費(fèi)者,kafka限制消費(fèi)者的個(gè)數(shù)要小于等于分區(qū)數(shù),如果要提高并行度,可以在消費(fèi)者中再開啟多線程,或者增加consumer實(shí)例數(shù)量。
rabbitmq:極高
本身是用Erlang語言寫的,并發(fā)性能高。
可在消費(fèi)者中開啟多線程,最常用的做法是一個(gè)channel對(duì)應(yīng)一個(gè)消費(fèi)者,每一個(gè)線程把持一個(gè)channel,多個(gè)線程復(fù)用connection的tcp連接,減少性能開銷。
當(dāng)rabbitmq隊(duì)列擁有多個(gè)消費(fèi)者的時(shí)候,隊(duì)列收到的消息將以輪詢的分發(fā)方式發(fā)送給消費(fèi)者。每條消息只會(huì)發(fā)送給訂閱列表里的一個(gè)消費(fèi)者,不會(huì)重復(fù)。
這種方式非常適合擴(kuò)展,而且是專門為并發(fā)程序設(shè)計(jì)的。
如果某些消費(fèi)者的任務(wù)比較繁重,那么可以設(shè)置basicQos限制信道上消費(fèi)者能保持的最大未確認(rèn)消息的數(shù)量,在達(dá)到上限時(shí),rabbitmq不再向這個(gè)消費(fèi)者發(fā)送任何消息。
zeromq:高
rocketmq:高
1>rocketmq限制消費(fèi)者的個(gè)數(shù)少于等于隊(duì)列數(shù),但是可以在消費(fèi)者中再開啟多線程,這一點(diǎn)和kafka是一致的,提高并行度的方法相同。
修改消費(fèi)并行度方法
a)同一個(gè) ConsumerGroup 下,通過增加 Consumer 實(shí)例數(shù)量來提高并行度,超過訂閱隊(duì)列數(shù)的 Consumer實(shí)例無效。
b)提高單個(gè) Consumer 的消費(fèi)并行線程,通過修改參數(shù)consumeThreadMin、consumeThreadMax
2>同一個(gè)網(wǎng)絡(luò)連接connection,客戶端多個(gè)線程可以同時(shí)發(fā)送請求,連接會(huì)被復(fù)用,減少性能開銷。
activemq:高
單個(gè)ActiveMQ的接收和消費(fèi)消息的速度在1萬筆/秒(持久化 一般為1-2萬, 非持久化 2 萬以上),在生產(chǎn)環(huán)境中部署10個(gè)Activemq就能達(dá)到10萬筆/秒以上的性能,部署越多的activemq broker 在MQ上latency也就越低,系統(tǒng)吞吐量也就越高
(25)綜合對(duì)比:
ActiveMQ:歷史悠久的開源項(xiàng)目,已經(jīng)在很多產(chǎn)品中得到應(yīng)用,實(shí)現(xiàn)了JMS1.1規(guī)范,可以和spring-jms輕松融合,實(shí)現(xiàn)了多種協(xié)議,不夠輕巧(源代碼比RocketMQ多),支持持久化到數(shù)據(jù)庫,對(duì)隊(duì)列數(shù)較多的情況支持不好。RabbitMq:它比kafka成熟,支持AMQP事務(wù)處理,在可靠性上,RabbitMq超過kafka,在性能方面超過ActiveMQ。Kafka:Kafka設(shè)計(jì)的初衷就是處理日志的,不支持AMQP事務(wù)處理,可以看做是一個(gè)日志系統(tǒng),針對(duì)性很強(qiáng),所以它并沒有具備一個(gè)成熟MQ應(yīng)該具備的特性Kafka的性能(吞吐量、tps)比RabbitMq要強(qiáng),如果用來做大數(shù)據(jù)量的快速處理是比RabbitMq有優(yōu)勢的

