如果有人問(wèn)到你MQ的知識(shí),高可用是必問(wèn)的,因?yàn)镸Q的缺點(diǎn),我剛才已經(jīng)說(shuō)過(guò)了,有好多,導(dǎo)致系統(tǒng)可用性降低,等等。所以只要你用了MQ,接下來(lái)問(wèn)的一些要點(diǎn)肯定就是圍繞著MQ的那些缺點(diǎn)怎么來(lái)解決了。要是你傻乎乎的就干用了一個(gè)MQ,各種問(wèn)題從來(lái)沒(méi)考慮過(guò),那你就悲劇了,面試官對(duì)你的印象就是,只會(huì)簡(jiǎn)單實(shí)用一些技術(shù),沒(méi)任何思考,馬上對(duì)你的印象就不太好了。這樣的同學(xué)招進(jìn)來(lái)要是做個(gè)20k薪資以內(nèi)的普通小弟還湊合。如果招進(jìn)來(lái)做薪資20多k的高工,那就慘了,讓你設(shè)計(jì)個(gè)系統(tǒng),里面肯定一堆坑,出了事故公司受損失,團(tuán)隊(duì)一起背鍋。
這個(gè)問(wèn)題這么問(wèn)是很好的,因?yàn)椴荒軉?wèn)你kafka的高可用性怎么保證?ActiveMQ的高可用性怎么保證?一個(gè)面試官要是這么問(wèn)就顯得很沒(méi)水平,人家可能用的就是RabbitMQ,沒(méi)用過(guò)Kafka,你上來(lái)問(wèn)人家kafka干什么?這不是擺明了刁難人么。所以有水平的面試官,問(wèn)的是MQ的高可用性怎么保證?這樣就是你用過(guò)哪個(gè)MQ,你就說(shuō)說(shuō)你對(duì)那個(gè)MQ的高可用性的理解。
RabbitMQ是比較有代表性的,因?yàn)槭腔谥鲝淖龈呖捎眯缘,我們就以他為例子講解第一種MQ的高可用性怎么實(shí)現(xiàn)。
2)普通集群模式:就是在多臺(tái)機(jī)器上啟動(dòng)多個(gè)rabbitmq實(shí)例,每個(gè)機(jī)器啟動(dòng)一個(gè)。但是你創(chuàng)建的queue,只會(huì)放在一個(gè)rabbtimq實(shí)例上,但是每個(gè)實(shí)例都同步queue的元數(shù)據(jù)。完了你消費(fèi)的時(shí)候,實(shí)際上如果連接到了另外一個(gè)實(shí)例,那么那個(gè)實(shí)例會(huì)從queue所在實(shí)例上拉取數(shù)據(jù)過(guò)來(lái)。這種方式確實(shí)很麻煩,也不怎么好,沒(méi)做到所謂的分布式,就是個(gè)普通集群。因?yàn)檫@導(dǎo)致你要么消費(fèi)者每次隨機(jī)連接一個(gè)實(shí)例然后拉取數(shù)據(jù),要么固定連接那個(gè)queue所在實(shí)例消費(fèi)數(shù)據(jù),前者有數(shù)據(jù)拉取的開(kāi)銷,后者導(dǎo)致單實(shí)例性能瓶頸。而且如果那個(gè)放queue的實(shí)例宕機(jī)了,會(huì)導(dǎo)致接下來(lái)其他實(shí)例就無(wú)法從那個(gè)實(shí)例拉取,如果你開(kāi)啟了消息持久化,讓rabbitmq落地存儲(chǔ)消息的話,消息不一定會(huì)丟,得等這個(gè)實(shí)例恢復(fù)了,然后才可以繼續(xù)從這個(gè)queue拉取數(shù)據(jù)。所以這個(gè)事兒就比較尷尬了,這就沒(méi)有什么所謂的高可用性可言了,這方案主要是提高吞吐量的,就是說(shuō)讓集群中多個(gè)節(jié)點(diǎn)來(lái)服務(wù)某個(gè)queue的讀寫操作。
3)鏡像集群模式:這種模式,才是所謂的rabbitmq的高可用模式,跟普通集群模式不一樣的是,你創(chuàng)建的queue,無(wú)論元數(shù)據(jù)還是queue里的消息都會(huì)存在于多個(gè)實(shí)例上,然后每次你寫消息到queue的時(shí)候,都會(huì)自動(dòng)把消息到多個(gè)實(shí)例的queue里進(jìn)行消息同步。這樣的話,好處在于,你任何一個(gè)機(jī)器宕機(jī)了,沒(méi)事兒,別的機(jī)器都可以用。壞處在于,第一,這個(gè)性能開(kāi)銷也太大了吧,消息同步所有機(jī)器,導(dǎo)致網(wǎng)絡(luò)帶寬壓力和消耗很重!第二,這么玩兒,就沒(méi)有擴(kuò)展性可言了,如果某個(gè)queue負(fù)載很重,你加機(jī)器,新增的機(jī)器也包含了這個(gè)queue的所有數(shù)據(jù),并沒(méi)有辦法線性擴(kuò)展你的queue。那么怎么開(kāi)啟這個(gè)鏡像集群模式呢?我這里簡(jiǎn)單說(shuō)一下,避免面試人家問(wèn)你你不知道,其實(shí)很簡(jiǎn)單rabbitmq有很好的管理控制臺(tái),就是在后臺(tái)新增一個(gè)策略,這個(gè)策略是鏡像集群模式的策略,指定的時(shí)候可以要求數(shù)據(jù)同步到所有節(jié)點(diǎn)的,也可以要求就同步到指定數(shù)量的節(jié)點(diǎn),然后你再次創(chuàng)建queue的時(shí)候,應(yīng)用這個(gè)策略,就會(huì)自動(dòng)將數(shù)據(jù)同步到其他的節(jié)點(diǎn)上去了。
1)kafka一個(gè)最基本的架構(gòu)認(rèn)識(shí):多個(gè)broker組成,每個(gè)broker是一個(gè)節(jié)點(diǎn);你創(chuàng)建一個(gè)topic,這個(gè)topic可以劃分為多個(gè)partition,每個(gè)partition可以存在于不同的broker上,每個(gè)partition就放一部分?jǐn)?shù)據(jù)。這就是天然的分布式消息隊(duì)列,就是說(shuō)一個(gè)topic的數(shù)據(jù),是分散放在多個(gè)機(jī)器上的,每個(gè)機(jī)器就放一部分?jǐn)?shù)據(jù)。實(shí)際上rabbitmq之類的,并不是分布式消息隊(duì)列,他就是傳統(tǒng)的消息隊(duì)列,只不過(guò)提供了一些集群、HA的機(jī)制而已,因?yàn)闊o(wú)論怎么玩兒,rabbitmq一個(gè)queue的數(shù)據(jù)都是放在一個(gè)節(jié)點(diǎn)里的,鏡像集群下,也是每個(gè)節(jié)點(diǎn)都放這個(gè)queue的完整數(shù)據(jù)。
2)kafka 0.8以前,是沒(méi)有HA機(jī)制的,就是任何一個(gè)broker宕機(jī)了,那個(gè)broker上的partition就廢了,沒(méi)法寫也沒(méi)法讀,沒(méi)有什么高可用性可言。kafka 0.8以后,提供了HA機(jī)制,就是replica副本機(jī)制。每個(gè)partition的數(shù)據(jù)都會(huì)同步到其它機(jī)器上,形成自己的多個(gè)replica副本。然后所有replica會(huì)選舉一個(gè)leader出來(lái),那么生產(chǎn)和消費(fèi)都跟這個(gè)leader打交道,然后其他replica就是follower。寫的時(shí)候,leader會(huì)負(fù)責(zé)把數(shù)據(jù)同步到所有follower上去,讀的時(shí)候就直接讀leader上數(shù)據(jù)即可。只能讀寫leader?很簡(jiǎn)單,要是你可以隨意讀寫每個(gè)follower,那么就要care數(shù)據(jù)一致性的問(wèn)題,系統(tǒng)復(fù)雜度太高,很容易出問(wèn)題。kafka會(huì)均勻的將一個(gè)partition的所有replica分布在不同的機(jī)器上,這樣才可以提高容錯(cuò)性。
3)這么搞,就有所謂的高可用性了,因?yàn)槿绻硞(gè)broker宕機(jī)了,沒(méi)事兒,那個(gè)broker上面的partition在其他機(jī)器上都有副本的,如果這上面有某個(gè)partition的leader,那么此時(shí)會(huì)重新選舉一個(gè)新的leader出來(lái),大家繼續(xù)讀寫那個(gè)新的leader即可。這就有所謂的高可用性了。
寫數(shù)據(jù)的時(shí)候,生產(chǎn)者就寫leader,然后leader將數(shù)據(jù)落地寫本地磁盤,接著其他follower自己主動(dòng)從leader來(lái)pull數(shù)據(jù)。一旦所有follower同步好數(shù)據(jù)了,就會(huì)發(fā)送ack給leader,leader收到所有follower的ack之后,就會(huì)返回寫成功的消息給生產(chǎn)者。(當(dāng)然,這只是其中一種模式,還可以適當(dāng)調(diào)整這個(gè)行為)
消費(fèi)的時(shí)候,只會(huì)從leader去讀,但是只有一個(gè)消息已經(jīng)被所有follower都同步成功返回ack的時(shí)候,這個(gè)消息才會(huì)被消費(fèi)者讀到。