今天咱們來聊聊高可用系統架構的熱點——異地多活。
現在比較吊的多活方式是異地三節點,有多少公司真正實現了就不得而知了。為什么要做異地多活,主要是為了提升系統的容災能力,比如單機房的網絡故障、地震火災等不可抗因素,都有可能造成整個機房癱瘓。
在上一家公司負責支付系統開發的時候,由於我們在天津機房的硬件設施太過老舊,經常時不時地網絡故障,進而逼我們搭建了一個異地多活的架構。我們先來看看我們當時的做法。整個部署結構如下圖:
- 通過域名做負載均衡,將請求路由到最近的可用服務的機房。
- 服務全部機房內自治,不進行跨機房訪問
- DB(mysql)僅有一個,機房2跨機房訪問機房1的DB進行讀寫
整個架構看起來是可行的,並且當時也是有在生產環境使用。但是不難看出,機房2的服務,在響應時間上肯定要比機房1更慢。因為跨機房訪問數據庫帶來了一定的網絡延時,在最正常的情況下,通過當時購買的專線,可以控制在數十ms以內。
當機房1故障時,通過dns切換(據說可以智能切換,不過我們當時並沒有實施)關閉機房1的請求,然后將機房2的數據庫從slave升級為master,就可以完成整個容災過程。看起來並不是全自動的,但至少比服務長時間癱瘓等待機房修復要好。而且,dns切換以及db切換,都可以通過自動的方式來實現。
上面的方案實現簡單,對於一般的業務也夠用了。但是,存在以下幾個問題。而這幾個問題,也是異地容災跨不過的坎。
- 機房間延時。不管是機房2訪問機房1的DB,還是DB之間的主從同步,都進行了跨機房的網絡請求,其延時是難以避免的
- 專線網絡需要花錢,而且不便宜。嚴格來講,你拉一條專線網絡,這也是一個單點服務。如果要做到專線網絡容災,價格應該至少要翻番吧
- 數據同步。對於實時性要求不高的業務,比如微信發朋友圈,可以允許延時。但對於支付(賬號余額)這種數據來講,必須是強一致性的。如果機房1掛了,機房2備份庫的數據還是一份臟數據,那必然會帶來重大的損失。所以,這種數據同步方案,對於強一致性要求的數據,是不可接受的。對於強一致性的數據,只有通過人為修復確保都更新到位后,才能恢復服務。也就是在此期間,其實服務也處於不可用狀態。
通過以上分析,我們不難看出,1.2兩個缺點,可以勉強花錢解決,但是對於3,花錢也解決不了。那么,對於強一致性要求的數據,我們如何來做容災呢?
-
機房1、機房2實現雙主(Master-Master)的數據庫架構。兩個數據庫分別置於機房1和機房2,實現讀寫。master之間通過mysql的內部實現,進行數據同步。這個方案其實跟之前的方案區別不大,只是減少了服務去訪問數據庫的網絡延時,屬於一個偽數據強一致性方案。而且雙主很依賴網絡延時進行數據同步,同時容易出現腦裂現象,個人不推薦使用。
-
通過業務層來實現分布式事務,以此來確保兩個機房數據的強一致性。兩個數據庫分別置於兩個機房中,通過業務程序來實現分布式事務,也就是通過業務層來確保數據庫1和數據庫2都更新成功,才視為更新成功。這樣確實可以保證數據庫1和數據庫2的數據強一致性。但是增加了系統的實現復雜度,也增強了對開發人員能力的要求。另外,分布式事務會增加業務處理時長以及失敗率,如果單機房故障一年都僅有幾個小時,這種分布式的代價是否值得呢?
-
將服務狀態化。對用戶進行分區,將用戶請求固定路由到機房1或機房2。如此一來,兩個機房不會對同一份數據進行更新,也就避免了數據強一致性的要求。同時,這兩個數據庫之間,仍然通過主備進行數據備份。當其中一個機房故障時,通過人為修復該機房同步到另外一個機房的數據后,再恢復機房1中的服務。對比在上家公司已實現的方案,這種方案有兩個優點:減小了跨機房訪問數據庫的延時;減小了受災用戶群體。個人覺得該方案不錯,但是如何在dns解析域名時進行狀態化呢?如果又引入中間件,那不是又單點了嗎。。
如果細讀了CAP理論,就會發現這個問題是沒有十全十美的解決方案的。在這個問題上,我更加傾向於的解決方案是:使用阿里雲服務,增加可用性。你有更好的方案嗎,歡迎給我留言。
摘自:https://mp.weixin.qq.com/s?spm=5176.100239.blogcont59149.3.rkSIqU&__biz=MzI0MzQ5MzMwMg==&mid=2247483662&idx=1&sn=e45bf4b395e727f543edc827fc050ee5&scene=1&srcid=0814e9DLDRSshqsi6PaGq116&from=groupmessage&isappinstalled=0#wechat_redirect