多活/多機房的幾種實現方式與重點

也可以在 多活/多機房的幾種實現方式與重點 - mdhs.io 讀到這篇文章。


當業務規模提升到一定程度之後,很多公司會考慮「多活」,也就是將自己的業務部署在多個機房,不管是同城還是異地,其中的原因包括但不限於:

  • 從高可用角度,公司已經不再能承擔單機房故障導致的服務中斷
  • 從業務的地域屬性角度,部署需要距離用戶更近,來獲得更迅速的用戶體驗
  • 或者更直接的,單個機房已經承擔不了全部的業務流量

無論哪種情況,將要建設的機房都要求具有獨立性,尤其是網絡環境,機房之間通過專線來進行連接。典型的拓撲會如下圖所示:

典型雙機房拓撲

在這種情況下,技術人員有多種多機房實現方式可以選擇。

初始的多機房實現

首先是技術人員遇到多機房部署任務時最先想到和最容易能夠做到的方案,將無狀態的計算應用,也就業務方開發的網絡應用程序,直接部署在新機房,將新機房視爲本機房的簡單拓展:

這種方案,優點是接到多機房部署任務後,無需任何準備就可以把新機房利用起來並對外提供服務。但同時也會有一個致命缺陷——業務應用對於專線具有強依賴:不管是對於其他服務的API調用還是對於存儲的訪問都是實時通過專線傳輸。

而專線的穩定性恰恰是不可控的

專線問題常常表現爲,延遲抖動,丟包,甚至在一段時間內完全不可用。而且,更致命的是,以上時間在發生之前通常不會得到預警。強如國內的某些獨角獸企業也會遇到因爲光纖被挖斷而喪失部分服務能力的情況。對於剛剛進行雙機房的部署的企業來說,業務總會時不時因爲專線問題收到報警或者錯誤。長此以往,技術人員應對這些問題會十分疲憊。

針對這個問題,可能會有人選擇將一個機房,完全作爲一個冗餘或熱備 —— 有一份實時備份的數據,同時也部署服務,但不讓其對外提供服務,僅僅作爲災備。爲了讓備用主機房真正掛掉的時候能頂上去,通常還要爲其配置和主機房相當的計算能力以及冗餘帶寬,這在平時是較大的浪費,稱之爲「多活」也有些牽強,在此不論。

如果機房專線的穩定性已經對你產生了足夠的困擾,則需要解除業務應用對於專線的實時依賴。下面我們將探究多機房部署下,完全避免專線實時影響的可能方案。

理想的多機房實現

圖上的實現方式能夠實現以下效果:

  • 兩個機房之間看起來像兩個完全獨立的系統,各自提供全量服務,實時調用被限制在機房內部,對專線無強依賴
  • 用戶可能任意訪問到兩個機房,並可以隨時在一個機房不可用時訪問另一個機房
  • 兩個機房的數據存儲(比如MySQL,MongoDB,Redis 等)通過某種強大的邏輯能夠進行實時同步,從而各自擁有一份全量且一致的數據。

這是一種理想的實現,無論是從架構上設計上還是在對於業務開發友好性上都很好,但在現實中極難落地。問題在於 CAP [1],也不能忍受兩個機房數據庫均寫入成功再返回給客戶端,否則延遲增大且可用性會受專線影響,只能通過後臺異步的方式將數據源源不斷從一個機房同步到另一個機房。而異步複製數據總是需要需要時間的,而且也會受到專線可用性影響。

這種數據複製上延遲帶來兩個問題:

  1. 用戶在機房 A 修改數據後,又立刻切換到機房B來讀,數據可能因爲複製延遲而不能被用戶讀到(且專線故障時延遲相當於無限大,可能放大這種問題)
  2. 用戶在機房 A 修改數據後,數據尚未同步到B機房時刻,用戶立刻切換到機房 B 修改同一行數據,數據可能會發生衝突

第一種情況容易理解。第二種情況可以類比 A B 兩位開發人員要修改同一份代碼, A 修改後提交,如果 B 在 A 提交之後先拉取,再修改提交,不會產生任何衝突。但如果 A 修改提交後,B 未拉取(類比複製延遲),此時修改提交會產生衝突。代碼衝突,要麼商量解決,要麼乾脆強制覆蓋掉 A 的提交(犧牲了代碼邏輯正確性),但對於線上的實時業務數據衝突,想要掛起業務由人工來修復是不現實的,只能選擇強制覆蓋,數據可能出錯。

沒有任何辦法了嗎?倒也不至於。每個公司業務形態不同,可以根據自身的業務特點來在此基礎上做改進,提供兩種方法:

基於用戶分區的多機房實現

這種方案基於用戶僅會修改自己的數據,而不會修改其他用戶的數據,可能是數據庫每一行都會有個用戶id字段,也可能是用戶擁有地域或者其他屬性,兩地用戶雖在使用同樣的服務,但一般見不到彼此,數據上是隔離的。

比如訂餐應用或者約車服務,某城市的商戶或者司機,只會爲本城市的用戶提供服務。

如果用戶集和地域相關,可以享受到DNS可按地域配置優勢,絕大多數用戶可以直接通過DNS直達指定的機房。各機房網關還需要實現邏輯,將DNS出錯,或在地域交界處的偶爾「迷路」走到錯誤機房的用戶重定向回正確機房。

如果你的業務用戶集沒有地域屬性,可能需要在各機房網關實現一套類似 redis-cluster 對 key 的分區策略,並讓路由結果在客戶端緩存,從而一個用戶在訪問過一次機房之後就能拿到正確的機房地址,涉及到聯動客戶端,整套實現下來更爲複雜。

同時底層的數據同步中間件,應該是實時的雙向複製,因爲兩機房各自修改的行不同,理論上不應該存在衝突,但是這一層最好依然實現一定的衝突檢測和修復機制,防止上層的方案失效或者誤操作,導致數據被污染。衝突的檢測邏輯可以參考 Amazon Dynamo 中向量鍾(vector clock)的實現 [2]。

前文說「理想的多機房實現」面臨切換機房延遲問題以及衝突問題。延遲問題有多大影響取決於用戶在兩個機房切換的頻率。而對於衝突問題,在 vector clock  發現衝突基礎上我們如果再給其增加一個時間戳,實現 LWW (Last Write Win),從而實時解決衝突,則可以在底層直接維護數據的一致性。兩個機房的時間戳無法完全一致,儘量減少誤差,可以更好地保證衝突解決的 正確性。 實現完善後應當具有一些使用場景。

用戶集在機房遷移時要注意,應先等待該用戶集產生的數據完全同步到目標機房後,再將此用戶集指向目標機房,防止同步數據和用戶在新機房的寫入操作產生競爭。

該方案完成後,專線完全切斷,即使人工不介入,也不會對用戶訪問產生任何影響。若機房整體宕機,有一部分用戶的訪問完全不受影響,另一部分用戶在人工介入前完全無法訪問。

基於微服務調度的多機房實現

這種方案基於企業已經將業務進行了足夠細粒度的微服務化。微服務主要屬性之一就是,服務內的數據存儲是內聚的,服務間低耦合,服務之間通過RPC(實時)或者消息隊列(異步)進行通信。

核心思想是,對某個微服務而言是熱備結構 —— 該服務在兩個機房均部署,且都僅連接各自機房內數據庫,但只給一個機房輸入流量。但是對於所有微服務構成的業務整體來看,卻利用了兩個機房的算力和帶寬。

類似 TiKV 等分佈式存儲中的 multi raft [3]

因爲一個微服務或者一組微服務對外可以擁有獨立的域名,同樣可以利用DNS實現直達目標機房。

底層的數據可以是單向同步,可以不再考慮衝突問題,但是爲了防止可能出現的上層分流邏輯失敗或者操作失誤,底層最好加一層開關,讓該服務的備份機房的數據庫不可寫入。

這種方案依賴微服務,有以下幾個難點:

首先,服務之間可能會有實時的RPC調用,而實時調用不應該跨越機房,機房之間應當只有異步的消息隊列,以避免對專線的強依賴。所以擁有實時RPC調用的多個服務應該劃分爲一個「微服務組」,他們纔是跨機房調度的最小單元。這個單元應該儘量小,這個比較考驗公司的服務治理和架構把控能力。

另外,方案的難點是需要一個合理的聯動機制。因爲演練或者其他需求要在機房之間的遷移服務時,需要找到該服務下所有的存儲,讓其數據複製反向,而且同樣在業務切換之前先保證數據已經同步完畢,同時還要正確配置各存儲讀寫開關。各個流程要緊密配合,還要有切換時出錯的回滾機制。這要求服務治理擁有完善的分佈式追蹤,手動維護對應關係麻煩且易出錯。

該方案完成後,專線完全切斷,即使人工不介入,也不會對用戶訪問產生任何影響。若機房整體宕機,所有用戶的某個微服務在人工介入前處於不可用狀態。但因爲該服務在另一個機房是隨時 stand by 的狀態,及時切過去即可。

一些妥協

上面的方案是以完全避免專線的影響爲目標所做的努力,可能實際落地成本會比較高。比如,微服務組的設計,對於已經有業務包袱的企業來說,將現有微服務劃分成組,規避組間實時調用已然不易,如果業務還在高速發展中,新業務開發中要做到不破壞「微服務組」還需要很多努力和試錯。

這時候,可以根據自身的業務形態,在專線故障的容忍能力上適當做一些妥協。

每個企業,總有一些核心業務在決定實時收益,其他業務是負責用戶粘性,爲將來帶來隱形效益。這兩種業務又大概符合二八定律。前者業務變動相對較少,而從收益和損失角度來講,後者對專線故障的容忍性更強。我們可以根據這個特點,把主要經歷放在維護影響實時收益的「核心業務組」的高內聚上,負責用戶粘性的業務放任其跨機房實時RPC,專線故障時做好降級。

小結

文章分析了企業在做多機房或者「多活」時可能遇到的問題,並給了兩種免受專線可用性影響的實現方案:基於用戶分區  基於微服務調度。這裏只給出了大體方向,實踐中還有無數的細節需要考慮。多機房部署,還要考慮自身的業務形態,選擇合適的落地方案。

不受專線影響要求額外付出一些努力,如果你覺得專線對你們的影響尚不值得付出這些額外努力,也不必強求架構上的純粹性。實踐以上方案的過程中找到一個讓自己舒服的點即可。

無論何種方案,對於公司的技術儲備和架構設計能力都是一個考驗,從上層的調度,到底層的同步可能都需要自研中間件實現,底層的複製中間件又要面對公司各種數據庫選型,比如 MySQL Redis Mongo 等,還有對於消息隊列正確調度。除此之外,需要還要留有一定的試錯時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章