面試題
如何保證消息隊(duì)列的高可用择懂?
面試官心理分析
如果有人問(wèn)到你 MQ 的知識(shí)约啊,高可用是必問(wèn)的邑遏。上一講提到,MQ 會(huì)導(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ì)你的感覺(jué)就是萎胰,只會(huì)簡(jiǎn)單使用一些技術(shù)碾盟,沒(méi)任何思考,馬上對(duì)你的印象就不太好了技竟。這樣的同學(xué)招進(jìn)來(lái)要是做個(gè) 20k 薪資以內(nèi)的普通小弟還湊合冰肴,要是做薪資 20k+ 的高工,那就慘了榔组,讓你設(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 的高可用性
RabbitMQ 是比較有代表性的,因?yàn)槭?strong>基于主從(非分布式)做高可用性的磁椒,我們就以 RabbitMQ 為例子講解第一種 MQ 的高可用性怎么實(shí)現(xiàn)堤瘤。
RabbitMQ 有三種模式:?jiǎn)螜C(jī)模式、普通集群模式浆熔、鏡像集群模式本辐。
單機(jī)模式
單機(jī)模式,就是 Demo 級(jí)別的医增,一般就是你本地啟動(dòng)了玩玩兒的??慎皱,沒(méi)人生產(chǎn)用單機(jī)模式。
普通集群模式(無(wú)高可用性)
普通集群模式叶骨,意思就是在多臺(tái)機(jī)器上啟動(dòng)多個(gè) RabbitMQ 實(shí)例茫多,每個(gè)機(jī)器啟動(dòng)一個(gè)。你創(chuàng)建的 queue忽刽,只會(huì)放在一個(gè) RabbitMQ 實(shí)例上天揖,但是每個(gè)實(shí)例都同步 queue 的元數(shù)據(jù)(元數(shù)據(jù)可以認(rèn)為是 queue 的一些配置信息,通過(guò)元數(shù)據(jù)跪帝,可以找到 queue 所在實(shí)例)今膊。你消費(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)銷(xiāo),后者導(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 的讀寫(xiě)操作食绿。
鏡像集群模式(高可用性)
這種模式,才是所謂的 RabbitMQ 的高可用模式公罕。跟普通集群模式不一樣的是器紧,在鏡像集群模式下,你創(chuàng)建的 queue楼眷,無(wú)論元數(shù)據(jù)還是 queue 里的消息都會(huì)存在于多個(gè)實(shí)例上铲汪,就是說(shuō),每個(gè) RabbitMQ 節(jié)點(diǎn)都有這個(gè) queue 的一個(gè)完整鏡像罐柳,包含 queue 的全部數(shù)據(jù)的意思桥状。然后每次你寫(xiě)消息到 queue 的時(shí)候,都會(huì)自動(dòng)把消息同步到多個(gè)實(shí)例的 queue 上硝清。
那么如何開(kāi)啟這個(gè)鏡像集群模式呢辅斟?其實(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)上去了芳撒。
這樣的話,好處在于未桥,你任何一個(gè)機(jī)器宕機(jī)了笔刹,沒(méi)事兒,其它機(jī)器(節(jié)點(diǎn))還包含了這個(gè) queue 的完整數(shù)據(jù)冬耿,別的 consumer 都可以到其它節(jié)點(diǎn)上去消費(fèi)數(shù)據(jù)舌菜。壞處在于,第一亦镶,這個(gè)性能開(kāi)銷(xiāo)也太大了吧日月,消息需要同步到所有機(jī)器上,導(dǎo)致網(wǎng)絡(luò)帶寬壓力和消耗很重缤骨!第二爱咬,這么玩兒,不是分布式的绊起,就沒(méi)有擴(kuò)展性可言了精拟,如果某個(gè) queue 負(fù)載很重,你加機(jī)器,新增的機(jī)器也包含了這個(gè) queue 的所有數(shù)據(jù)串前,并沒(méi)有辦法線性擴(kuò)展你的 queue。你想实蔽,如果這個(gè) queue 的數(shù)據(jù)量很大荡碾,大到這個(gè)機(jī)器上的容量無(wú)法容納了,此時(shí)該怎么辦呢局装?
Kafka 的高可用性
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í)際上 RabbmitMQ 之類(lèi)的,并不是分布式消息隊(duì)列灵妨,它就是傳統(tǒng)的消息隊(duì)列解阅,只不過(guò)提供了一些集群、HA(High Availability, 高可用性) 的機(jī)制而已泌霍,因?yàn)闊o(wú)論怎么玩兒货抄,RabbitMQ 一個(gè) queue 的數(shù)據(jù)都是放在一個(gè)節(jié)點(diǎn)里的,鏡像集群下朱转,也是每個(gè)節(jié)點(diǎn)都放這個(gè) queue 的完整數(shù)據(jù)蟹地。
Kafka 0.8 以前,是沒(méi)有 HA 機(jī)制的藤为,就是任何一個(gè) broker 宕機(jī)了锈津,那個(gè) broker 上的 partition 就廢了,沒(méi)法寫(xiě)也沒(méi)法讀凉蜂,沒(méi)有什么高可用性可言琼梆。
比如說(shuō),我們假設(shè)創(chuàng)建了一個(gè) topic窿吩,指定其 partition 數(shù)量是 3 個(gè)茎杂,分別在三臺(tái)機(jī)器上。但是纫雁,如果第二臺(tái)機(jī)器宕機(jī)了煌往,會(huì)導(dǎo)致這個(gè) topic 的 1/3 的數(shù)據(jù)就丟了,因此這個(gè)是做不到高可用的。
Kafka 0.8 以后刽脖,提供了 HA 機(jī)制羞海,就是 replica(復(fù)制品) 副本機(jī)制。每個(gè) partition 的數(shù)據(jù)都會(huì)同步到其它機(jī)器上曲管,形成自己的多個(gè) replica 副本却邓。所有 replica 會(huì)選舉一個(gè) leader 出來(lái),那么生產(chǎn)和消費(fèi)都跟這個(gè) leader 打交道院水,然后其他 replica 就是 follower腊徙。寫(xiě)的時(shí)候,leader 會(huì)負(fù)責(zé)把數(shù)據(jù)同步到所有 follower 上去檬某,讀的時(shí)候就直接讀 leader 上的數(shù)據(jù)即可撬腾。只能讀寫(xiě) leader?很簡(jiǎn)單恢恼,要是你可以隨意讀寫(xiě)每個(gè) follower民傻,那么就要 care 數(shù)據(jù)一致性的問(wèn)題,系統(tǒng)復(fù)雜度太高场斑,很容易出問(wèn)題饰潜。Kafka 會(huì)均勻地將一個(gè) partition 的所有 replica 分布在不同的機(jī)器上,這樣才可以提高容錯(cuò)性和簸。
這么搞彭雾,就有所謂的高可用性了,因?yàn)槿绻硞€(gè) broker 宕機(jī)了锁保,沒(méi)事兒薯酝,那個(gè) broker上面的 partition 在其他機(jī)器上都有副本的,如果這上面有某個(gè) partition 的 leader爽柒,那么此時(shí)會(huì)從 follower 中重新選舉一個(gè)新的 leader 出來(lái)吴菠,大家繼續(xù)讀寫(xiě)那個(gè)新的 leader 即可。這就有所謂的高可用性了浩村。
寫(xiě)數(shù)據(jù)的時(shí)候做葵,生產(chǎn)者就寫(xiě) leader,然后 leader 將數(shù)據(jù)落地寫(xiě)本地磁盤(pán)心墅,接著其他 follower 自己主動(dòng)從 leader 來(lái) pull 數(shù)據(jù)酿矢。一旦所有 follower 同步好數(shù)據(jù)了,就會(huì)發(fā)送 ack 給 leader怎燥,leader 收到所有 follower 的 ack 之后瘫筐,就會(huì)返回寫(xiě)成功的消息給生產(chǎn)者。(當(dāng)然铐姚,這只是其中一種模式策肝,還可以適當(dāng)調(diào)整這個(gè)行為)
消費(fèi)的時(shí)候,只會(huì)從 leader 去讀,但是只有當(dāng)一個(gè)消息已經(jīng)被所有 follower 都同步成功返回 ack 的時(shí)候之众,這個(gè)消息才會(huì)被消費(fèi)者讀到拙毫。
看到這里,相信你大致明白了 Kafka 是如何保證高可用機(jī)制的了棺禾,對(duì)吧缀蹄?不至于一無(wú)所知,現(xiàn)場(chǎng)還能給面試官畫(huà)畫(huà)圖帘睦。要是遇上面試官確實(shí)是 Kafka 高手,深挖了問(wèn)坦康,那你只能說(shuō)不好意思竣付,太深入的你沒(méi)研究過(guò)。