異地多活在近年愈來愈多大型互聯網公司採用的方案,幾乎也是大型應用發展到必定階段的必然選擇,綜合比較一下各個互聯網公司的方案,會發現有不少共性的東西,也有不少差別化的東西,這是最有意思的地方html
異地多活通常是指在不一樣城市創建獨立的數據中心,「活」是相對於冷備份而言的,冷備份是備份全量數據,平時不支撐業務需求,只有在主機房出現故障的時候纔會切換到備用機房,而多活,是指這些機房在平常的業務中也須要走流量,作業務支撐。冷備份的主要問題是成本高,不跑業務,當主機房出問題的時候,也不必定能成功把業務接管過來。mysql
分佈式架構設計不管怎樣都繞不開CAP原則,C一致性 A可用性 P分區容錯性,分區容錯性是必不可少的,沒有分區容錯性就至關於退化成了單機系統,因此實際上架構設計是在一致性和可用性一個天平上的兩端作衡量。爲何強一致性和高可用性是不能同時知足?假如須要知足強一致性,就須要寫入一條數據的時候,擴散到分佈式系統裏面的每一臺機器,每一臺機器都回復ACK確認後再給客戶端確認,這就是強一致性。若是集羣任何一臺機器故障了,都回滾數據,對客戶端返回失敗,所以影響了可用性。若是隻知足高可用性,任何一臺機器寫入成功都返回成功,那麼有可能中途由於網絡抖動或者其餘緣由形成了數據不一樣步,部分客戶端獨到的仍然是舊數據,所以,沒法知足強一致性。sql
全部業務都要異地多活
以用戶中心爲例,註冊是不必作異地多活的,假如用戶在A機房註冊了,在數據沒有向外同步的時候,A機房網絡中斷,這個時候若是讓用戶切換到B機房註冊,就有可能發生數據不一致,出現兩個基本相同的帳號,這是不可容忍的。可是相對應的來講,用戶登陸這種是關鍵核心業務,就有必要作到異地多活了,用戶在A機房登陸不了,那就讓用戶在B機房登陸。雖然有極端的狀況,用戶在A機房修改了密碼,可是出現網絡中斷,B機房的用戶仍然保存的是舊密碼,可是相對於不可登陸來講,這種狀況是可容忍的。同時有些業務仍然是沒法實現異地多活的,好比涉及到金錢的業務,加入有一個用戶有100塊,消費了50塊,A機房發生異常,數據沒有同步出去,這時候用戶在B機房登陸後發現本身還有100塊,能夠繼續消費,就會對業務形成嚴重的影響。數據庫
必須作到實時一致性
受限於物理條件,跨地域的網速必定會存在延遲,通常是幾十毫秒,若是趕上網絡抖動,延遲超過幾秒甚至幾十秒都有可能。解決方法只能是減小須要同步的數據和只保證數據的最終一致性,有時候用戶在A機房修改了一條數據,業務上其實是能容忍數據的短期不一致的,即便其餘用戶在B機房讀到的是舊數據,實際上對業務也沒有任何影響。緩存
業務內聚,單個訂單的全部流程保證在一個機房內完成調用,不容許進行跨機房調用。每個機房稱爲一個ezone,對服務進行分區,讓用戶,商戶,騎手按照規則聚合到一個ezone內。根據業務特色,餓了麼選擇了把地理位置做爲劃分業務的單元,以行政省界用圍欄
把全國分爲多個shard。在某個機房出現問題的時候,也能夠按照地理位置把用戶,商戶,騎手打包遷移到別的機房便可。
網絡
可用性優先,當機房發生故障的時候,優先保證可用,用戶能夠先下單吃飯,有限時間窗口內的數據不一致能夠過後再修復。每一個 ezone 都會有全量的業務數據,當一個 ezone 失效後,其餘的 ezone 能夠接管用戶。用戶在一個ezone的下單數據,會實時的複製到其餘ezone。session
保證數據的正確性,在切換和故障時,檢測到某些訂單在兩個機房不一致,會鎖定改訂單,避免錯誤進一步擴散。架構
MySQL的數據量最大,每一個機房產生的數據,都經過 DRC 複製到其餘 ezone,每一個ezone的主鍵取值空間是ezoneid + 固定步長,因此產生的 id 各不相同,數據複製到一塊兒後不會發生主鍵衝突。按照分區規則,正常狀況下,每一個 ezone 只會寫入本身的數據,但萬一出現異常,2個 ezone 同時更新了同一筆數據,就會產生衝突。DRC 支持基於時間戳的衝突解決方案,當一筆數據在兩個機房同時被修改時,最後修改的數據會被保留,老的數據會被覆蓋。分佈式
對於個別一致性要求很高的應用,咱們提供了一種強一致的方案(Global Zone),Globa Zone是一種跨機房的讀寫分離機制,全部的寫操做被定向到一個 Master 機房進行,以保證一致性,讀操做能夠在每一個機房的 Slave庫執行,也能夠 bind 到 Master 機房進行,這一切都基於咱們的數據庫訪問層(DAL)完成,業務基本無感知。測試
微博使用了基於 MCQ(微博自研的消息隊列)的跨機房消息同步方案,並開發出跨機房消息同步組件 WMB(Weibo Message Broker)。
每一個機房的緩存是徹底獨立的,由每一個機房的 Processor(專門負責消息處理的程序,類 Storm)根據收到的消息進行緩存更新。因爲消息不會重複分發,並且信息完備,因此 MytriggerQ 方案存在的緩存更新髒數據問題就解決了。而當緩存不存在時,會穿透到 MySQL 從庫,而後進行回種。可能出現的問題是,緩存穿透,可是 MySQL 從庫若是此時出現延遲,這樣就會把髒數據種到緩存中。解決方案是作一個延時 10 分鐘的消息隊列,而後由一個處理程序來根據這個消息作數據的從新載入。通常從庫延時時間不超過 10 分鐘,而 10 分鐘內的髒數據在微博的業務場景下也是能夠接受的。
因爲微博對數據庫不是強依賴,加上數據庫雙寫的維護成本過大,選擇的方案是數據庫經過主從同步的方式進行。這套方案可能的缺點是若是主從同步慢,而且緩存穿透,這時可能會出現髒數據。這種同步方式已運行了三年,總體上很是穩定,沒有發生由於數據同步而致使的服務故障。
阿里在部署異地多活的時候一樣是碰到延時問題,解決方案是訪問一次頁面的操做都在本機房完成,不作跨機房調用。阿里把業務劃分紅各類單元,如交易單元,這個單元是完成交易業務,稱之爲單元化。
讓操做所有在同一中心內完成,單元化
好比用戶進入之後,好比說在淘寶上看商品,瀏覽商品,搜索、下單、放進購物車等等操做,還包括寫數據庫,就都是在所進入的那個數據中心中完成的,而不須要跨數據中心
異地部署的是流量會爆發式增加的,流量很大的那部分。流量小的,用的很少的,不用異地部署。
其餘一些功能就會缺失,因此咱們在異地部署的並不是全站,而是一組業務,這組業務就成爲單元
好比:在異地只部署跟買家交易相關的核心業務,確保一個買家在淘寶上瀏覽商品,一直到買完東西的全過程均可以完成
買家相關的數據在寫的時候,必定是要寫在那個單元裏。要保障這個用戶從進來一直到訪問服務,到訪問數據庫,全鏈路的路由規則都是徹底一致的。若是說某個用戶原本應該進A城市的數據中心,可是卻由於路由錯誤,進入了B城市,那看到的數據就是錯的了。形成的結果,多是用戶看到的購買列表是空的,這是不能接受的。
異地部署,咱們須要同步賣家的數據、商品的數據。能接受的延時必需要作到一秒內,即在全國的範圍內,都必須作到一秒內把數據同步完中心之間骨幹網。
把用戶操做封閉在一個單元內完成,最關鍵的是數據。在某個點,必須確保單行的數據在一個地方寫,絕對不能在多個地方寫。
爲了作到這一點,必須肯定數據的維度。淘寶除了用戶自己的信息之外,還會看到全部商品的數據、全部賣家的數據,面對的是買家、賣家和商品三個維度。由於異地的是買家的核心鏈路,因此選擇買家這個維度。按買家維度來切分數據。但由於有三個維度的數據,當操做賣家、商品數據時,就沒法封閉。
在全部的異地多活項目中,最重要的是保障某個點寫進去的數據必定是正確的。這是最大的挑戰,也是咱們在設計整個方案中的第一原則。業務這一層出故障咱們均可以接受,可是不能接受數據故障。
多個單元之間必定會有數據同步。一方面,每一個單元都須要賣家的數據、商品的數據;
另外一方面,咱們的單元不是全量業務,那必定會有業務須要這個單元,好比說買家在這個單元下了一筆定單,而其餘業務有可能也是須要這筆數據,不然可能操做不了,因此須要同步該數據。
因此怎樣確保每一個單元之間的商品、賣家的數據是一致的,而後買家數據中心和單元是一致的,這是很是關鍵的。
各類方案都是針對不一樣的業務場景設計的,因此會有必定的不一樣,可是基本思路都是一致的。經過各類手段避免進行跨機房調用,消除延遲,讓用戶無感知。必要的時候經過業務的妥協,犧牲一致性來獲取更高的可用性和更低的部署複雜程度。細讀CAP理論就知道,這個問題是不存在完美的解決方案的,只有儘可能貼合業務,逐漸迭代出更合適的方案。
引用:
異地多活設計辣麼難?實際上是你想多了!
餓了麼異地多活技術實現(一)整體介紹
微博「異地多活」部署經驗談
絕對乾貨:解密阿里巴巴「異地多活」技術
阿里和微博的異地多活方案zt