本篇內(nèi)容主要講解“GitHub的MySQL高可用怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“GitHub的MySQL高可用怎么解決”吧!
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),安義企業(yè)網(wǎng)站建設(shè),安義品牌網(wǎng)站建設(shè),網(wǎng)站定制,安義網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,安義網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
GitHub在所有非Git的地方使用MySQL存儲數(shù)據(jù),其可用性對GitHub的運行至關(guān)重要。網(wǎng)站,API,鑒權(quán)等等,都需要數(shù)據(jù)庫訪問。GitHub運行多個MySQL集群來滿足其不同的服務(wù)和任務(wù)。這些集群使用典型的主復
結(jié)構(gòu),在集群中只有唯一節(jié)點(主)能寫入,其他節(jié)點(復制點)異步地復制主節(jié)點的變化(重播)并提供【讀】服務(wù)。
主節(jié)點的可用性至關(guān)重要。沒有了主節(jié)點,整個集群都不能寫入了(數(shù)據(jù)保存不下來)。任何數(shù)據(jù)變化操作,如提交、Bug、注冊、新建庫等等,都將失敗。要能寫入顯然需要有一個可獲得的寫入節(jié)點,即主節(jié)點。其中關(guān)鍵是,我們能定位或者發(fā)現(xiàn)這個節(jié)點。
在主節(jié)點崩潰的情形,必須保證一個新的主節(jié)點出現(xiàn),并且快速地廣播出去。檢測到崩潰,主節(jié)點切換和集群廣播告知,一起合計的時間就是總宕機時間。當然越小越好!
本文展示了GitHub的MySQL高可用和集群選主解決方案,該方案讓GitHub可靠地運行跨數(shù)據(jù)中心操作,容忍數(shù)據(jù)中心隔離(不可用),實現(xiàn)更短的宕機時間。
本文描述的解決方案是之前GitHub實現(xiàn)的高可用的迭代優(yōu)化。當擴容的時候,MySQL的高可用能夠適應(yīng)變化。我們也期望在GitHub有類似MySQL的策略用于其他服務(wù)。
當考慮高可用和服務(wù)發(fā)現(xiàn)時,一些問題會引導你走向一個合適解決方案,不完全的問題清單如下:
能忍受多久的宕機時間?
崩潰檢測是否可靠?能否忍受錯誤(過早切換)?
失效切換是否可靠?那里失效了?
方案在跨中心時是否也工作良好?在高/低延遲的網(wǎng)絡(luò)里呢?
方案能否容忍整個數(shù)據(jù)中心崩潰或網(wǎng)絡(luò)隔離?
是否有機制組織或減緩腦裂
出現(xiàn)(集群中兩個節(jié)點都聲稱自己是主,兩者獨立互,不知道對方,并都接受寫入)?
能否承受數(shù)據(jù)丟失?丟多少能忍?
為了說明這些問題,讓我們看看以前的高可用解決方案,并且為何要優(yōu)化它!
在以前的迭代中,我們使用:
用orchestrator做崩潰檢測和失效切換,并
用VIP和DNS做主節(jié)點發(fā)現(xiàn) 在該策略下,客戶端用名字來發(fā)現(xiàn)寫節(jié)點,例如mysql-writer-1.github.net,該名字被解析到一個虛擬IP地址(VIP),對應(yīng)的主節(jié)點主機就能訪問到。因此,正常情況下,客戶端會解釋這個名字,連到獲得的IP,找到主節(jié)點。
考慮這樣的復制拓撲結(jié)構(gòu),跨了3個數(shù)據(jù)中心: 在主節(jié)點失效時,復制節(jié)點里的一個 ,必須被提名替代其【主】位。
orchestrator將檢測失效,提名新主,接著重新定義名字或VIP??蛻舳瞬⒉恢佬轮髟趺炊ㄎ唬驗樗麄冎恢烂?,而名字必須解釋到新主上。情況是這樣的:
VIP是協(xié)同的:他們被數(shù)據(jù)庫服務(wù)器聲稱并擁有。為了獲得或釋放一個VIP,服務(wù)器必須發(fā)送一個ARP請求。占用該VIP的服務(wù)器必須先釋放才能讓新主獲得它。這隱含的效果是:
一個有序的失效切換操作先得聯(lián)系失效舊主并請求它釋放VIP,接著聯(lián)系新主請求其抓住該VIP。假如舊主無法訪問了或者拒絕釋放VIP咋辦?在舊主失效情景里,它不能按時響應(yīng)或完全不響應(yīng),都是可能的。
容許腦裂可以解決該問題:兩個主機都生成擁有同一個VIP。不同的客戶端可能連到其中之一上,看在網(wǎng)絡(luò)上誰離的近。
其中根源在于兩個獨立的服務(wù)器需要協(xié)作,而這個結(jié)構(gòu)是不可靠的。
就算舊主做出協(xié)作了,整個流程也浪費了寶貴的時間:切換到新主必須等到能聯(lián)系到舊主。
而且當VIP改變了,已存在的客戶端連接也不能保證從舊主哪里斷開,仍然會出現(xiàn)事實上的腦裂情景。
VIP通常是以物理位置邊界來設(shè)計,由路由器或開關(guān)擁有。因而,我們只能給相關(guān)位置的服務(wù)器重設(shè)VIP。在一些特殊情況下,我們無法給另一個數(shù)據(jù)中心的新主重設(shè)VIP,必須修改DNS。
DNS的變化擴散出去需要更長時間??蛻舳司彺媪薉NS(特定時間后才刷新)。跨數(shù)據(jù)中心的失效通常導致更長的宕機時間:需要更多時間讓客戶端意識到主節(jié)點變了。
這些限制促使我們尋求更好的解決方案,更多地考慮:
主節(jié)點通過pt-heartbeat心跳服務(wù)來自主地注入自己,基于延遲度量和流量控制
。該服務(wù)必須在新提名的主節(jié)點上被啟動。如果可能,在舊主上的該服務(wù)將被關(guān)停。
類似的,Pseudo-GTID注入由主節(jié)點自主管理。它應(yīng)該在新主啟動,并最好在舊主關(guān)停。
新主被置為可寫入,舊主被置為只讀(如果可能)。
這些額外的步驟會增加更多的總宕機時間,并且他們自身也會遇到失敗和沖突。這個解決方案是有效的,GitHub也做過成功的失效切換,在雷達監(jiān)控下運行良好。但我們希望高可用在這些方面做得更好:
跨數(shù)據(jù)中心無感。
能忍受數(shù)據(jù)中心失效。
去除不可靠的協(xié)作流程。
減少總宕機時間。
盡可能做到無損失效切換。
我們的新策略,伴隨著附帶的優(yōu)化,上述關(guān)注問題的解決或減輕。當前的HA結(jié)構(gòu)中包括:
orchestrator負責失效探測和切換(用的是跨數(shù)據(jù)中心的orchestrator/raft)。
Hashicorp的Consul用于服務(wù)發(fā)現(xiàn)。
GLB/HAProxy作為代理層處于客戶端和寫節(jié)點之間。
anycast用于網(wǎng)絡(luò)路由。
新的結(jié)構(gòu)去掉了VIP和DNS修改。雖然我們引入了更多的組件,但能夠解耦組件并簡化任務(wù),也能利用上堅固穩(wěn)定的解決方案。接下來詳細的說明下。
正常情況下,應(yīng)用通過GLB/HAProxy連接到寫節(jié)點,應(yīng)用永遠感受不到主節(jié)點身份。在以前,應(yīng)用需要使用名字。例如,cluster1集群的主節(jié)點用mysql-writer-1.github.net。在當前的結(jié)構(gòu)下,這個名字會被解釋到一個anycast地址(IP)。
用anycast,這個名字解釋到任何地方的同一個IP,但流量會基于客戶端位置被路由到不同地方。尤其是,我們的每一個數(shù)據(jù)中心都有GLB,我們的高可用負載均衡器,部署在多個機柜里。去往mysql-writer-1.github.net的流量總是路由到本地數(shù)據(jù)中心的GLB集群。
因而,所有的客戶端都由本地的代理服務(wù)。GLB運行于HAProxy之上。HXProxy有寫節(jié)點池:每個MySQL集群有這么個池,每個池僅只一個后端服務(wù)器 — 集群主節(jié)點。所有數(shù)據(jù)中心的GLB/HAProxy機柜用同一個池,亦即用池里的同一個后端服務(wù)器。因而,應(yīng)用如果想寫入到mysql-writer-1.github.net,和其所連接到的GLB服務(wù)器無關(guān),它總是被路由到cluster1集群的主節(jié)點。
應(yīng)用只需了解,發(fā)現(xiàn)終結(jié)于GLB,不存在重新發(fā)現(xiàn)的必要。剩下的就由GLB負責把流量路由到正確的目的地。那么GLB怎么知道服務(wù)于那些后臺服務(wù)器,并且怎么擴散對GLB的修改呢?
Consul是眾所周知的服務(wù)發(fā)現(xiàn)解決方案,也提供DNS服務(wù)。在我們的方案里,使用它作為高可用的KV存儲。
在Consul的KV存儲里存放集群主節(jié)點的標識。對每個集群,有一組KV條目標識集群主節(jié)點的fqdn、port、ipv4和ipv6。
每個GLB/HAProxy節(jié)點運行著consul-template:一個監(jiān)聽Consul數(shù)據(jù)變化的服務(wù)(對我們來說就是對集群描述數(shù)據(jù)的變化),該服務(wù)產(chǎn)生一個合法配置文件能用于重載HAProxy(當配置變化時)。
因而,Consul里一個主節(jié)點標識的變化被每個GLB/HAProxy機柜跟蹤著,并對自己進行重新配置,將新主設(shè)為集群后臺服務(wù)器池里唯一實體,并重載以反映這些變化。
在GitHub我們每個數(shù)據(jù)中心都有一個Consul,都是高可用結(jié)構(gòu)。但這些結(jié)構(gòu)是互相獨立的,不互聯(lián)復制也不共享任何數(shù)據(jù)。
那么Consul怎么獲知變化?以及信息怎么在跨數(shù)據(jù)中心間傳遞的?
我們運行著一個orchestrator/raft結(jié)構(gòu):orchestrator節(jié)點間通過raft互聯(lián)交流。每個數(shù)據(jù)中心有1-2個orchestrator節(jié)點。
orchestrator負責失效檢測,MySQL失效切換,以及Consul里主節(jié)點信息變化的傳遞。失效切換由單一的orchestrator/raft領(lǐng)頭節(jié)點操作,但變化 — 集群有個新主的消息,被擴展到所有orchestrator節(jié)點,通過raft機制。
當orchestrator節(jié)點接收到新主變化的消息,他們與本地Consul交互:觸發(fā)一個KV寫操作。有多個orchestrator節(jié)點的數(shù)據(jù)中心可能觸發(fā)多次對Consul的寫入。
當主節(jié)點崩潰時:
orchestrator檢測到失效。
orchestrator/raft領(lǐng)頭節(jié)點觸發(fā)一個恢復。一個新主被提名。
orchestrator/raft廣播主節(jié)點變化給所有raft集群節(jié)點。
每個orchestrator/raft節(jié)點收到領(lǐng)頭節(jié)點變化通知,更新本地Consul的KV存儲(新主的標識)。
每個GLB/HAProxy的consul-template監(jiān)聽到Consul里KV值變化,隨即重新配置并重載HAProxy。
客戶端流量轉(zhuǎn)向新主。
流程中每個組件都有明確的功能,整個設(shè)計解耦得很好也相當簡單。orchestrator不知道負載均衡,Consul不知道信息從哪兒來,HAProxy只關(guān)注Consul,而客戶端只關(guān)注Proxies。而且:
沒有DNS變化需要擴展。
沒有TTL。
流程不需要死舊主協(xié)作。
為了讓流程更加安全,我們還做了這些工作:
HAProxy配置很短的hard-stop-after。當其重載新的后臺服務(wù)器到寫節(jié)點池,它自動地終止所有對舊主的連接。
用hard-stop-after參數(shù)我們不必尋求客戶端的協(xié)作,從而減輕腦裂影響。當然這明顯沒有完全消除,我們斷掉所有舊連接需要時間。但總算有個時間點,在那之后讓我們感覺舒服并且不會有令人不爽的意外。
我們不嚴格要求Consul在任何時候都可用。事實上,我們只需要它在失效切換時能用即可。如果Consul恰好不可用,GLB會接著用最后已知的信息完成操作,不會造成什么極端行為。
GLB被設(shè)置為校驗新提名主節(jié)點的標識,類似我們的context-aware MySQL pools,會對后臺服務(wù)器進行檢查,確認其確實是個寫入節(jié)點。如果我們不慎刪除了Consul中的主節(jié)點標識,也沒問題,空項會被忽略。如果我們不慎將非主服務(wù)器寫到到Consul里,也沒問題,GLB將拒絕更新它仍按舊狀態(tài)繼續(xù)運行。
我們繼續(xù)追尋高可用的目標和關(guān)注。
orchestrator用holistic approach來檢測失效,這是很可靠的。我們沒有觀察到錯誤的失效切換,也就沒有承擔不必要的宕機時間。
orchestrator/raft更進一步深究完整的數(shù)據(jù)中心網(wǎng)絡(luò)隔離的情形。該情形下會出現(xiàn)誤導:數(shù)據(jù)中心里服務(wù)器能互相對話。但此時,是自己被其他數(shù)據(jù)中心隔離了,還是其他數(shù)據(jù)中心被隔離了?
在orchestrator/raft結(jié)構(gòu)里,raft領(lǐng)頭節(jié)點負責失效切換。領(lǐng)頭節(jié)點是個被組里多數(shù)支持的節(jié)點(類似民主投票)。我們orchestrator節(jié)點部署單中心選主,而是任何n-1個中心來做。
在完整的數(shù)據(jù)中心網(wǎng)絡(luò)隔離事件里,數(shù)據(jù)中心的orchestrator節(jié)點從其他節(jié)點(在其他數(shù)據(jù)中心的)斷開連接。這樣,隔離數(shù)據(jù)中心的orchestrator節(jié)點就不能成為raft集群的領(lǐng)頭。如果任何這類節(jié)點不巧成為領(lǐng)頭,它會宕掉。一個新的領(lǐng)頭會從其他數(shù)據(jù)中心賦予,這個領(lǐng)頭有其他數(shù)據(jù)中心的支持(投票),它有能力相互之間通信。
因而,這個orchestrator節(jié)點被叫做【槍擊】,它是網(wǎng)絡(luò)隔離數(shù)據(jù)中心外面來的。假設(shè)在隔離的數(shù)據(jù)中心里有個主節(jié)點,orchestrator會觸發(fā)失效切換來替換它,用其他數(shù)據(jù)中心獲得的服務(wù)器。我們緩解了數(shù)據(jù)中心隔離,通過委托其他非隔離的數(shù)據(jù)中心進行選主。
總宕機時間能顯著地降低,如果能更快地廣播主節(jié)點變化。怎么做到呢?
當orchestrator開始失效切換,它觀察可能被提名的眾多服務(wù)器。通過提示或限制,理解復制規(guī)則和曾經(jīng)記憶,它會依據(jù)合理程序做出科學的選擇。
它認為可被提名的服務(wù)器是個理想候選者,依據(jù):
沒有阻止該服務(wù)器被提名的任何障礙(或者用戶潛在地提示該服務(wù)器是適合被提名),并且
該服務(wù)器能被期待可以讓它的兄弟節(jié)點作為復制節(jié)點。
滿足條件下,orchestrator將其先設(shè)置為可寫入,并立即廣播該服務(wù)器提名(寫入到Consul庫里),同時異步地開始修復復制節(jié)點樹,該操作通常需要花幾秒鐘時間。
等到我們的GLB服務(wù)器都完成重載,復制節(jié)點樹也基本完成重整了,當然這并不是必須的。服務(wù)器恢復到可寫入就算OK。
在MySQL里,半同步復制是主節(jié)點不確認一個事務(wù)的提交,直到數(shù)據(jù)變化已被傳遞到1個或多個復制從節(jié)點。該行為提供了一種達到無損失效切換的方法:任何主節(jié)點的變化都已在復制從節(jié)點上應(yīng)用或正在應(yīng)用。
一致性是有成本的:對可獲得性造成風險。假設(shè)復制節(jié)點沒給收到變化的確認,主節(jié)點會阻塞,寫操作堆積。幸運的是,可以設(shè)置超時,超過時間就讓主節(jié)點切回到異步復制模式,讓寫操作可以繼續(xù)。
我們設(shè)置該超時時間在一個合理低值(500ms),這相對于將變化傳遞到本地DC的復制點的時間足夠久,甚至夠傳遞到遠程DC的復制點。在這個超時時間內(nèi),我們觀察到完美的半同步復制行為(沒有跌落到異步復制),以及滿意的短暫阻塞(當確認失敗時)。
在本地DC復制點我們用半同步復制,在遇到主節(jié)點死亡,我們期待(不是絕對要求)無損的失效切換。無損的失效切換在一個整個DC失效中代價過于高昂,不是我們的訴求。
在實驗半同步復制超時時,我們也觀察到對我們有利的現(xiàn)象:在主節(jié)點失效時我們能夠影響理想候選者的標識。通過在指定的服務(wù)器設(shè)置半同步復制,標識其作為候選者,我們能減少總宕機時間(通過影響失效結(jié)果)。在我們的實驗中,我們觀察到能更快完成候選者篩選,并因此加快新主廣播。
相對于讓pt-heartbeat服務(wù)在當選_落選的新主上啟_停,我們選擇讓其在任何時間任何地點都運行著。這需要對pt-heartbeat打個補丁讓其能夠適應(yīng)服務(wù)的讀寫狀態(tài)變換,甚至完全宕機。
在當前配置中pt-heartbeat服務(wù)運行在主節(jié)點和復制點上。在主節(jié)點上,它產(chǎn)生心跳,在復制點上,它標識服務(wù)器為只讀并定時循環(huán)地檢查其狀態(tài)。一旦某個服務(wù)器被提名為新主,其上的pt-heartbeat就標識其為可寫入并且開始產(chǎn)生心跳。
orchestrator承擔了更多的工作:
Pseudo-GTID生成器。
設(shè)置新主可寫入狀態(tài),清除復制點狀態(tài)。
設(shè)置舊主只讀狀態(tài)(如果可能)。
這是為了減少新主各工作的沖突。新主被選出顯然是期望它活著并可訪問,否則我們就沒必要提名它。當它能感知了,就讓orchestrator將變化直接應(yīng)用到它身上。
代理層讓應(yīng)用無法感知到主節(jié)點的標識,但他也讓應(yīng)用的標識被屏蔽在主節(jié)點之外。所有主節(jié)點看起來連接都都來自代理層,丟失了連接的真實來源信息。隨著分布式系統(tǒng)前行,我們?nèi)杂行┪刺幚淼降那樾巍?/p>
尤其,在數(shù)據(jù)中心網(wǎng)絡(luò)隔離情形,假設(shè)主節(jié)點是在被隔離DC里,而同DC的應(yīng)用還能寫入到主節(jié)點,而此時網(wǎng)絡(luò)恢復了,這就可能導致狀態(tài)不一致。我們正在探索降低腦裂后患的方法,通過實現(xiàn)一個可靠的STONITH,在正好隔離的DC里。像之前一樣,將主節(jié)點關(guān)停需要點時間,這仍將存在短暫的腦裂期。完全避免腦裂的操作成本是相當高昂的。
更多的情形包括:Consul在失效切換時宕了;部分DC隔離,等等。我們明白在分布式系統(tǒng)里,堵上所有的漏洞是不可能的,所以我們專注于最重要的情形。
我們的orchestrator_GLB_Consul架構(gòu)實現(xiàn)了:
可靠的失效檢測;
不可知數(shù)據(jù)中心失效切換;
典型的無損失效切換;
數(shù)據(jù)中心網(wǎng)絡(luò)隔離支持;
降低腦裂損害;
沒有協(xié)作延遲;
大多數(shù)10-13秒左右的總宕機時間,少數(shù)要20秒,極端要25秒;
到此,相信大家對“GitHub的MySQL高可用怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!