從github超24小時的故障看異地多活全局設計的重要性

咱們先來回顧一下github此次事故: 2018年10月21日,github 在更換網絡設備時,引起了美國東海岸網絡中心和東海岸數據中心的網絡連接發生了40秒的中斷,最終致使多個mysql的主集羣由Orchestrator 自動選舉切換到了美國西海岸數據中心對應的集羣,由此引起了數據不一致,直接致使了超過24小時的服務降級,最後仍然還有少許數據需人工排查修復的悲劇。前端

事件的整個過程參考blog.github.com/2018-10-30-… 這篇文章,在這裏不詳細說明,咱們來直接看致使事件的根本緣由。mysql

根本緣由:缺失異地數據中心之間數據一致性的保障機制

github數據庫作的是本地主備+跨區域數據中心的容災方案,主數據庫集羣和其餘數據中心的集羣是異步同步的,當物理網絡發生中斷後,對於github這樣全球性的,大量用戶訪問的系統,時時刻刻都有數據變動,剛剛提交的數據尚未來得急同步過去,這時按照Orchestrator的機制,必然會從新選舉出新的數據庫寫入主節點。在沒有肯定數據全局一致性的狀況,就這麼一切,兩邊數據就無法一致同步了,更悲劇的是等網絡40s後恢復後,在Orchestrator沒有將原有的數據庫主節點置爲從節點以前,東海岸本地的應用還在往本地數據庫集羣寫數據,加重了數據的不一致,發生了腦裂現象。除了數據不一致的問題外,還有個比較嚴重的後果,github 除了數據庫主節點負責單點寫外,其餘區域數據中心的數據庫節點負責讀,把東海岸的應用數據庫切都西海岸,會有60ms的網絡消耗,就這點耗時,致使不少應用出現了服務超時不可用,對於不少web應用,一個前端請求會觸發後端系統幾十次的請求很是正常。由此能夠看出,github在處理跨數據中心的高可用方案上是有較大漏洞,沒有真正考慮一個數據中心不可用,和數據中心之間的網絡故障時的兩個重要場景。git

沒有引發重視的緣由分析

對於這麼重要的場景,爲啥github這麼牛的公司沒有實施了?我的猜想的幾個緣由(僅我的觀點):github

1.github 發展太快也太順利了,以前應當是沒有出過什麼嚴重問題,精力都聚焦到能帶來效益的事情了,這樣的事情沒有引發足夠的重視,技術戰略上沒有特別重視。web

2.異地多活的方案很是複雜,不只是數據庫的跨地域數據中心同步這麼簡單,須要結合公司的實際業務進行全局總體性的方案設計。redis

3.投入大,成本高,就拿異地機房之間的網絡線路來講,至少須要保障兩個物理上獨立的線路,而這些線路對數據中心來講,至少須要100G 光纖專線。此外其應用系統爲了適應異地多活帶來也須要進行架構升級,灰度測試等等。sql

實際來看這是不少公司都面臨的廣泛問題,在業務高速發展和系統可靠性建設上如何找到平衡點的問題。對於不少業務導向的公司,系統出現過嚴重問題,纔會重視起來。數據庫

異地多活方案如何來作?

計算機的分層思想很是有利於分析一個複雜系統,異地多活涉及到數據,應用系統,基礎軟件,網絡,運維繫統等等,很是複雜。採用分層思想能極大的簡化問題,解耦各層,而後全局看。下面是一個典型分佈式是數據中心的分層結構:後端



讓咱們來看每一個分層的異地多活方案如何作:緩存

DNS層:自己就是一個全球性的分佈式系統,自然就是異地多活的,在這一層作本身的異地多活,更可能是依賴DNS機制,系統化的動態切換域名和服務器的映射。因其DNS變動生效須要幾分鐘到幾十分鐘,對實時性要求高的容災,不能依賴這塊。

CDN層:嚴格來講,和DNS 同樣,也是自然異地多活的,由於CDN更多的是對靜態資源訪問的加速,需提早將靜態資源分發到離消費者更近的節點,掛掉一個節點不會影響數據的不一致,會下降訪問速度,影響用戶體驗。

負載均衡層:經過故障轉移策略,能夠迅速的將掛掉的服務器流量切到同城或者異地的數據中心,很是便捷高效,但這個地方必定要確保底層的數據已經同步過去以後,才能切,不然會出現數據不一致的狀況。

應用層:須要跨數據中心彈性集羣部署,就單個應用自己而言,沒有什麼難度,難度主要集中在依賴應用上,對於不少業務系統,特別是微服務架構成爲主流後,一個業務系統至少會依賴調用好幾個其餘應用,對於複雜的電商系統來講,一個系統依賴幾十個其餘系統的服務很正常。應用層的異地雙活,就不是簡單的單應用的跨數據中心部署,而是須要按照業務單元總體性考慮,單元化的思想是阿里異地雙活的基礎。這塊須要重點考慮的是,業務單元內的系統之間相互調用要本地化調用,避免跨單元,但對於一些無法單元化的業務,須要有中心單元化來統一支撐。此外應用系統自己的架構也須要考慮異地多活,特別是要考慮跨地域訪問帶來的時延影響,數據重複消費等問題。

中間件,緩存層:須要中間件自己要支持異地多活,就拿分佈式緩存redis來講,put 數據,須要支持在本地數據中心,和異地數據中心同時生效,失效也是同樣。這就須要對redis 進行修改。消息中間件,以及其餘中間件也是相似,對於不支持異地數據中心的版本,都需自行修改源碼進行支持,對於通常的小公司來講,這個難度很是大。只有top的公司才具有這樣的技術和環境去作這個事情。

數據庫/存儲:數據庫每一個廠商對異地數據中心的支持方案有差別,就mysql來講,mysql 目前的版本還不支持異地同步的方案,只支持本地同步副本,對於mysql的同步,只能是利用實時的數據同步工具drc 來作,由於不是異步同步,仍然存在幾ms-幾百ms的延遲。將流量從故障的數據中心切換到其餘數據中心時,必定要先將故障集羣的數據庫設置成只讀集羣,其次肯定數據庫已經徹底同步數據到對應異地數據中心的數據庫。最後將異地數據庫集羣設置爲寫集羣。



而整個過程會有幾分鐘的中斷,服務不可用,趕上罕見的這種故障,幾分鐘的故障恢復時間是能夠接受的,支付寶的異地多活也是分鐘級別的。這個地方最怕的就是物理線路故障,如挖掘機挖斷光纖的事情,對於大型金融級的數據中心,物理上有兩條獨立的光纖線路是必須的。趕上物理線路故障,確定會存在少許數據沒有同步完的狀況,這時候,本來到故障dc的寫流量是不能貿然轉移到其餘dc的,這時必然要犧牲部分服務的可用性;除非你能接受數據不一致的狀況。

看完每層的狀況,再來看全局,當一個DC發生故障時,如何在保證數據完整的狀況下,故障轉移了。發生故障不可怕,怕的是丟數據,數據錯亂。全部的策略都是圍繞數據的完整和正確性。全局設計也是同樣,所以我認爲較爲合理故障處理策略應當按照下面的步驟來:



咱們的原則就是將一切形成數據混亂的可能性降到最低,必然就是先關閉數據庫的寫,這會形成應用層寫數據庫等異常,但這也是咱們指望的。

發生整個DC出現大面積故障的事件是比較少的,最多見的故障仍是好比某個核心系統庫,部分網絡故障. 而這些故障會根據異地多活的方案有不一樣的一些恢復策略,以數據庫發生異常爲例,一般的恢復策略爲:

1.切換本地備庫爲主庫;從已有備份從新還原作備庫.

2.切換數據庫的代理到異地/同城的對應的數據庫集羣,必定要確保數據是徹底同步過去以後才能切,若是用Orchestrator之類的故障自動轉移,須要作對應的數據檢查機制。

總結

對於異地多活,沒有一刀切徹底通用的方案,須要根據本身的業務特色,在成本,服務可用性和數據完整性,技術複雜度之間作平衡,找到最適合本身公司的方案;可是最重要的原則就是無論那種方案,確保數據的完整性和一致性是首要考慮的。

更多文章歡迎訪問 http://www.apexyun.com/

聯繫郵箱:public@space-explore.com

(未經贊成,請勿轉載)

相關文章
相關標籤/搜索