RocketMq和Kafka對(duì)比
kafka高性能原因:
生產(chǎn)者:
Kafka會(huì)把收到的消息都寫(xiě)入到硬盤(pán)中,它絕對(duì)不會(huì)丟失數(shù)據(jù)。為了優(yōu)化寫(xiě)入速度Kafak采用了兩個(gè)技術(shù),順序?qū)懭牒蚆MFile
。
順序?qū)懭耄?/h4>
因?yàn)橛脖P(pán)是機(jī)械結(jié)構(gòu),每次讀寫(xiě)都會(huì)尋址->寫(xiě)入,其中尋址是一個(gè)“機(jī)械動(dòng)作”,它是最耗時(shí)的。所以硬盤(pán)最“討厭”隨機(jī)I/O,最喜歡順序I/O。
為了提高讀寫(xiě)硬盤(pán)的速度,Kafka就是使用順序I/O。收到消息后Kafka會(huì)把數(shù)據(jù)插入到文件末尾
。這種方法有一個(gè)缺陷
——沒(méi)有辦法刪除數(shù)據(jù),所以Kafka是不會(huì)刪除數(shù)據(jù)的,它會(huì)把所有的數(shù)據(jù)都保留下來(lái),每個(gè)消費(fèi)者(Consumer)對(duì)每個(gè)Topic都有一個(gè)offset用來(lái)表示讀取到了第幾條數(shù)據(jù)
。
Memory Mapped Files:
Kafka的數(shù)據(jù)并不是實(shí)時(shí)的寫(xiě)入硬盤(pán),它充分利用了現(xiàn)代操作系統(tǒng)分頁(yè)存儲(chǔ)來(lái)利用內(nèi)存提高I/O效率
。
Memory Mapped Files也被翻譯成內(nèi)存映射文件,在64位操作系統(tǒng)中一般可以表示20G的數(shù)據(jù)文件,它的工作原理是直接利用操作系統(tǒng)的Page來(lái)實(shí)現(xiàn)文件到物理內(nèi)存的直接映射。完成映射之后你對(duì)物理內(nèi)存的操作會(huì)被同步到硬盤(pán)上(操作系統(tǒng)在適當(dāng)?shù)臅r(shí)候)。這種方法也有一個(gè)很明顯的缺陷——不可靠,寫(xiě)到mmap中的數(shù)據(jù)并沒(méi)有被真正的寫(xiě)到硬盤(pán),操作系統(tǒng)會(huì)在程序主動(dòng)調(diào)用flush的時(shí)候才把數(shù)據(jù)真正的寫(xiě)到硬盤(pán)。
Kafka提供了一個(gè)參數(shù)——producer.type來(lái)控制是不是主動(dòng)flush,如果Kafka寫(xiě)入到mmap之后就立即flush然后再返回Producer叫同步(sync);寫(xiě)入mmap之后立即返回Producer不調(diào)用flush叫異步(async)。
消費(fèi)者:
zero copy:
傳統(tǒng)read/write方式進(jìn)行網(wǎng)絡(luò)文件傳輸?shù)姆绞?,文件?shù)據(jù)實(shí)際上是經(jīng)過(guò)了四次copy操作:硬盤(pán)—>內(nèi)核buf—>用戶(hù)buf—>socket相關(guān)緩沖區(qū)—>協(xié)議引擎kafka基于sendfile實(shí)現(xiàn)Zero Copy,直接從內(nèi)核空間(DMA的)到內(nèi)核空間(Socket的),然后發(fā)送網(wǎng)卡。
批量壓縮:
在很多情況下,系統(tǒng)的瓶頸不是CPU或磁盤(pán),而是網(wǎng)絡(luò)IO。進(jìn)行數(shù)據(jù)壓縮會(huì)消耗少量的CPU資源,不過(guò)對(duì)于kafka而言,網(wǎng)絡(luò)IO更應(yīng)該需要考慮。Kafka使用了批量壓縮,即將多個(gè)消息一起壓縮而不是單個(gè)消息壓縮。Kafka允許使用遞歸的消息集合,批量的消息可以通過(guò)壓縮的形式傳輸并且在日志中也可以保持壓縮格式,直到被消費(fèi)者解壓縮。Kafka支持多種壓縮協(xié)議,包括Gzip和Snappy壓縮協(xié)議。
rocketMq高性能原因:
生產(chǎn)者:
順序?qū)懭耄?/h4>
消息存儲(chǔ)是由ConsumeQueue和CommitLog配合完成的
。一個(gè)Topic里面有多個(gè)MessageQueue,每個(gè)MessageQueue對(duì)應(yīng)一個(gè)ConsumeQueue。ConsumeQueue里記錄著消息物理存儲(chǔ)地址。CommitLog就存儲(chǔ)文件具體的字節(jié)信息。文件大小默認(rèn)1g,文件名稱(chēng)20位數(shù),左邊補(bǔ)0右邊為偏移量。消息順序?qū)懭胛募?,文件滿了則寫(xiě)入下一個(gè)文件。
消費(fèi)者
隨機(jī)讀
每次讀消息時(shí)先讀邏輯隊(duì)列consumQue中的元數(shù)據(jù),再?gòu)腸ommitlog中找到消息體。但是入口處rocketmq采用package機(jī)制,可以批量地從磁盤(pán)讀取,作為cache存到內(nèi)存中,加速后續(xù)的讀取速度。
隨機(jī)讀具體流程:
- Consumer每20s重新做一次負(fù)載均衡更新,根據(jù)從Broker存儲(chǔ)的ConsumerGroup和Topic信息,把MessageQueue分發(fā)給不同的Consumer,負(fù)載策略默認(rèn)是分頁(yè)
- 每個(gè)MessageQueue對(duì)應(yīng)一個(gè)pullRequest,全部存儲(chǔ)到該Consumer的pullRequestQueue隊(duì)列里面
- Consumer啟動(dòng)獨(dú)立后臺(tái)PullMessageService線程,不停的嘗試從pullRequestQueue.take()獲取PullRequest
- 撈取到PullRequest會(huì)先做緩存校驗(yàn)(默認(rèn)一個(gè)Queue里面緩存待處理消息個(gè)數(shù)不超過(guò)1000個(gè),消息大小不超過(guò)100M,否則會(huì)延遲50ms再重試),從而保證客戶(hù)端的緩存負(fù)載不會(huì)過(guò)高
- PullRequest發(fā)送給Broker,如果Broker發(fā)現(xiàn)該Queue有待處理的消息,就會(huì)直接返回給Consumer,Consumer接收響應(yīng)以后,重新把該P(yáng)ullRequest丟到自己的pullRequestQueue隊(duì)列里面,從而重復(fù)執(zhí)行撈取消息的動(dòng)作,保證消息的及時(shí)性
- PullRequest發(fā)送給Broker,如果Broker發(fā)現(xiàn)該Queue沒(méi)有待處理的消息,則會(huì)Hold住這個(gè)請(qǐng)求,暫不響應(yīng)給Consumer,默認(rèn)長(zhǎng)輪詢(xún)是5s重試獲取一次待處理消息,如果有新的待處理消息則立刻Response給Consumer,當(dāng)客戶(hù)端檢測(cè)到消息掛起超時(shí)(客戶(hù)端有默認(rèn)參數(shù) 響應(yīng)超時(shí)時(shí)間 20s),會(huì)重新發(fā)起PullRequest給Broker
消費(fèi)模型:
常見(jiàn)消費(fèi)模型有以下幾種:
push:producer發(fā)送消息后,broker馬上把消息投遞給consumer。這種方式好在實(shí)時(shí)性比較高,但是會(huì)增加broker的負(fù)載;而且消費(fèi)端能力不同,如果push推送過(guò)快,消費(fèi)端會(huì)出現(xiàn)很多問(wèn)題。
pull:producer發(fā)送消息后,broker什么也不做,等著consumer自己來(lái)讀取。它的優(yōu)點(diǎn)在于主動(dòng)權(quán)在消費(fèi)者端,可控性好;但是間隔時(shí)間不好設(shè)置,間隔太短浪費(fèi)資源,間隔太長(zhǎng)又會(huì)消費(fèi)不及時(shí)。
長(zhǎng)輪詢(xún):當(dāng)consumer過(guò)來(lái)請(qǐng)求時(shí),broker會(huì)保持當(dāng)前連接一段時(shí)間 默認(rèn)15s,如果這段時(shí)間內(nèi)有消息到達(dá),則立刻返回給consumer;15s沒(méi)消息的話則返回空然后重新請(qǐng)求。這種方式的缺點(diǎn)就是服務(wù)端要保存consumer狀態(tài),客戶(hù)端過(guò)多會(huì)一直占用資源。
RocketMQ默認(rèn)是采用pushConsumer方式消費(fèi)的
,從概念上來(lái)說(shuō)是推送給消費(fèi)者,它的本質(zhì)是pull+長(zhǎng)輪詢(xún)
。這樣既通過(guò)長(zhǎng)輪詢(xún)達(dá)到了push的實(shí)時(shí)性,又有了pull的可控性
。系統(tǒng)收到消息后會(huì)自動(dòng)處理消息和offset(消息偏移量),如果期間有新的consumer加入會(huì)自動(dòng)做負(fù)載均衡(集群模式下offset存在broker中; 廣播模式下offset存在consumer里)。當(dāng)然我們也可以設(shè)置為pullConsumer模式,這樣靈活性會(huì)提高,但是代碼卻會(huì)很復(fù)雜,需要手動(dòng)維護(hù)offset,消息存儲(chǔ)和狀態(tài)。
zero copy:
零拷貝技術(shù)有mmap及sendfile,sendfile大文件傳輸快,mmap小文件傳輸快。MMQ發(fā)送的消息通常都很小,rocketmq就是以mmap+write方式實(shí)現(xiàn)的。
為什么kafka比RocketMQ吞吐量更高?
kafka性吞吐量更高主要是由于Producer端將多個(gè)小消息合并,批量發(fā)向Broker。kafka采用異步發(fā)送的機(jī)制,當(dāng)發(fā)送一條消息時(shí),消息并沒(méi)有發(fā)送到broker而是緩存起來(lái),然后直接向業(yè)務(wù)返回成功,當(dāng)緩存的消息達(dá)到一定數(shù)量時(shí)再批量發(fā)送。此時(shí)減少了網(wǎng)絡(luò)io,從而提高了消息發(fā)送的性能,但是如果消息發(fā)送者宕機(jī),會(huì)導(dǎo)致消息丟失,業(yè)務(wù)出錯(cuò),所以理論上kafka利用此機(jī)制提高了io性能卻降低了可靠性
。
RocketMQ為何無(wú)法使用同樣的方式?
RocketMQ通常使用的Java語(yǔ)言,緩存過(guò)多消息會(huì)導(dǎo)致頻繁GC
。
Producer調(diào)用發(fā)送消息接口,消息未發(fā)送到Broker,向業(yè)務(wù)返回成功,此時(shí)Producer宕機(jī),會(huì)導(dǎo)致消息丟失,業(yè)務(wù)出錯(cuò)。Producer通常為分布式系統(tǒng),且每臺(tái)機(jī)器都是多線程發(fā)送,我們認(rèn)為線上的系統(tǒng)單個(gè)Producer每秒產(chǎn)生的數(shù)據(jù)量有限,不可能上萬(wàn)。緩存的功能完全可以由上層業(yè)務(wù)完成。
為什么選擇RocketMQ?
當(dāng)broker里面的topic的partition數(shù)量過(guò)多時(shí),kafka的性能卻不如rocketMq。kafka和rocketMq都使用文件存儲(chǔ),但是kafka是一個(gè)分區(qū)一個(gè)文件,當(dāng)topic過(guò)多,分區(qū)的總量也會(huì)增加,kafka中存在過(guò)多的文件,當(dāng)對(duì)消息刷盤(pán)時(shí),就會(huì)出現(xiàn)文件競(jìng)爭(zhēng)磁盤(pán),出現(xiàn)性能的下降
。一個(gè)partition(分區(qū))一個(gè)文件,順序讀寫(xiě)。一個(gè)分區(qū)只能被一個(gè)消費(fèi)組中的一個(gè) 消費(fèi)線程進(jìn)行消費(fèi),因此可以同時(shí)消費(fèi)的消費(fèi)端也比較少
。rocketMq所有的隊(duì)列都存儲(chǔ)在一個(gè)文件中,每個(gè)隊(duì)列的存儲(chǔ)的消息量也比較小,因此topic的增加對(duì)rocketMq的性能的影響較小。rocketMq可以存在的topic比較多,可以適應(yīng)比較復(fù)雜的業(yè)務(wù)
。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-478029.html
參考并感謝:
https://www.zhihu.com/search?type=content&q=kafka%E4%B8%8ErocketMq%E7%9A%84%E5%8C%BA%E5%88%AB文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-478029.html
到了這里,關(guān)于RocketMq和Kafka對(duì)比的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!