本文介紹最近幾年美團(tuán)點(diǎn)評MySQL數(shù)據(jù)庫高可用架構(gòu)的演進(jìn)過程,以及我們在開源技術(shù)基礎(chǔ)上做的一些創(chuàng)新。同時(shí),也和業(yè)界其它方案進(jìn)行綜合對比,了解業(yè)界在高可用方面的進(jìn)展,和未來我們的一些規(guī)劃和展望。
MMM
在2015年之前,美團(tuán)點(diǎn)評(點(diǎn)評側(cè))長期使用MMM(Master-Master replication manager for MySQL)做數(shù)據(jù)庫高可用,積累了比較多的經(jīng)驗(yàn),也踩了不少坑,可以說MMM在公司數(shù)據(jù)庫高速發(fā)展過程中起到了很大的作用。
MMM的架構(gòu)如下。
如上所示,整個(gè)MySQL集群提供1個(gè)寫VIP(Virtual IP)和N(N>=1)個(gè)讀VIP提供對外服務(wù)。每個(gè)MySQL節(jié)點(diǎn)均部署有一個(gè)Agent(mmm-agent),mmm-agent和mmm-manager保持通信狀態(tài),定期向mmm-manager上報(bào)當(dāng)前MySQL節(jié)點(diǎn)的存活情況(這里稱之為心跳)。當(dāng)mmm-manager連續(xù)多次無法收到mmm-agent的心跳消息時(shí),會(huì)進(jìn)行切換操作。
mmm-manager分兩種情況處理出現(xiàn)的異常。
出現(xiàn)異常的是從節(jié)點(diǎn)
mmm-manager會(huì)嘗試摘掉該從節(jié)點(diǎn)的讀VIP,并將該讀VIP漂移到其它存活的節(jié)點(diǎn)上,通過這種方式實(shí)現(xiàn)從庫的高可用。
出現(xiàn)異常的是主節(jié)點(diǎn)
如果當(dāng)時(shí)節(jié)點(diǎn)還沒完全掛,只是響應(yīng)超時(shí)。則嘗試將Dead Master加上全局鎖(flush tables with read lock)。
在從節(jié)點(diǎn)中選擇一個(gè)候選主節(jié)點(diǎn)作為新的主節(jié)點(diǎn),進(jìn)行數(shù)據(jù)補(bǔ)齊。
數(shù)據(jù)補(bǔ)齊之后,摘掉Dead Master的寫VIP,并嘗試加到新的主節(jié)點(diǎn)上。
將其它存活的節(jié)點(diǎn)進(jìn)行數(shù)據(jù)補(bǔ)齊,并重新掛載在新的主節(jié)點(diǎn)上。
主庫發(fā)生故障后,整個(gè)集群狀態(tài)變化如下:
mmm-manager檢測到master1發(fā)生了故障,對數(shù)據(jù)進(jìn)行補(bǔ)齊之后,將寫VIP漂移到了master2上,應(yīng)用寫操作在新的節(jié)點(diǎn)上繼續(xù)進(jìn)行。
然而,MMM架構(gòu)存在如下問題:
VIP的數(shù)量過多,管理困難(曾經(jīng)有一個(gè)集群是1主6從,共計(jì)7個(gè)VIP)。某些情況下會(huì)導(dǎo)致集群大部分VIP同時(shí)丟失,很難分清節(jié)點(diǎn)上之前使用的是哪個(gè)VIP。
mmm-agent過度敏感,容易導(dǎo)致VIP丟失。同時(shí)mmm-agent自身由于沒有高可用,一旦掛掉,會(huì)造成mmm-manager誤判,誤認(rèn)為MySQL節(jié)點(diǎn)異常。
mmm-manager存在單點(diǎn),一旦由于某些原因掛掉,整個(gè)集群就失去了高可用。
VIP需要使用ARP協(xié)議,跨網(wǎng)段、跨機(jī)房的高可用基本無法實(shí)現(xiàn),保障能力有限。
在此我向大家推薦一個(gè)架構(gòu)學(xué)習(xí)交流圈。交流學(xué)習(xí)企鵝圈號:948368769 里面會(huì)分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多
同時(shí),MMM是Google技術(shù)團(tuán)隊(duì)開發(fā)的一款比較老的高可用產(chǎn)品,在業(yè)內(nèi)使用的并不多,社區(qū)也不活躍,Google很早就不再維護(hù)MMM的代碼分支。我們在使用過程中發(fā)現(xiàn)大量Bug,部分Bug我們做了修改,并提交到開源社區(qū),有興趣的同學(xué)可以參考這里。
MHA
針對于此,從2015年開始,美團(tuán)點(diǎn)評對MySQL高可用架構(gòu)進(jìn)行了改進(jìn),全部更新為MHA,很大程度上解決了之前MMM遇到的各種問題。
MHA(MySQL Master High Availability)是由Facebook工程師Yoshinori Matsunobu開發(fā)的一款MySQL高可用軟件。從名字就可以看出,MHA只負(fù)責(zé)MySQL主庫的高可用。主庫發(fā)生故障時(shí),MHA會(huì)選擇一個(gè)數(shù)據(jù)最接近原主庫的候選主節(jié)點(diǎn)(這里只有一個(gè)從節(jié)點(diǎn),所以該從節(jié)點(diǎn)即為候選主節(jié)點(diǎn))作為新的主節(jié)點(diǎn),并補(bǔ)齊和之前Dead Master 差異的Binlog。數(shù)據(jù)補(bǔ)齊之后,即將寫VIP漂移到新主庫上。
整個(gè)MHA的架構(gòu)如下(為簡單起見,只描述一主一從):
這里我們對MHA做了一些優(yōu)化,避免一些腦裂問題。
比如DB服務(wù)器的上聯(lián)交換機(jī)出現(xiàn)了抖動(dòng),導(dǎo)致主庫無法訪問,被管理節(jié)點(diǎn)判定為故障,觸發(fā)MHA切換,VIP被漂到了新主庫上。隨后交換機(jī)恢復(fù),主庫可被訪問,但由于VIP并沒有從主庫上摘除,因此2臺(tái)機(jī)器同時(shí)擁有VIP,會(huì)產(chǎn)生腦裂。我們對MHA Manager加入了向同機(jī)架上其他物理機(jī)的探測,通過對比更多的信息來判斷是網(wǎng)絡(luò)故障還是單機(jī)故障。
MHA+Zebra (DAL)
Zebra(斑馬)是美團(tuán)點(diǎn)評基礎(chǔ)架構(gòu)團(tuán)隊(duì)開發(fā)的一個(gè)Java數(shù)據(jù)庫訪問中間件,是在c3p0基礎(chǔ)上包裝的美團(tuán)點(diǎn)評內(nèi)部使用的動(dòng)態(tài)數(shù)據(jù)源,包括讀寫分離、分庫分表、SQL流控等非常強(qiáng)的功能。它和MHA配合,成為了MySQL數(shù)據(jù)庫高可用的重要一環(huán)。如下是MHA+Zebra配合的整體架構(gòu):
還是以主庫發(fā)生故障為例,處理邏輯有如下兩種方式:
當(dāng)MHA切換完成之后,主動(dòng)發(fā)送消息給Zebra monitor,Zebra monitor更新ZooKeeper的配置,將主庫上配置的讀流量標(biāo)記為下線狀態(tài)。
Zebra monitor每隔一段時(shí)間(10s ~ 40s)檢測集群中節(jié)點(diǎn)的健康狀況,一旦發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)出現(xiàn)了問題,及時(shí)刷新ZooKeeper中的配置,將該節(jié)點(diǎn)標(biāo)記為下線。
一旦節(jié)點(diǎn)變更完成,客戶端監(jiān)聽到節(jié)點(diǎn)發(fā)生了變更,會(huì)立即使用新的配置重建連接,而老的連接會(huì)逐步關(guān)閉。整個(gè)集群故障切換的過程如下(僅描述Zebra monitor主動(dòng)探測的情況,第一種MHA通知請自行腦補(bǔ)^_^)。
由于該切換過程還是借助于VIP漂移,導(dǎo)致只能在同網(wǎng)段或者說同個(gè)二層交換機(jī)下進(jìn)行,無法做到跨網(wǎng)段或者跨機(jī)房的高可用。為解決這個(gè)問題,我們對MHA進(jìn)行了二次開發(fā),將MHA添加VIP的操作去掉,切換完之后通知Zebra monitor去重新調(diào)整節(jié)點(diǎn)的讀寫信息(將Write調(diào)整為new master的實(shí)IP,將Dead Master的讀流量摘除),整個(gè)切換就完全去VIP化,做到跨網(wǎng)段、甚至跨機(jī)房切換,徹底解決之前高可用僅局限于同網(wǎng)段的問題。上述切換過程就變成了如下圖。
然而,這種方式中的MHA管理節(jié)點(diǎn)是單點(diǎn),在網(wǎng)絡(luò)故障或者機(jī)器宕機(jī)情況下依然存在風(fēng)險(xiǎn)。同時(shí),由于Master-Slave之間是基于Binlog的異步復(fù)制,也就導(dǎo)致了主庫機(jī)器宕機(jī)或者主庫無法訪問時(shí),MHA切換過程中可能導(dǎo)致數(shù)據(jù)丟失。
另外,當(dāng)Master-Slave延遲太大時(shí),也會(huì)給數(shù)據(jù)補(bǔ)齊這一操作帶來額外的時(shí)間開銷。
Proxy
除了Zebra中間件,美團(tuán)點(diǎn)評還有一套基于Proxy的中間件,和MHA一起配合使用。當(dāng)MHA切換后,主動(dòng)通知Proxy來進(jìn)行讀寫流量調(diào)整,Proxy相比Zebra更加靈活,同時(shí)也能覆蓋非Java應(yīng)用場景。缺點(diǎn)就是訪問鏈路多了一層,對應(yīng)的Response Time和故障率也有一定增加。有興趣的同學(xué)們可以自行前往GitHub查詢詳細(xì)文檔。
未來架構(gòu)設(shè)想
上文提到的MHA架構(gòu)依然存在如下兩個(gè)問題:
管理節(jié)點(diǎn)單點(diǎn)。
MySQL異步復(fù)制中的數(shù)據(jù)丟失。
針對于此,我們在部分核心業(yè)務(wù)上使用Semi-Sync,可以保證95%以上場景下數(shù)據(jù)不丟失(依然存在一些極端情況下無法保障數(shù)據(jù)的強(qiáng)一致性)。另外,高可用使用分布式的Agent,在某個(gè)節(jié)點(diǎn)發(fā)生故障后,通過一定的選舉協(xié)議來選擇新的Master,從而解決了MHA Manager的單點(diǎn)問題。在此我向大家推薦一個(gè)架構(gòu)學(xué)習(xí)交流圈。交流學(xué)習(xí)企鵝圈號:948368769 里面會(huì)分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多
針對上述問題,我們研究了業(yè)界的一些領(lǐng)先的做法,簡單描述如下。
主從同步數(shù)據(jù)丟失
針對主從同步的數(shù)據(jù)丟失,一種做法是創(chuàng)建一個(gè)Binlog Server,該Server模擬Slave接受Binlog日志,主庫每次的數(shù)據(jù)寫入都需要接收到Binlog Server的ACK應(yīng)答,才認(rèn)為寫入成功。Binlog Server可以部署在就近的物理節(jié)點(diǎn)上,從而保證每次數(shù)據(jù)寫入都能快速落地到Binlog Server。在發(fā)生故障時(shí),只需要從Binlog Server拉取數(shù)據(jù)即可保證數(shù)據(jù)不丟失。
分布式Agent高可用
針對MHA管理節(jié)點(diǎn)單點(diǎn)問題,一種做法是讓MySQL數(shù)據(jù)庫集群中每個(gè)節(jié)點(diǎn)部署Agent,發(fā)生故障時(shí)每個(gè)Agent均參與選舉投票,選舉出合適的Slave作為新的主庫,防止只通過Manager來切換,去除MHA單點(diǎn)。整個(gè)架構(gòu)如下圖所示。
MGR結(jié)合中間件高可用
上述方式某種程度上解決了之前的問題,但是Agent和Binlog Server卻是新引入的風(fēng)險(xiǎn),同時(shí)Binlog Server的存在,也帶來了響應(yīng)時(shí)間上的額外開銷。有沒有一種方式,能夠去除Binlog Server和Agent,又能保證數(shù)據(jù)不丟失呢 ?答案當(dāng)然是有的。
最近幾年,MySQL社區(qū)關(guān)于分布式協(xié)議Raft和Paxos非?;?,社區(qū)也推出了基于Paxos的MGR版本的MySQL,通過Paxos將一致性和切換過程下推到數(shù)據(jù)庫內(nèi)部,向上層屏蔽了切換細(xì)節(jié)。架構(gòu)如下(以MGR的single-primary為例)。
當(dāng)數(shù)據(jù)庫發(fā)生故障時(shí),MySQL內(nèi)部自己進(jìn)行切換。切換完成后將topo結(jié)構(gòu)推送給Zebra monitor,Zebra monitor進(jìn)行相應(yīng)的讀寫流量變更。不過,該架構(gòu)存在與Binlog Server同樣的需要回復(fù)確認(rèn)問題,就是每次主庫數(shù)據(jù)寫入,都需要大多數(shù)節(jié)點(diǎn)回復(fù)ACK,該次寫入才算成功,存在一定的響應(yīng)時(shí)間開銷。同時(shí),每個(gè)MGR集群必須需要奇數(shù)個(gè)數(shù)(大于1)的節(jié)點(diǎn),導(dǎo)致原先只需要一主一從兩臺(tái)機(jī)器,現(xiàn)在需要至少三臺(tái),帶來一定的資源浪費(fèi)。但不管怎么說,MGR的出現(xiàn)是無疑是MySQL數(shù)據(jù)庫又一次偉大的創(chuàng)新。
結(jié)語
本文介紹了美團(tuán)點(diǎn)評MySQL數(shù)據(jù)庫高可用架構(gòu)從MMM到MHA+Zebra以及MHA+Proxy的演進(jìn)歷程,同時(shí)也介紹了業(yè)界一些高可用的做法。數(shù)據(jù)庫最近幾年發(fā)展突飛猛進(jìn),數(shù)據(jù)庫的高可用設(shè)計(jì)上沒有完美的方案,只有不斷的突破和創(chuàng)新,我們也一直在這條路上探索更加優(yōu)秀的設(shè)計(jì)與更加完美的方案。