MQ奪命連環(huán)11問(wèn)

一、你們?yōu)槭裁词褂胢q苦锨?具體的使用場(chǎng)景是什么逼泣?

mq的作用很簡(jiǎn)單趴泌,削峰填谷。以電商交易下單的場(chǎng)景來(lái)說(shuō)拉庶,正向交易的過(guò)程可能涉及到創(chuàng)建訂單嗜憔、扣減庫(kù)存、扣減活動(dòng)預(yù)算氏仗、扣減積分等等吉捶。每個(gè)接口的耗時(shí)如果是100ms,那么理論上整個(gè)下單的鏈路就需要耗費(fèi)400ms皆尔,這個(gè)時(shí)間顯然是太長(zhǎng)了呐舔。

下單

如果這些操作全部同步處理的話,首先調(diào)用鏈路太長(zhǎng)影響接口性能慷蠕,其次分布式事務(wù)的問(wèn)題很難處理珊拼,這時(shí)候像扣減預(yù)算和積分這種對(duì)實(shí)時(shí)一致性要求沒有那么高的請(qǐng)求,完全就可以通過(guò)mq異步的方式去處理了流炕。同時(shí)澎现,考慮到異步帶來(lái)的不一致的問(wèn)題,我們可以通過(guò)job去重試保證接口調(diào)用成功每辟,而且一般公司都會(huì)有核對(duì)的平臺(tái)剑辫,比如下單成功但是未扣減積分的這種問(wèn)題可以通過(guò)核對(duì)作為兜底的處理方案。

下單-MQ

使用mq之后我們的鏈路變簡(jiǎn)單了渠欺,同時(shí)異步發(fā)送消息我們的整個(gè)系統(tǒng)的抗壓能力也上升了妹蔽。

二、那你們使用什么mq挠将?基于什么做的選型胳岂?

我們主要調(diào)研了幾個(gè)主流的mq,kafka捐名、rabbitmq旦万、rocketmq、activemq镶蹋,選型我們主要基于以下幾個(gè)點(diǎn)去考慮:

1成艘、由于我們系統(tǒng)的qps壓力比較大,所以性能是首要考慮的要素贺归。
2淆两、開發(fā)語(yǔ)言,由于我們的開發(fā)語(yǔ)言是java拂酣,主要是為了方便二次開發(fā)秋冰。
3、對(duì)于高并發(fā)的業(yè)務(wù)場(chǎng)景是必須的婶熬,所以需要支持分布式架構(gòu)的設(shè)計(jì)剑勾。
4埃撵、功能全面,由于不同的業(yè)務(wù)場(chǎng)景虽另,可能會(huì)用到順序消息暂刘、事務(wù)消息等。

基于以上幾個(gè)考慮捂刺,我們最終選擇了RocketMQ谣拣。

MQ對(duì)比

三、你上面提到異步發(fā)送族展,那消息可靠性怎么保證森缠?

消息丟失可能發(fā)生在生產(chǎn)者發(fā)送消息、MQ本身丟失消息仪缸、消費(fèi)者丟失消息3個(gè)方面贵涵。

3.1 生產(chǎn)者丟失

生產(chǎn)者丟失消息的可能點(diǎn)在于程序發(fā)送失敗拋異常了沒有重試處理,或者發(fā)送的過(guò)程成功但是過(guò)程中網(wǎng)絡(luò)閃斷MQ沒收到腹殿,消息就丟失了独悴。

由于同步發(fā)送的一般不會(huì)出現(xiàn)這樣使用方式,所以我們就不考慮同步發(fā)送的問(wèn)題锣尉,我們基于異步發(fā)送的場(chǎng)景來(lái)說(shuō)。

異步發(fā)送分為兩個(gè)方式:異步有回調(diào)和異步無(wú)回調(diào)决采,無(wú)回調(diào)的方式自沧,生產(chǎn)者發(fā)送完后不管結(jié)果可能就會(huì)造成消息丟失,而通過(guò)異步發(fā)送+回調(diào)通知+本地消息表的形式我們就可以做出一個(gè)解決方案树瞭。以下單的場(chǎng)景舉例拇厢。

1、下單后先保存本地?cái)?shù)據(jù)和MQ消息表晒喷,這時(shí)候消息的狀態(tài)是發(fā)送中孝偎,如果本地事務(wù)失敗,那么下單失敗凉敲,事務(wù)回滾(訂單數(shù)據(jù)衣盾、MQ消息記錄都不會(huì)保存)。

2爷抓、下單成功势决,直接返回客戶端成功,異步發(fā)送MQ消息蓝撇。

3果复、MQ回調(diào)通知消息發(fā)送結(jié)果,對(duì)應(yīng)更新數(shù)據(jù)庫(kù)MQ發(fā)送狀態(tài)渤昌。

4虽抄、JOB輪詢超過(guò)一定時(shí)間(時(shí)間根據(jù)業(yè)務(wù)配置)還未發(fā)送成功的消息去重試
在監(jiān)控平臺(tái)配置或者JOB程序處理超過(guò)一定次數(shù)一直發(fā)送不成功的消息走搁,告警,人工介入迈窟。

MQ

一般而言私植,對(duì)于大部分場(chǎng)景來(lái)說(shuō)異步回調(diào)的形式就可以了,只有那種需要完全保證不能丟失消息的場(chǎng)景我們做一套完整的解決方案菠隆。

3.2 MQ丟失

如果生產(chǎn)者保證消息發(fā)送到MQ兵琳,而MQ收到消息后還在內(nèi)存中,這時(shí)候宕機(jī)了又沒來(lái)得及同步給從節(jié)點(diǎn)骇径,就有可能導(dǎo)致消息丟失躯肌。

比如RocketMQ:

RocketMQ分為同步刷盤和異步刷盤兩種方式,默認(rèn)的是異步刷盤破衔,就有可能導(dǎo)致消息還未刷到硬盤上就丟失了清女,可以通過(guò)設(shè)置為同步刷盤的方式來(lái)保證消息可靠性,這樣即使MQ掛了晰筛,恢復(fù)的時(shí)候也可以從磁盤中去恢復(fù)消息嫡丙。

比如Kafka也可以通過(guò)配置做到:

acks=all 只有參與復(fù)制的所有節(jié)點(diǎn)全部收到消息,才返回生產(chǎn)者成功读第。這樣的話除非所有的節(jié)點(diǎn)都掛了曙博,消息才會(huì)丟失。
replication.factor=N,設(shè)置大于1的數(shù)怜瞒,這會(huì)要求每個(gè)partion至少有2個(gè)副本
min.insync.replicas=N父泳,設(shè)置大于1的數(shù),這會(huì)要求leader至少感知到一個(gè)follower還保持著連接
retries=N吴汪,設(shè)置一個(gè)非常大的值惠窄,讓生產(chǎn)者發(fā)送失敗一直重試

雖然我們可以通過(guò)配置的方式來(lái)達(dá)到MQ本身高可用的目的,但是都對(duì)性能有損耗漾橙,怎樣配置需要根據(jù)業(yè)務(wù)做出權(quán)衡杆融。

3.3 消費(fèi)者丟失

消費(fèi)者丟失消息的場(chǎng)景1:消費(fèi)者剛收到消息,此時(shí)服務(wù)器宕機(jī)霜运,MQ認(rèn)為消費(fèi)者已經(jīng)消費(fèi)脾歇,不會(huì)重復(fù)發(fā)送消息,消息丟失觉渴。

RocketMQ默認(rèn)是需要消費(fèi)者回復(fù)ack確認(rèn)介劫,而kafka需要手動(dòng)開啟配置關(guān)閉自動(dòng)offset。

消費(fèi)方不返回ack確認(rèn)案淋,重發(fā)的機(jī)制根據(jù)MQ類型的不同發(fā)送時(shí)間間隔座韵、次數(shù)都不盡相同,如果重試超過(guò)次數(shù)之后會(huì)進(jìn)入死信隊(duì)列,需要手工來(lái)處理了誉碴。(Kafka沒有這些)

MQ

消費(fèi)者丟失消息的場(chǎng)景2:消費(fèi)者收到消息宦棺,但消費(fèi)業(yè)務(wù)邏輯出錯(cuò),消費(fèi)失敗黔帕。
解決:利用前面提到的MQ本地表代咸,消費(fèi)者收到消息且業(yè)務(wù)邏輯執(zhí)行完畢后再更新MQ消息的狀態(tài)(更新為已消費(fèi))

四、你說(shuō)到消費(fèi)者消費(fèi)失敗的問(wèn)題成黄,那么如果一直消費(fèi)失敗導(dǎo)致消息積壓怎么處理呐芥?

因?yàn)榭紤]到時(shí)消費(fèi)者消費(fèi)一直出錯(cuò)的問(wèn)題,那么我們可以從以下幾個(gè)角度來(lái)考慮:

1奋岁、消費(fèi)者出錯(cuò)思瘟,肯定是程序或者其他問(wèn)題導(dǎo)致的,如果容易修復(fù)闻伶,先把問(wèn)題修復(fù)滨攻,讓consumer恢復(fù)正常消費(fèi)。

2蓝翰、如果時(shí)間來(lái)不及處理很麻煩光绕,做轉(zhuǎn)發(fā)處理,寫一個(gè)臨時(shí)的consumer消費(fèi)方案畜份,先把消息消費(fèi)诞帐,然后再轉(zhuǎn)發(fā)到一個(gè)新的topic和MQ資源,這個(gè)新的topic的機(jī)器資源單獨(dú)申請(qǐng)爆雹,要能承載住當(dāng)前積壓的消息景埃。

3、處理完積壓數(shù)據(jù)后顶别,修復(fù)consumer,去消費(fèi)新的MQ和現(xiàn)有的MQ數(shù)據(jù)拒啰,新MQ消費(fèi)完成后恢復(fù)原狀隐锭。

MQ

五督惰、那如果消息積壓達(dá)到磁盤上限,消息被刪除了怎么辦?

最初拧咳,我們發(fā)送的消息記錄是落庫(kù)保存了的,而轉(zhuǎn)發(fā)發(fā)送的數(shù)據(jù)也保存了褐着,那么我們就可以通過(guò)這部分?jǐn)?shù)據(jù)來(lái)找到丟失的那部分?jǐn)?shù)據(jù)逃顶,再單獨(dú)跑個(gè)腳本重發(fā)就可以了。如果轉(zhuǎn)發(fā)的程序沒有落庫(kù)甲捏,那就和消費(fèi)方的記錄去做對(duì)比演熟,只是過(guò)程會(huì)更艱難一點(diǎn)。

六、說(shuō)了這么多芒粹,那你說(shuō)說(shuō)RocketMQ實(shí)現(xiàn)原理吧兄纺?

RocketMQ由NameServer注冊(cè)中心集群、Producer生產(chǎn)者集群化漆、Consumer消費(fèi)者集群和若干Broker(RocketMQ進(jìn)程)組成估脆,它的架構(gòu)原理是這樣的:

1、Broker在啟動(dòng)的時(shí)候去向所有的NameServer注冊(cè)座云,并保持長(zhǎng)連接疙赠,每30s發(fā)送一次心跳。

2朦拖、Producer在發(fā)送消息的時(shí)候從NameServer獲取Broker服務(wù)器地址圃阳,根據(jù)負(fù)載均衡算法選擇一臺(tái)服務(wù)器來(lái)發(fā)送消息。

3贞谓、Conusmer消費(fèi)消息的時(shí)候同樣從NameServer獲取Broker地址限佩,然后主動(dòng)拉取消息來(lái)消費(fèi)。

RocketMQ

七裸弦、為什么RocketMQ不使用Zookeeper作為注冊(cè)中心呢祟同?

我認(rèn)為有以下幾個(gè)點(diǎn)是不使用zookeeper的原因:

1、根據(jù)CAP理論理疙,同時(shí)最多只能滿足兩個(gè)點(diǎn)晕城,而zookeeper滿足的是CP,也就是說(shuō)zookeeper并不能保證服務(wù)的可用性窖贤,zookeeper在進(jìn)行選舉的時(shí)候砖顷,整個(gè)選舉的時(shí)間太長(zhǎng),期間整個(gè)集群都處于不可用的狀態(tài)赃梧,而這對(duì)于一個(gè)注冊(cè)中心來(lái)說(shuō)肯定是不能接受的滤蝠,作為服務(wù)發(fā)現(xiàn)來(lái)說(shuō)就應(yīng)該是為可用性而設(shè)計(jì)。

2授嘀、基于性能的考慮物咳,NameServer本身的實(shí)現(xiàn)非常輕量,而且可以通過(guò)增加機(jī)器的方式水平擴(kuò)展蹄皱,增加集群的抗壓能力览闰,而zookeeper的寫是不可擴(kuò)展的,而zookeeper要解決這個(gè)問(wèn)題只能通過(guò)劃分領(lǐng)域巷折,劃分多個(gè)zookeeper集群來(lái)解決压鉴,首先操作起來(lái)太復(fù)雜,其次這樣還是又違反了CAP中的A的設(shè)計(jì)锻拘,導(dǎo)致服務(wù)之間是不連通的油吭。

3、持久化的機(jī)制來(lái)帶的問(wèn)題,ZooKeeper 的 ZAB 協(xié)議對(duì)每一個(gè)寫請(qǐng)求上鞠,會(huì)在每個(gè) ZooKeeper 節(jié)點(diǎn)上保持寫一個(gè)事務(wù)日志际邻,同時(shí)再加上定期的將內(nèi)存數(shù)據(jù)鏡像(Snapshot)到磁盤來(lái)保證數(shù)據(jù)的一致性和持久性,而對(duì)于一個(gè)簡(jiǎn)單的服務(wù)發(fā)現(xiàn)的場(chǎng)景來(lái)說(shuō)芍阎,這其實(shí)沒有太大的必要世曾,這個(gè)實(shí)現(xiàn)方案太重了。而且本身存儲(chǔ)的數(shù)據(jù)應(yīng)該是高度定制化的谴咸。

4轮听、消息發(fā)送應(yīng)該弱依賴注冊(cè)中心,而RocketMQ的設(shè)計(jì)理念也正是基于此岭佳,生產(chǎn)者在第一次發(fā)送消息的時(shí)候從NameServer獲取到Broker地址后緩存到本地血巍,如果NameServer整個(gè)集群不可用,短時(shí)間內(nèi)對(duì)于生產(chǎn)者和消費(fèi)者并不會(huì)產(chǎn)生太大影響珊随。

八述寡、那Broker是怎么保存數(shù)據(jù)的呢?

RocketMQ主要的存儲(chǔ)文件包括commitlog文件叶洞、consumequeue文件鲫凶、indexfile文件。

Broker在收到消息之后衩辟,會(huì)把消息保存到commitlog的文件當(dāng)中螟炫,而同時(shí)在分布式的存儲(chǔ)當(dāng)中,每個(gè)broker都會(huì)保存一部分topic的數(shù)據(jù)艺晴,同時(shí)昼钻,每個(gè)topic對(duì)應(yīng)的messagequeue下都會(huì)生成consumequeue文件用于保存commitlog的物理位置偏移量offset,indexfile中會(huì)保存key和offset的對(duì)應(yīng)關(guān)系封寞。

Broker

CommitLog文件保存于${Rocket_Home}/store/commitlog目錄中然评,從圖中我們可以明顯看出來(lái)文件名的偏移量,每個(gè)文件默認(rèn)1G狈究,寫滿后自動(dòng)生成一個(gè)新的文件沾瓦。

log

由于同一個(gè)topic的消息并不是連續(xù)的存儲(chǔ)在commitlog中,消費(fèi)者如果直接從commitlog獲取消息效率非常低谦炒,所以通過(guò)consumequeue保存commitlog中消息的偏移量的物理地址,這樣消費(fèi)者在消費(fèi)的時(shí)候先從consumequeue中根據(jù)偏移量定位到具體的commitlog物理文件风喇,然后根據(jù)一定的規(guī)則(offset和文件大小取模)在commitlog中快速定位宁改。

log

九、Master和Slave之間是怎么同步數(shù)據(jù)的呢魂莫?

而消息在master和slave之間的同步是根據(jù)raft協(xié)議來(lái)進(jìn)行的:

1还蹲、在broker收到消息后,會(huì)被標(biāo)記為uncommitted狀態(tài)
2、然后會(huì)把消息發(fā)送給所有的slave
3谜喊、slave在收到消息之后返回ack響應(yīng)給master
4潭兽、master在收到超過(guò)半數(shù)的ack之后,把消息標(biāo)記為committed
5斗遏、發(fā)送committed消息給所有slave山卦,slave也修改狀態(tài)為committed

十、你知道RocketMQ為什么速度快嗎诵次?

是因?yàn)槭褂昧隧樞虼鎯?chǔ)账蓉、Page Cache和異步刷盤。

1逾一、我們?cè)趯懭隿ommitlog的時(shí)候是順序?qū)懭氲闹荆@樣比隨機(jī)寫入的性能就會(huì)提高很多。

2遵堵、寫入commitlog的時(shí)候并不是直接寫入磁盤箱玷,而是先寫入操作系統(tǒng)的PageCache。

3陌宿、最后由操作系統(tǒng)異步將緩存中的數(shù)據(jù)刷到磁盤锡足。

十一、什么是事務(wù)限番、半事務(wù)消息舱污?怎么實(shí)現(xiàn)的?

事務(wù)消息就是MQ提供的類似XA的分布式事務(wù)能力弥虐,通過(guò)事務(wù)消息可以達(dá)到分布式事務(wù)的最終一致性扩灯。半事務(wù)消息就是MQ收到了生產(chǎn)者的消息,但是沒有收到二次確認(rèn)霜瘪,不能投遞的消息珠插。實(shí)現(xiàn)原理如下:

1、生產(chǎn)者先發(fā)送一條半事務(wù)消息到MQ颖对。

2捻撑、MQ收到消息后返回ack確認(rèn)。

3缤底、生產(chǎn)者開始執(zhí)行本地事務(wù)顾患。

4、如果事務(wù)執(zhí)行成功發(fā)送commit到MQ个唧,失敗發(fā)送rollback江解。

5、如果MQ長(zhǎng)時(shí)間未收到生產(chǎn)者的二次確認(rèn)commit或者rollback徙歼,MQ對(duì)生產(chǎn)者發(fā)起消息回查犁河。

6鳖枕、生產(chǎn)者查詢事務(wù)執(zhí)行最終狀態(tài)。

7桨螺、根據(jù)查詢事務(wù)狀態(tài)再次提交二次確認(rèn)宾符。

最終,如果MQ收到二次確認(rèn)commit灭翔,就可以把消息投遞給消費(fèi)者魏烫,反之如果是rollback,消息會(huì)保存下來(lái)并且在3天后被刪除缠局。

事務(wù)

轉(zhuǎn)載自:面試題系列:MQ 奪命連環(huán)11問(wèn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末则奥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狭园,更是在濱河造成了極大的恐慌读处,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唱矛,死亡現(xiàn)場(chǎng)離奇詭異罚舱,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绎谦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門管闷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人窃肠,你說(shuō)我怎么就攤上這事包个。” “怎么了冤留?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵碧囊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我纤怒,道長(zhǎng)糯而,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任泊窘,我火速辦了婚禮熄驼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烘豹。我一直安慰自己瓜贾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布携悯。 她就那樣靜靜地躺著阐虚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚌卤。 梳的紋絲不亂的頭發(fā)上实束,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音逊彭,去河邊找鬼咸灿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛侮叮,可吹牛的內(nèi)容都是我干的避矢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼囊榜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼审胸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起卸勺,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤砂沛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后曙求,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碍庵,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年悟狱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了静浴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挤渐,死狀恐怖苹享,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浴麻,我是刑警寧澤得问,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站白胀,受9級(jí)特大地震影響椭赋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜或杠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一哪怔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧向抢,春花似錦认境、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至艘希,卻和暖如春硼身,著一層夾襖步出監(jiān)牢的瞬間硅急,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工佳遂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留营袜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓丑罪,卻偏偏與公主長(zhǎng)得像荚板,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吩屹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容