面試必問(wèn) | 如何設(shè)計(jì)一款高并發(fā)的消息中間件?
大家好,我是冰河~~
很多小伙伴去大廠(chǎng)面試,幾乎都會(huì)遇到一些開(kāi)放式的題目,這些開(kāi)放式的題目沒(méi)有固定的答案,但是它能夠?qū)崒?shí)在在的體現(xiàn)面試者較為真實(shí)的系統(tǒng)設(shè)計(jì)能力和技術(shù)功底。如果你回答的比較完美,那么,通過(guò)這種開(kāi)放式題目,就能夠讓你從眾多的面試者中脫穎而出。
今天,我們就一起來(lái)聊聊,去大廠(chǎng)面試時(shí),一個(gè)較為常見(jiàn)的開(kāi)放式題目:如果讓你設(shè)計(jì)一個(gè)高并發(fā)的消息中間件,你會(huì)怎么做?
消息中間件涉及的知識(shí)點(diǎn)
要想設(shè)計(jì)一個(gè)具有高并發(fā)的消息中間件,那么首先就要了解下消息中間件涉及哪些具體的知識(shí)點(diǎn)。通常,設(shè)計(jì)一個(gè)良好的消息中間件最少需要滿(mǎn)足如下條件:
- 生產(chǎn)者、消費(fèi)者模型。
- 支持分布式架構(gòu)。
- 數(shù)據(jù)的高可用。
- 消息數(shù)據(jù)不丟失。
接下來(lái),我們就針對(duì)消息中間件來(lái)分別談?wù)勥@些技術(shù)點(diǎn)。
生產(chǎn)者消費(fèi)者模型
相信很多小伙伴對(duì)于生產(chǎn)者和消費(fèi)者模型都比較了解了,簡(jiǎn)單的說(shuō):就是消息中間件能夠使其他應(yīng)用來(lái)生產(chǎn)消息,也能夠使其他應(yīng)用來(lái)消費(fèi)相應(yīng)的消息。
對(duì)于生產(chǎn)者和消費(fèi)者模型,我們需要考慮的問(wèn)題點(diǎn)就比較多了。接下來(lái),我就一步步來(lái)引導(dǎo)大家進(jìn)行思考。
首先,我們來(lái)思考這樣一個(gè)問(wèn)題:如果生產(chǎn)者生產(chǎn)了消息,那么消息中間件應(yīng)該怎樣存儲(chǔ)相應(yīng)的數(shù)據(jù)呢?存儲(chǔ)在內(nèi)存? 存儲(chǔ)在磁盤(pán)?還是同時(shí)存儲(chǔ)在內(nèi)存和磁盤(pán)中呢?
如果是將消息數(shù)據(jù)同時(shí)存儲(chǔ)在內(nèi)存和磁盤(pán)中,我們又該如何處理這些數(shù)據(jù)呢?是生產(chǎn)者將消息投遞到消息中間件之后,我們就立刻將數(shù)據(jù)寫(xiě)入磁盤(pán)?還是說(shuō)數(shù)據(jù)先駐留到內(nèi)存,然后每隔一段時(shí)間刷到磁盤(pán)上?
如果是每隔一段時(shí)間刷到磁盤(pán)上,那我們又要考慮磁盤(pán)文件的切分問(wèn)題,也就是說(shuō),需要將消息數(shù)據(jù)分成多少個(gè)磁盤(pán)文件?(總不能把所有的數(shù)據(jù)放到一個(gè)磁盤(pán)文件中吧)。如果是需要切分成多個(gè)磁盤(pán)文件,那切分的規(guī)則又是什么呢?
上面這些問(wèn)題都是我們?cè)谠O(shè)計(jì)一個(gè)消息中間件時(shí)需要考慮的問(wèn)題。然而,這還只是一小部分問(wèn)題。如果想在面試時(shí)脫穎而出,那就還需要繼續(xù)往下看,還有一些重要的問(wèn)題點(diǎn)需要注意。
如果文件按照一定的規(guī)則切分到多個(gè)磁盤(pán)文件中了,那是不是還需要管理元數(shù)據(jù)來(lái)標(biāo)識(shí)數(shù)據(jù)的具體消息(就像是Hadoop中的NameNode節(jié)點(diǎn)中存儲(chǔ)著DataNode的元數(shù)據(jù)信息,NameNode節(jié)點(diǎn)通過(guò)這些元數(shù)據(jù)信息就能夠更好的管理DataNode節(jié)點(diǎn))?
這些元數(shù)據(jù)可以包括:消息數(shù)據(jù)的偏移量、也可以是消息數(shù)據(jù)的唯一ID。
考慮完數(shù)據(jù)的存儲(chǔ)問(wèn)題,我們還需要考慮的是:消息中間件是如何將數(shù)據(jù)投遞到對(duì)應(yīng)的消費(fèi)者的?
在設(shè)計(jì)生產(chǎn)者和消費(fèi)者時(shí),還一個(gè)很重要的問(wèn)題需要我們考慮:我們?cè)谠O(shè)計(jì)消息中間件時(shí),采用的消費(fèi)模式是什么?會(huì)不會(huì)將數(shù)據(jù)均勻的分配給消費(fèi)者?還是會(huì)通過(guò)一些其他的規(guī)則將數(shù)據(jù)投遞到消費(fèi)者?
支持分布式架構(gòu)
如果我們?cè)O(shè)計(jì)的消息中間件,每天會(huì)承載TB級(jí)別的數(shù)據(jù)高并發(fā)和高吞吐量的寫(xiě)入操作。這里,我們就需要考慮將消息中間件設(shè)計(jì)成分布式架構(gòu)。
在設(shè)計(jì)分布式架構(gòu)時(shí),我們還需要考慮將存儲(chǔ)的比較大的數(shù)據(jù),做成分片存儲(chǔ),對(duì)數(shù)據(jù)進(jìn)行分片等操作。
除了這些,我們還需要考慮另外一個(gè)核心問(wèn)題:對(duì)于消息中間件來(lái)說(shuō),需要支持自動(dòng)擴(kuò)容操作。
還有就是是否支持?jǐn)?shù)據(jù)分片,如何實(shí)現(xiàn)數(shù)據(jù)分片的擴(kuò)容和自動(dòng)數(shù)據(jù)負(fù)載均衡遷移等。
數(shù)據(jù)的高可用
一般互聯(lián)網(wǎng)應(yīng)用的高可用,是通過(guò)本地堆內(nèi)存,分布式緩存,和一份數(shù)據(jù)在不同的服務(wù)器上都搞一個(gè)副本來(lái)實(shí)現(xiàn)的。此時(shí),任何一個(gè)存儲(chǔ)節(jié)點(diǎn)宕機(jī),都不會(huì)影響整體的高可用。我們?cè)谠O(shè)計(jì)消息中間件時(shí)也可以參考這個(gè)思路。
消息數(shù)據(jù)不丟失
此時(shí),我們就需要提供手動(dòng)ACK的機(jī)制,也就是說(shuō):當(dāng)消費(fèi)者真正消費(fèi)消息完畢后,向消息中間件返回“ 處理完成” 的標(biāo)識(shí),消息中間件刪除相應(yīng)的已處理的消息。
但是,細(xì)化的話(huà),這里,我們就需要兩套ACK機(jī)制:
一種ACK對(duì)應(yīng)的是生產(chǎn)端。如果一直沒(méi)有接收到ACK消息,則需要通過(guò)生產(chǎn)者來(lái)重新發(fā)送一條消息來(lái)保證生產(chǎn)消息成功。
另一種ACK對(duì)應(yīng)的是消費(fèi)端。一旦一條消息消費(fèi)并處理成功,必須返回一個(gè)ack給消息中間件,然后消息中間件才能刪除這條消息。否則一旦消費(fèi)者宕機(jī),就必須重發(fā)這條消息給其他的消費(fèi)者實(shí)例,保證消息一定會(huì)被處理成功。
今天,我們沒(méi)有聊具體的業(yè)務(wù)點(diǎn),而是從整體上考慮:如果實(shí)現(xiàn)一個(gè)消息中間件,需要我們注意的各項(xiàng)知識(shí)點(diǎn)和專(zhuān)業(yè)技能!