阿里三面:MQ 消息丟失蟋软、重復(fù)镶摘、積壓?jiǎn)栴},如何解決岳守?

面試官在面試候選人時(shí)凄敢,如果發(fā)現(xiàn)候選人的簡(jiǎn)歷中寫了在項(xiàng)目中使用了 MQ 技術(shù)(如 Kafka、RabbitMQ棺耍、RocketMQ)贡未,基本都會(huì)拋出一個(gè)問題:在使用 MQ 的時(shí)候种樱,怎么確保消息 100% 不丟失蒙袍?

這個(gè)問題在實(shí)際工作中很常見,既能考察候選者對(duì)于 MQ 中間件技術(shù)的掌握程度嫩挤,又能很好地區(qū)分候選人的能力水平害幅。接下來,我們就從這個(gè)問題出發(fā)岂昭,探討你應(yīng)該掌握的基礎(chǔ)知識(shí)和答題思路以现,以及延伸的面試考點(diǎn)。

案例背景

以京東系統(tǒng)為例约啊,用戶在購(gòu)買商品時(shí)邑遏,通常會(huì)選擇用京豆抵扣一部分的金額,在這個(gè)過程中恰矩,交易服務(wù)和京豆服務(wù)通過 MQ 消息隊(duì)列進(jìn)行通信记盒。在下單時(shí),交易服務(wù)發(fā)送“扣減賬戶 X 100 個(gè)京豆”的消息給 MQ 消息隊(duì)列外傅,而京豆服務(wù)則在消費(fèi)端消費(fèi)這條命令纪吮,實(shí)現(xiàn)真正的扣減操作。

那在這個(gè)過程中你會(huì)遇到什么問題呢萎胰?

案例分析

要知道碾盟,在互聯(lián)網(wǎng)面試中,引入 MQ 消息中間件最直接的目的是:做系統(tǒng)解耦合流量控制技竟,追其根源還是為了解決互聯(lián)網(wǎng)系統(tǒng)的高可用和高性能問題冰肴。

  • 系統(tǒng)解耦:用 MQ 消息隊(duì)列,可以隔離系統(tǒng)上下游環(huán)境變化帶來的不穩(wěn)定因素,比如京豆服務(wù)的系統(tǒng)需求無論如何變化熙尉,交易服務(wù)不用做任何改變估盘,即使當(dāng)京豆服務(wù)出現(xiàn)故障,主交易流程也可以將京豆服務(wù)降級(jí)骡尽,實(shí)現(xiàn)交易服務(wù)和京豆服務(wù)的解耦遣妥,做到了系統(tǒng)的高可用。
  • 流量控制:遇到秒殺等流量突增的場(chǎng)景攀细,通過 MQ 還可以實(shí)現(xiàn)流量的“削峰填谷”的作用箫踩,可以根據(jù)下游的處理能力自動(dòng)調(diào)節(jié)流量。

不過引入 MQ 雖然實(shí)現(xiàn)了系統(tǒng)解耦合流量控制谭贪,也會(huì)帶來其他問題境钟。

引入 MQ 消息中間件實(shí)現(xiàn)系統(tǒng)解耦,會(huì)影響系統(tǒng)之間數(shù)據(jù)傳輸?shù)囊恢滦浴?/strong> 在分布式系統(tǒng)中俭识,如果兩個(gè)節(jié)點(diǎn)之間存在數(shù)據(jù)同步慨削,就會(huì)帶來數(shù)據(jù)一致性的問題。同理套媚,在這一講你要解決的就是:消息生產(chǎn)端和消息消費(fèi)端的消息數(shù)據(jù)一致性問題(也就是如何確保消息不丟失)缚态。

而引入 MQ 消息中間件解決流量控制 , 會(huì)使消費(fèi)端處理能力不足從而導(dǎo)致消息積壓堤瘤,這也是你要解決的問題玫芦。

所以你能發(fā)現(xiàn),問題與問題之間往往是環(huán)環(huán)相扣的本辐,面試官會(huì)借機(jī)考察你解決問題思路的連貫性和知識(shí)體系的掌握程度桥帆。

那面對(duì)“在使用 MQ 消息隊(duì)列時(shí),如何確保消息不丟失”這個(gè)問題時(shí)慎皱,你要怎么回答呢老虫?首先,你要分析其中有幾個(gè)考點(diǎn)茫多,比如:

  • 如何知道有消息丟失祈匙?
  • 哪些環(huán)節(jié)可能丟消息?
  • 如何確保消息不丟失地梨?

候選人在回答時(shí)菊卷,要先讓面試官知道你的分析思路,然后再提供解決方案 :網(wǎng)絡(luò)中的數(shù)據(jù)傳輸不可靠宝剖,想要解決如何不丟消息的問題洁闰,首先要知道哪些環(huán)節(jié)可能丟消息,以及我們?nèi)绾沃老⑹欠駚G失了万细,最后才是解決方案(而不是上來就直接說自己的解決方案)扑眉。就好比“架構(gòu)設(shè)計(jì)”“架構(gòu)”體現(xiàn)了架構(gòu)師的思考過程纸泄,而“設(shè)計(jì)”才是最后的解決方案,兩者缺一不可腰素。

案例解答

我們首先來看消息丟失的環(huán)節(jié)聘裁,一條消息從生產(chǎn)到消費(fèi)完成這個(gè)過程,可以劃分三個(gè)階段弓千,分別為消息生產(chǎn)階段衡便,消息存儲(chǔ)階段和消息消費(fèi)階段。

  • 消息生產(chǎn)階段: 從消息被生產(chǎn)出來洋访,然后提交給 MQ 的過程中镣陕,只要能正常收到 MQ Broker 的 ack 確認(rèn)響應(yīng),就表示發(fā)送成功姻政,所以只要處理好返回值和異常呆抑,這個(gè)階段是不會(huì)出現(xiàn)消息丟失的。
  • 消息存儲(chǔ)階段: 這個(gè)階段一般會(huì)直接交給 MQ 消息中間件來保證汁展,但是你要了解它的原理鹊碍,比如 Broker 會(huì)做副本,保證一條消息至少同步兩個(gè)節(jié)點(diǎn)再返回 ack食绿。
  • 消息消費(fèi)階段: 消費(fèi)端從 Broker 上拉取消息侈咕,只要消費(fèi)端在收到消息后,不立即發(fā)送消費(fèi)確認(rèn)給 Broker炫欺,而是等到執(zhí)行完業(yè)務(wù)邏輯后乎完,再發(fā)送消費(fèi)確認(rèn)熏兄,也能保證消息的不丟失品洛。

方案看似萬無一失,每個(gè)階段都能保證消息的不丟失摩桶,但在分布式系統(tǒng)中桥状,故障不可避免,作為消息生產(chǎn)端硝清,你并不能保證 MQ 是不是弄丟了你的消息辅斟,消費(fèi)者是否消費(fèi)了你的消息,所以芦拿,本著 Design for Failure 的設(shè)計(jì)原則士飒,你還是需要一種機(jī)制,來 Check 消息是否丟失了蔗崎。

緊接著酵幕,你還可以向面試官闡述怎么進(jìn)行消息檢測(cè)? 總體方案解決思路為:在消息生產(chǎn)端缓苛,給每個(gè)發(fā)出的消息都指定一個(gè)全局唯一 ID芳撒,或者附加一個(gè)連續(xù)遞增的版本號(hào),然后在消費(fèi)端做對(duì)應(yīng)的版本校驗(yàn)。

具體怎么落地實(shí)現(xiàn)呢笔刹?你可以利用攔截器機(jī)制芥备。 在生產(chǎn)端發(fā)送消息之前,通過攔截器將消息版本號(hào)注入消息中(版本號(hào)可以采用連續(xù)遞增的 ID 生成舌菜,也可以通過分布式全局唯一 ID生成)萌壳。然后在消費(fèi)端收到消息后,再通過攔截器檢測(cè)版本號(hào)的連續(xù)性或消費(fèi)狀態(tài)日月,這樣實(shí)現(xiàn)的好處是消息檢測(cè)的代碼不會(huì)侵入到業(yè)務(wù)代碼中讶凉,可以通過單獨(dú)的任務(wù)來定位丟失的消息,做進(jìn)一步的排查山孔。

這里需要你注意:如果同時(shí)存在多個(gè)消息生產(chǎn)端和消息消費(fèi)端懂讯,通過版本號(hào)遞增的方式就很難實(shí)現(xiàn)了,因?yàn)椴荒鼙WC版本號(hào)的唯一性台颠,此時(shí)只能通過全局唯一 ID 的方案來進(jìn)行消息檢測(cè)褐望,具體的實(shí)現(xiàn)原理和版本號(hào)遞增的方式一致。

現(xiàn)在串前,你已經(jīng)知道了哪些環(huán)節(jié)(消息存儲(chǔ)階段瘫里、消息消費(fèi)階段)可能會(huì)出問題,并有了如何檢測(cè)消息丟失的方案荡碾,然后就要給出解決防止消息丟失的設(shè)計(jì)方案谨读。

回答完“如何確保消息不會(huì)丟失?” 之后坛吁,面試官通常會(huì)追問“怎么解決消息被重復(fù)消費(fèi)的問題劳殖?

比如:在消息消費(fèi)的過程中,如果出現(xiàn)失敗的情況拨脉,通過補(bǔ)償?shù)臋C(jī)制發(fā)送方會(huì)執(zhí)行重試哆姻,重試的過程就有可能產(chǎn)生重復(fù)的消息,那么如何解決這個(gè)問題玫膀?

這個(gè)問題其實(shí)可以換一種說法矛缨,就是如何解決消費(fèi)端冪等性問題(冪等性,就是一條命令帖旨,任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同)箕昭,只要消費(fèi)端具備了冪等性,那么重復(fù)消費(fèi)消息的問題也就解決了解阅。

我們還是來看扣減京豆的例子落竹,將賬戶 X 的金豆個(gè)數(shù)扣減 100 個(gè),在這個(gè)例子中瓮钥,我們可以通過改造業(yè)務(wù)邏輯筋量,讓它具備冪等性烹吵。

最簡(jiǎn)單的實(shí)現(xiàn)方案,就是在數(shù)據(jù)庫(kù)中建一張消息日志表 桨武, 這個(gè)表有兩個(gè)字段:消息 ID 和消息執(zhí)行狀態(tài)肋拔。這樣,我們消費(fèi)消息的邏輯可以變?yōu)椋涸谙⑷罩颈碇性黾右粭l消息記錄呀酸,然后再根據(jù)消息記錄凉蜂,異步操作更新用戶京豆余額。

因?yàn)槲覀兠看味紩?huì)在插入之前檢查是否消息已存在性誉,所以就不會(huì)出現(xiàn)一條消息被執(zhí)行多次的情況窿吩,這樣就實(shí)現(xiàn)了一個(gè)冪等的操作。當(dāng)然错览,基于這個(gè)思路纫雁,不僅可以使用關(guān)系型數(shù)據(jù)庫(kù),也可以通過 Redis 來代替數(shù)據(jù)庫(kù)實(shí)現(xiàn)唯一約束的方案倾哺。

在這里我多說一句轧邪,想要解決“消息丟失”和“消息重復(fù)消費(fèi)”的問題,有一個(gè)前提條件就是要實(shí)現(xiàn)一個(gè)全局唯一 ID 生成的技術(shù)方案羞海。這也是面試官喜歡考察的問題忌愚,你也要掌握。

在分布式系統(tǒng)中却邓,全局唯一 ID 生成的實(shí)現(xiàn)方法有數(shù)據(jù)庫(kù)自增主鍵硕糊、UUID、Redis腊徙,Twitter-Snowflake 算法简十,我總結(jié)了幾種方案的特點(diǎn),你可以參考下昧穿。

我提醒你注意勺远,無論哪種方法,如果你想同時(shí)滿足簡(jiǎn)單时鸵、高可用和高性能,就要有取舍厅瞎,所以你要站在實(shí)際的業(yè)務(wù)中饰潜,說明你的選型所考慮的平衡點(diǎn)是什么。我個(gè)人在業(yè)務(wù)中比較傾向于選擇 Snowflake 算法和簸,在項(xiàng)目中也進(jìn)行了一定的改造彭雾,主要是讓算法中的 ID 生成規(guī)則更加符合業(yè)務(wù)特點(diǎn),以及優(yōu)化諸如時(shí)鐘回?fù)艿葐栴}锁保。

當(dāng)然薯酝,除了“怎么解決消息被重復(fù)消費(fèi)的問題半沽?”之外,面試官還會(huì)問到你“消息積壓”吴菠。 原因在于消息積壓反映的是性能問題者填,解決消息積壓?jiǎn)栴},可以說明候選者有能力處理高并發(fā)場(chǎng)景下的消費(fèi)能力問題做葵。

你在解答這個(gè)問題時(shí)占哟,依舊要傳遞給面試官一個(gè)這樣的思考過程: 如果出現(xiàn)積壓,那一定是性能問題酿矢,想要解決消息從生產(chǎn)到消費(fèi)上的性能問題榨乎,就首先要知道哪些環(huán)節(jié)可能出現(xiàn)消息積壓,然后在考慮如何解決瘫筐。

因?yàn)橄l(fā)送之后才會(huì)出現(xiàn)積壓的問題蜜暑,所以和消息生產(chǎn)端沒有關(guān)系,又因?yàn)榻^大部分的消息隊(duì)列單節(jié)點(diǎn)都能達(dá)到每秒鐘幾萬的處理能力策肝,相對(duì)于業(yè)務(wù)邏輯來說史煎,性能不會(huì)出現(xiàn)在中間件的消息存儲(chǔ)上面。毫無疑問驳糯,出問題的肯定是消息消費(fèi)階段篇梭,那么從消費(fèi)端入手,如何回答呢酝枢?

如果是線上突發(fā)問題恬偷,要臨時(shí)擴(kuò)容,增加消費(fèi)端的數(shù)量帘睦,與此同時(shí)袍患,降級(jí)一些非核心的業(yè)務(wù)。通過擴(kuò)容和降級(jí)承擔(dān)流量竣付,這是為了表明你對(duì)應(yīng)急問題的處理能力诡延。

其次,才是排查解決異常問題古胆,如通過監(jiān)控肆良,日志等手段分析是否消費(fèi)端的業(yè)務(wù)邏輯代碼出現(xiàn)了問題,優(yōu)化消費(fèi)端的業(yè)務(wù)處理邏輯逸绎。

最后惹恃,如果是消費(fèi)端的處理能力不足,可以通過水平擴(kuò)容來提供消費(fèi)端的并發(fā)處理能力棺牧,但這里有一個(gè)考點(diǎn)需要特別注意 巫糙, 那就是在擴(kuò)容消費(fèi)者的實(shí)例數(shù)的同時(shí),必須同步擴(kuò)容主題 Topic 的分區(qū)數(shù)量颊乘,確保消費(fèi)者的實(shí)例數(shù)和分區(qū)數(shù)相等参淹。如果消費(fèi)者的實(shí)例數(shù)超過了分區(qū)數(shù)醉锄,由于分區(qū)是單線程消費(fèi),所以這樣的擴(kuò)容就沒有效果浙值。

比如在 Kafka 中恳不,一個(gè) Topic 可以配置多個(gè) Partition(分區(qū)),數(shù)據(jù)會(huì)被寫入到多個(gè)分區(qū)中亥鸠,但在消費(fèi)的時(shí)候妆够,Kafka 約定一個(gè)分區(qū)只能被一個(gè)消費(fèi)者消費(fèi),Topic 的分區(qū)數(shù)量決定了消費(fèi)的能力负蚊,所以神妹,可以通過增加分區(qū)來提高消費(fèi)者的處理能力。

總結(jié)

至此,我們講解了 MQ 消息隊(duì)列的熱門問題的解決方案,無論是初中級(jí)還是高級(jí)研發(fā)工程師穴豫,本篇文章的內(nèi)容都是你需要掌握的方灾,你都可以從這幾點(diǎn)出發(fā)狂票,與面試官進(jìn)行友好的交流。我來總結(jié)一下今天的重點(diǎn)內(nèi)容。

  • 如何確保消息不會(huì)丟失? 你要知道一條消息從發(fā)送到消費(fèi)的每個(gè)階段庸疾,是否存在丟消息,以及如何監(jiān)控消息是否丟失当编,最后才是如何解決問題届慈,方案可以基于“ MQ 的可靠消息投遞 ”的方式。
  • 如何保證消息不被重復(fù)消費(fèi)忿偷? 在進(jìn)行消息補(bǔ)償?shù)臅r(shí)候金顿,一定會(huì)存在重復(fù)消息的情況,那么如何實(shí)現(xiàn)消費(fèi)端的冪等性就這道題的考點(diǎn)鲤桥。
  • 如何處理消息積壓?jiǎn)栴}揍拆? 這道題的考點(diǎn)就是如何通過 MQ 實(shí)現(xiàn)真正的高性能,回答的思路是茶凳,本著解決線上異常為最高優(yōu)先級(jí)嫂拴,然后通過監(jiān)控和日志進(jìn)行排查并優(yōu)化業(yè)務(wù)邏輯,最后是擴(kuò)容消費(fèi)端和分片的數(shù)量慧妄。

在回答問題的時(shí)候顷牌,你需要特別注意的是,讓面試官了解到你的思維過程塞淹,這種解決問題的能力是面試官更為看中的,比你直接回答一道面試題更有價(jià)值罪裹。

另外饱普,如果你應(yīng)聘的部門是基礎(chǔ)架構(gòu)部运挫,那么除了要掌握本講中的常見問題的主線知識(shí)以外,還要掌握消息中間件的其他知識(shí)體系套耕,如:

  • 如何選型消息中間件谁帕?
  • 消息中間件中的隊(duì)列模型與發(fā)布訂閱模型的區(qū)別?
  • 為什么消息隊(duì)列能實(shí)現(xiàn)高吞吐冯袍?
  • 序列化匈挖、傳輸協(xié)議,以及內(nèi)存管理等問題
  • … >
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末康愤,一起剝皮案震驚了整個(gè)濱河市儡循,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌征冷,老刑警劉巖择膝,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異检激,居然都是意外死亡肴捉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門叔收,熙熙樓的掌柜王于貴愁眉苦臉地迎上來齿穗,“玉大人,你說我怎么就攤上這事饺律∏砸常” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蓝晒,是天一觀的道長(zhǎng)腮出。 經(jīng)常有香客問我,道長(zhǎng)芝薇,這世上最難降的妖魔是什么胚嘲? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮洛二,結(jié)果婚禮上馋劈,老公的妹妹穿的比我還像新娘。我一直安慰自己晾嘶,他們只是感情好妓雾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著垒迂,像睡著了一般械姻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上机断,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天楷拳,我揣著相機(jī)與錄音绣夺,去河邊找鬼。 笑死欢揖,一個(gè)胖子當(dāng)著我的面吹牛陶耍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播她混,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烈钞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了坤按?” 一聲冷哼從身側(cè)響起毯欣,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晋涣,沒想到半個(gè)月后仪媒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谢鹊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年算吩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佃扼。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡偎巢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兼耀,到底是詐尸還是另有隱情压昼,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布瘤运,位于F島的核電站窍霞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拯坟。R本人自食惡果不足惜但金,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望郁季。 院中可真熱鬧冷溃,春花似錦、人聲如沸梦裂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽年柠。三九已至凿歼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毅往。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工牵咙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留派近,地道東北人攀唯。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像渴丸,于是被迫代替她去往敵國(guó)和親侯嘀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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