高併發系統設計(二十三):【多機房部署】:跨地域的分佈式系統如何做?

來想象這樣一個場景:你的垂直電商系統部署的IDC機房,在某一天發佈了公告說,機房會在第二天凌晨做一次網絡設備的割接,在割接過程中會不定時出現瞬間,或短時間網絡中斷。

機房網絡的中斷,肯定會對業務造成不利的影響,即使割接的時間在凌晨(業務的低峯期),作爲技術負責人的你,也要儘量思考方案來規避隔離的影響。然而不幸的是,在現有的技術架構下,電商業務全都部署在一個IDC機房中,你並沒有好的解決辦法。

而IDC機房的可用性問題是整個系統的阿喀琉斯之踵,一旦IDC機房像一些大廠一樣,出現很嚴重的問題,就會對整體服務的可用性造成嚴重的影響。比如:

2016年7月,北京聯通整頓旗下40多個IDC機房中,不規範的接入情況,大批不合規接入均被斷網,這一舉動致使脈脈當時使用的藍汛機房受到影響,脈脈宕機長達15個小時,著名的A站甚至宕機超過48個小時,損失可想而知。

而目前,單一機房部署的架構特點,決定了你的系統可用性受制於機房的可用性,也就是機房掌控了系統的生命線。所以,你開始思考,如何通過架構的改造,來進一步提升系統的可用性。在網上搜索解決方案和學習一些大廠的經驗後,你發現“多機房部署”可以解決這個問題。

多機房部署的難點是什麼

多機房部署的含義是:在不同的IDC機房中,部署多套服務,這些服務共享同一份業務數據,並且都可以承接來自用戶的流量。

這樣,當其中某一個機房出現網絡故障、火災,甚至整個城市發生地震、洪水等大的不可抗的災難時,你可以隨時將用戶的流量切換到其它地域的機房中,從而保證系統可以不間斷地持續運行。這種架構聽起來非常美好,但是在實現上卻是非常複雜和困難的,那麼它複雜在哪兒呢?

假如我們有兩個機房A和B都部署了應用服務,數據庫的主庫和從庫部署在A機房,那麼機房B的應用如何訪問到數據呢?有兩種思路。

一個思路是直接跨機房讀取A機房的從庫:

另一個思路是在機房B部署一個從庫,跨機房同步主庫的數據,然後機房B的應用就可以讀取這個從庫的數據了:

無論是哪一種思路,都涉及到跨機房的數據傳輸,這就對機房之間延遲情況有比較高的要求了。而機房之間的延遲,和機房之間的距離息息相關,你可以記住幾個數字:

1.北京同地雙機房之間的專線延遲一般在1ms~3ms。

這個延遲會造成怎樣的影響呢?要知道,我們的接口響應時間需要控制在200ms之內,而一個接口可能會調用幾次第三方HTTP服務,或者RPC服務。如果這些服務部署在異地機房,那麼接口響應時間就會增加幾毫秒,是可以接受的。

一次接口可能會涉及幾次的數據庫寫入,那麼如果數據庫主庫在異地機房,那麼接口的響應時間也會因爲寫入異地機房的主庫,增加幾毫秒到十幾毫秒,也是可以接受的。

但是,接口讀取緩存和數據庫的數量,可能會達到十幾次甚至幾十次,那麼這就會增加幾十毫秒甚至上百毫秒的延遲,就不能接受了。

2.國內異地雙機房之間的專線延遲會在50ms之內。

具體的延遲數據依據距離的不同而不同。比如,北京到天津的專線延遲,會在10ms之內;而北京到上海的延遲就會提高到接近30ms;如果想要在北京和廣州部署雙機房,那麼延遲就會到達50ms了。在這個延遲數據下,要想保證接口的響應時間在200ms之內,就要儘量減少跨機房的服務調用,更要避免跨機房的數據庫和緩存操作了。

3.如果你的業務是國際化的服務,需要部署跨國的雙機房,那麼機房之間的延遲就更高了,依據各大雲廠商的數據來看,比如,從國內想要訪問部署在美國西海岸的服務,這個延遲會在100ms~200ms左右。在這個延遲下,就要避免數據跨機房同步調用,而只做異步的數據同步。

如果你正在考慮多機房部署的架構,那麼這些數字都是至關重要的基礎數據,你需要牢牢記住,避免出現跨機房訪問數據造成性能衰減問題。

機房之間的數據延遲,在客觀上是存在的,你沒有辦法改變,你可以做的,就是儘量避免數據延遲對於接口響應時間的影響。那麼在數據延遲下,你要如何設計多機房部署的方案呢?

逐步迭代多機房部署方案

1.同城雙活

制定多機房部署的方案不是一蹴而就的,而是不斷迭代發展的。我在上面提到,同城機房之間的延時在1ms~3ms左右,對於跨機房調用的容忍度比較高,所以,這種同城雙活的方案複雜度會比較低。

但是,它只能做到機房級別的容災,無法做到城市級別的容災。不過,相比於城市發生地震、洪水等自然災害來說,機房網絡故障、掉電出現的概率要大的多。所以,如果你的系統不需要考慮城市級別的容災,一般做到同城雙活就足夠了。那麼,同城雙活的方案要如何設計呢?

假設這樣的場景:你在北京有A和B兩個機房,A是聯通的機房,B是電信的機房,機房之間以專線連接,方案設計時,核心思想是,儘量避免跨機房的調用。具體方案如下:

  • 首先,數據庫的主庫可以部署在一個機房中,比如部署在A機房中,那麼A和B機房數據都會被寫入到A機房中。然後,在A、B兩個機房中各部署一個從庫,通過主從複製的方式,從主庫中同步數據,這樣雙機房的查詢請求可以查詢本機房的從庫。一旦A機房發生故障,可以通過主從切換的方式,將B機房的從庫提升爲主庫,達到容災的目的。

  • 緩存也可以部署在兩個機房中,查詢請求也讀取本機房的緩存,如果緩存中數據不存在,就穿透到本機房的從庫中,加載數據。數據的更新可以更新雙機房中的數據,保證數據的一致性。

  • 不同機房的RPC服務會向註冊中心,註冊不同的服務組,而不同機房的RPC客戶端,也就是Web服務,只訂閱同機房的RPC服務組,這樣就可以實現RPC調用盡量發生在本機房內,避免跨機房的RPC調用。

你的系統肯定會依賴公司內的其他服務,比如審覈,搜索等服務,如果這些服務也是雙機房部署的,那麼也需要儘量保證只調用本機房的服務,降低調用的延遲。

使用了同城雙活架構之後,可以實現機房級別的容災,服務的部署也能夠突破單一機房的限制,但是,還是會存在跨機房寫數據的問題,不過鑑於寫數據的請求量不高,所以在性能上是可以容忍的。

2.異地多活

上面這個方案,足夠應對你目前的需要,但是,你的業務是不斷髮展的,如果有朝一日,你的電商系統的流量達到了京東或者淘寶的級別,那麼你就要考慮,即使機房所在的城市發生重大的自然災害,也要保證系統的可用性。而這時,你需要採用異地多活的方案(據我所知,阿里和餓了麼採用的都是異地多活的方案)。

在考慮異地多活方案時,你首先要考慮異地機房的部署位置。它部署的不能太近,否則發生自然災害時,很可能會波及。所以,如果你的主機房在北京,那麼異地機房就儘量不要建設在天津,而是可以選擇上海、廣州這樣距離較遠的位置。但這就會造成更高的數據傳輸延遲,同城雙活中,使用的跨機房寫數據庫的方案,就不合適了。

所以,在數據寫入時,你要保證只寫本機房的數據存儲服務,再採取數據同步的方案,將數據同步到異地機房中。一般來說,數據同步的方案有兩種:

  • 一種基於存儲系統的主從複製,比如MySQL和Redis。也就是在一個機房部署主庫,在異地機房部署從庫,兩者同步主從複製,實現數據的同步。

  • 另一種是基於消息隊列的方式。一個機房產生寫入請求後,會寫一條消息到消息隊列,另一個機房的應用消費這條消息後,再執行業務處理邏輯,寫入到存儲服務中。

我建議你,採用兩種同步相結合的方式,比如,你可以基於消息的方式,同步緩存的數據、HBase數據等。然後基於存儲,主從複製同步MySQL、Redis等數據。

無論是採取哪種方案,數據從一個機房,傳輸到另一個機房都會有延遲,所以,你需要儘量保證用戶在讀取自己的數據時,讀取數據主庫所在的機房。爲了達到這一點,你需要對用戶做分片,讓一個用戶每次的讀寫都儘量在同一個機房中。同時,在數據讀取和服務調用時,也要儘量調用本機房的服務。這裏有一個場景:假如在電商系統中,用戶A要查看所有訂單的信息,而這些訂單中,店鋪的信息和賣家的信息很可能是存儲在異地機房中,那麼你應該優先保證服務調用,和數據讀取在本機房中進行,即使讀取的是跨機房從庫的數據,會有一些延遲,也是可以接受的。

 

  • 不同機房的數據傳輸延遲,是造成多機房部署困難的主要原因,你需要知道,同城多機房的延遲一般在1ms~3ms,異地機房的延遲在50ms以下,而跨國機房的延遲在200ms以下。

  • 同城多機房方案可以允許有跨機房數據寫入的發生,但是數據的讀取,和服務的調用應該儘量保證在同一個機房中。

  • 異地多活方案則應該避免跨機房同步的數據寫入和讀取,而是採取異步的方式,將數據從一個機房同步到另一個機房。

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