??作者簡(jiǎn)介:大家好,我是愛(ài)發(fā)博客的嗯哼,愛(ài)好Java的小菜鳥(niǎo)
??如果感覺(jué)博主的文章還不錯(cuò)的話,請(qǐng)??三連支持??一下博主哦
??社區(qū)論壇:希望大家能加入社區(qū)共同進(jìn)步
?????個(gè)人博客:智慧筆記
??系列專欄:面試寶典
- 本文引自黑馬程序員Java面試寶典
面試官:RabbitMQ-如何保證消息不丟失
候選人:
嗯!我們當(dāng)時(shí)MYSQL和Redis的數(shù)據(jù)雙寫一致性就是采用RabbitMQ實(shí)現(xiàn)同步的,這里面就要求了消息的高可用性,我們要保證消息的不丟失。主要從三個(gè)層面考慮
第一個(gè)是開(kāi)啟生產(chǎn)者確認(rèn)機(jī)制,確保生產(chǎn)者的消息能到達(dá)隊(duì)列,如果報(bào)錯(cuò)可以先記錄到日志中,再去修復(fù)數(shù)據(jù)
第二個(gè)是開(kāi)啟持久化功能,確保消息未消費(fèi)前在隊(duì)列中不會(huì)丟失,其中的交換機(jī)、隊(duì)列、和消息都要做持久化
第三個(gè)是開(kāi)啟消費(fèi)者確認(rèn)機(jī)制為auto,由spring確認(rèn)消息處理成功后完成ack,當(dāng)然也需要設(shè)置一定的重試次數(shù),我們當(dāng)時(shí)設(shè)置了3次,如果重試3次還沒(méi)有收到消息,就將失敗后的消息投遞到異常交換機(jī),交由人工處理
面試官:RabbitMQ消息的重復(fù)消費(fèi)問(wèn)題如何解決的
候選人:
嗯,這個(gè)我們還真遇到過(guò),是這樣的,我們當(dāng)時(shí)消費(fèi)者是設(shè)置了自動(dòng)確認(rèn)機(jī)制,當(dāng)服務(wù)還沒(méi)來(lái)得及給MQ確認(rèn)的時(shí)候,服務(wù)宕機(jī)了,導(dǎo)致服務(wù)重啟之后,又消費(fèi)了一次消息。這樣就重復(fù)消費(fèi)了
因?yàn)槲覀儺?dāng)時(shí)處理的支付(訂單|業(yè)務(wù)唯一標(biāo)識(shí)),它有一個(gè)業(yè)務(wù)的唯一標(biāo)識(shí),我們?cè)偬幚硐r(shí),先到數(shù)據(jù)庫(kù)查詢一下,這個(gè)數(shù)據(jù)是否存在,如果不存在,說(shuō)明沒(méi)有處理過(guò),這個(gè)時(shí)候就可以正常處理這個(gè)消息了。如果已經(jīng)存在這個(gè)數(shù)據(jù)了,就說(shuō)明消息重復(fù)消費(fèi)了,我們就不需要再消費(fèi)了
面試官:那你還知道其他的解決方案嗎?
候選人:
嗯,我想想~
其實(shí)這個(gè)就是典型的冪等的問(wèn)題,比如,redis分布式鎖、數(shù)據(jù)庫(kù)的鎖都是可以的
面試官:RabbitMQ中死信交換機(jī) ? (RabbitMQ延遲隊(duì)列有了解過(guò)嘛)
候選人:
嗯!了解過(guò)!
我們當(dāng)時(shí)的xx項(xiàng)目有一個(gè)xx業(yè)務(wù),需要用到延遲隊(duì)列,其中就是使用RabbitMQ來(lái)實(shí)現(xiàn)的。
延遲隊(duì)列就是用到了死信交換機(jī)和TTL(消息存活時(shí)間)實(shí)現(xiàn)的。
如果消息超時(shí)未消費(fèi)就會(huì)變成死信,在RabbitMQ中如果消息成為死信,隊(duì)列可以綁定一個(gè)死信交換機(jī),在死信交換機(jī)上可以綁定其他隊(duì)列,在我們發(fā)消息的時(shí)候可以按照需求指定TTL的時(shí)間,這樣就實(shí)現(xiàn)了延遲隊(duì)列的功能了。
我記得RabbitMQ還有一種方式可以實(shí)現(xiàn)延遲隊(duì)列,在RabbitMQ中安裝一個(gè)死信插件,這樣更方便一些,我們只需要在聲明交互機(jī)的時(shí)候,指定這個(gè)就是死信交換機(jī),然后在發(fā)送消息的時(shí)候直接指定超時(shí)時(shí)間就行了,相對(duì)于死信交換機(jī)+TTL要省略了一些步驟
面試官:如果有100萬(wàn)消息堆積在MQ , 如何解決 ?
候選人:
我在實(shí)際的開(kāi)發(fā)中,沒(méi)遇到過(guò)這種情況,不過(guò),如果發(fā)生了堆積的問(wèn)題,解決方案也所有很多的
第一:提高消費(fèi)者的消費(fèi)能力 ,可以使用多線程消費(fèi)任務(wù)
第二:增加更多消費(fèi)者,提高消費(fèi)速度
? 使用工作隊(duì)列模式, 設(shè)置多個(gè)消費(fèi)者消費(fèi)消費(fèi)同一個(gè)隊(duì)列中的消息
第三:擴(kuò)大隊(duì)列容積,提高堆積上限
可以使用RabbitMQ惰性隊(duì)列,惰性隊(duì)列的好處主要是
①接收到消息后直接存入磁盤而非內(nèi)存
②消費(fèi)者要消費(fèi)消息時(shí)才會(huì)從磁盤中讀取并加載到內(nèi)存
③支持?jǐn)?shù)百萬(wàn)條的消息存儲(chǔ)
面試官:RabbitMQ的高可用機(jī)制有了解過(guò)嘛
候選人:
嗯,熟悉的~
我們當(dāng)時(shí)項(xiàng)目在生產(chǎn)環(huán)境下,使用的集群,當(dāng)時(shí)搭建是鏡像模式集群,使用了3臺(tái)機(jī)器。
鏡像隊(duì)列結(jié)構(gòu)是一主多從,所有操作都是主節(jié)點(diǎn)完成,然后同步給鏡像節(jié)點(diǎn),如果主節(jié)點(diǎn)宕機(jī)后,鏡像節(jié)點(diǎn)會(huì)替代成新的主節(jié)點(diǎn),不過(guò)在主從同步完成前,主節(jié)點(diǎn)就已經(jīng)宕機(jī),可能出現(xiàn)數(shù)據(jù)丟失
面試官:那出現(xiàn)丟數(shù)據(jù)怎么解決呢?
候選人:
我們可以采用仲裁隊(duì)列,與鏡像隊(duì)列一樣,都是主從模式,支持主從數(shù)據(jù)同步,主從同步基于Raft協(xié)議,強(qiáng)一致。
并且使用起來(lái)也非常簡(jiǎn)單,不需要額外的配置,在聲明隊(duì)列的時(shí)候只要指定這個(gè)是仲裁隊(duì)列即可
面試官:Kafka是如何保證消息不丟失
候選人:
嗯,這個(gè)保證機(jī)制很多,在發(fā)送消息到消費(fèi)者接收消息,在每個(gè)階段都有可能會(huì)丟失消息,所以我們解決的話也是從多個(gè)方面考慮
第一個(gè)是生產(chǎn)者發(fā)送消息的時(shí)候,可以使用異步回調(diào)發(fā)送,如果消息發(fā)送失敗,我們可以通過(guò)回調(diào)獲取失敗后的消息信息,可以考慮重試或記錄日志,后邊再做補(bǔ)償都是可以的。同時(shí)在生產(chǎn)者這邊還可以設(shè)置消息重試,有的時(shí)候是由于網(wǎng)絡(luò)抖動(dòng)的原因?qū)е掳l(fā)送不成功,就可以使用重試機(jī)制來(lái)解決
第二個(gè)在broker中消息有可能會(huì)丟失,我們可以通過(guò)kafka的復(fù)制機(jī)制來(lái)確保消息不丟失,在生產(chǎn)者發(fā)送消息的時(shí)候,可以設(shè)置一個(gè)acks,就是確認(rèn)機(jī)制。我們可以設(shè)置參數(shù)為all,這樣的話,當(dāng)生產(chǎn)者發(fā)送消息到了分區(qū)之后,不僅僅只在leader分區(qū)保存確認(rèn),在follwer分區(qū)也會(huì)保存確認(rèn),只有當(dāng)所有的副本都保存確認(rèn)以后才算是成功發(fā)送了消息,所以,這樣設(shè)置就很大程度了保證了消息不會(huì)在broker丟失
第三個(gè)有可能是在消費(fèi)者端丟失消息,kafka消費(fèi)消息都是按照offset進(jìn)行標(biāo)記消費(fèi)的,消費(fèi)者默認(rèn)是自動(dòng)按期提交已經(jīng)消費(fèi)的偏移量,默認(rèn)是每隔5s提交一次,如果出現(xiàn)重平衡的情況,可能會(huì)重復(fù)消費(fèi)或丟失數(shù)據(jù)。我們一般都會(huì)禁用掉自動(dòng)提價(jià)偏移量,改為手動(dòng)提交,當(dāng)消費(fèi)成功以后再報(bào)告給broker消費(fèi)的位置,這樣就可以避免消息丟失和重復(fù)消費(fèi)了
面試官:Kafka中消息的重復(fù)消費(fèi)問(wèn)題如何解決的
候選人:
kafka消費(fèi)消息都是按照offset進(jìn)行標(biāo)記消費(fèi)的,消費(fèi)者默認(rèn)是自動(dòng)按期提交已經(jīng)消費(fèi)的偏移量,默認(rèn)是每隔5s提交一次,如果出現(xiàn)重平衡的情況,可能會(huì)重復(fù)消費(fèi)或丟失數(shù)據(jù)。我們一般都會(huì)禁用掉自動(dòng)提價(jià)偏移量,改為手動(dòng)提交,當(dāng)消費(fèi)成功以后再報(bào)告給broker消費(fèi)的位置,這樣就可以避免消息丟失和重復(fù)消費(fèi)了
為了消息的冪等,我們也可以設(shè)置唯一主鍵來(lái)進(jìn)行區(qū)分,或者是加鎖,數(shù)據(jù)庫(kù)的鎖,或者是redis分布式鎖,都能解決冪等的問(wèn)題
面試官:Kafka是如何保證消費(fèi)的順序性
候選人:
kafka默認(rèn)存儲(chǔ)和消費(fèi)消息,是不能保證順序性的,因?yàn)橐粋€(gè)topic數(shù)據(jù)可能存儲(chǔ)在不同的分區(qū)中,每個(gè)分區(qū)都有一個(gè)按照順序的存儲(chǔ)的偏移量,如果消費(fèi)者關(guān)聯(lián)了多個(gè)分區(qū)不能保證順序性
如果有這樣的需求的話,我們是可以解決的,把消息都存儲(chǔ)同一個(gè)分區(qū)下就行了,有兩種方式都可以進(jìn)行設(shè)置,第一個(gè)是發(fā)送消息時(shí)指定分區(qū)號(hào),第二個(gè)是發(fā)送消息時(shí)按照相同的業(yè)務(wù)設(shè)置相同的key,因?yàn)槟J(rèn)情況下分區(qū)也是通過(guò)key的hashcode值來(lái)選擇分區(qū)的,hash值如果一樣的話,分區(qū)肯定也是一樣的
面試官:Kafka的高可用機(jī)制有了解過(guò)嘛
候選人:
嗯,主要是有兩個(gè)層面,第一個(gè)是集群,第二個(gè)是提供了復(fù)制機(jī)制
kafka集群指的是由多個(gè)broker實(shí)例組成,即使某一臺(tái)宕機(jī),也不耽誤其他broker繼續(xù)對(duì)外提供服務(wù)
復(fù)制機(jī)制是可以保證kafka的高可用的,一個(gè)topic有多個(gè)分區(qū),每個(gè)分區(qū)有多個(gè)副本,有一個(gè)leader,其余的是follower,副本存儲(chǔ)在不同的broker中;所有的分區(qū)副本的內(nèi)容是都是相同的,如果leader發(fā)生故障時(shí),會(huì)自動(dòng)將其中一個(gè)follower提升為leader,保證了系統(tǒng)的容錯(cuò)性、高可用性
面試官:解釋一下復(fù)制機(jī)制中的ISR
候選人:
ISR的意思是in-sync replica,就是需要同步復(fù)制保存的follower
其中分區(qū)副本有很多的follower,分為了兩類,一個(gè)是ISR,與leader副本同步保存數(shù)據(jù),另外一個(gè)普通的副本,是異步同步數(shù)據(jù),當(dāng)leader掛掉之后,會(huì)優(yōu)先從ISR副本列表中選取一個(gè)作為leader,因?yàn)镮SR是同步保存數(shù)據(jù),數(shù)據(jù)更加的完整一些,所以優(yōu)先選擇ISR副本列表
面試官:Kafka數(shù)據(jù)清理機(jī)制了解過(guò)嘛
候選人:
嗯,了解過(guò)~~
Kafka中topic的數(shù)據(jù)存儲(chǔ)在分區(qū)上,分區(qū)如果文件過(guò)大會(huì)分段存儲(chǔ)segment
每個(gè)分段都在磁盤上以索引(xxxx.index)和日志文件(xxxx.log)的形式存儲(chǔ),這樣分段的好處是,第一能夠減少單個(gè)文件內(nèi)容的大小,查找數(shù)據(jù)方便,第二方便kafka進(jìn)行日志清理。
在kafka中提供了兩個(gè)日志的清理策略:
第一,根據(jù)消息的保留時(shí)間,當(dāng)消息保存的時(shí)間超過(guò)了指定的時(shí)間,就會(huì)觸發(fā)清理,默認(rèn)是168小時(shí)( 7天)
第二是根據(jù)topic存儲(chǔ)的數(shù)據(jù)大小,當(dāng)topic所占的日志文件大小大于一定的閾值,則開(kāi)始刪除最久的消息。這個(gè)默認(rèn)是關(guān)閉的
這兩個(gè)策略都可以通過(guò)kafka的broker中的配置文件進(jìn)行設(shè)置
面試官:Kafka中實(shí)現(xiàn)高性能的設(shè)計(jì)有了解過(guò)嘛
候選人:
Kafka 高性能,是多方面協(xié)同的結(jié)果,包括宏觀架構(gòu)、分布式存儲(chǔ)、ISR 數(shù)據(jù)同步、以及高效的利用磁盤、操作系統(tǒng)特性等。主要體現(xiàn)有這么幾點(diǎn):
消息分區(qū):不受單臺(tái)服務(wù)器的限制,可以不受限的處理更多的數(shù)據(jù)
順序讀寫:磁盤順序讀寫,提升讀寫效率
頁(yè)緩存:把磁盤中的數(shù)據(jù)緩存到內(nèi)存中,把對(duì)磁盤的訪問(wèn)變?yōu)閷?duì)內(nèi)存的訪問(wèn)
零拷貝:減少上下文切換及數(shù)據(jù)拷貝
消息壓縮:減少磁盤IO和網(wǎng)絡(luò)IO
分批發(fā)送:將消息打包批量發(fā)送,減少網(wǎng)絡(luò)開(kāi)銷文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-658612.html
往期文章推薦:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-658612.html
- Java集合相關(guān)面試題
- Java集合詳解
- 微服務(wù)相關(guān)面試題
- redis相關(guān)面試題
- 圖解 Paxos 算法
- Spring相關(guān)面試題
- Mysql相關(guān)面試題
- 深入淺出WebSocket
到了這里,關(guān)于消息中間件相關(guān)面試題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!