來想象這樣一個場景:你的垂直電商系統部署的 IDC 機房,在某一天發布了公告說,機房會在第二天凌晨做一次網絡設備的割接,在割接過程中會不定時出現瞬間或短時間網絡中斷。
機房網絡的中斷肯定會對業務造成不利的影響,即使割接的時間在凌晨(業務的低峰期),作為技術負責人的你,也要盡量思考方案來規避隔離的影響。然而不幸的是,在現有的技術架構下,電商業務全都部署在一個 IDC 機房中,你並沒有好的解決辦法。
而 IDC 機房的可用性問題是整個系統的阿喀琉斯之踵,一旦 IDC 機房像一些大廠一樣出現很嚴重的問題,就會對整體服務的可用性造成嚴重的影響。比如:
而目前,單一機房部署的架構特點決定了你的系統可用性受制於機房的可用性,也就是機房掌控了系統的生命線。所以,你開始思考如何通過架構的改造進一步提升系統的可用性。在網上搜索解決方案和學習一些大廠的經驗后,你發現“多機房部署”可以解決這個問題。
多機房部署的難點是什么
多機房部署的含義是:在不同的 IDC 機房中部署多套服務,這些服務共享同一份業務數據,並且都可以承接來自用戶的流量。
這樣,當其中某一個機房出現網絡故障、火災,甚至整個城市發生地震、洪水等大的不可抗的災難時,你可以隨時將用戶的流量切換到其它地域的機房中,從而保證系統可以不間斷地持續運行。這種架構聽起來非常美好,但是在實現上卻是非常復雜和困難的,那么它復雜在哪兒呢?
假如我們有兩個機房 A 和 B 都部署了應用服務,數據庫的主庫和從庫部署在 A 機房,那么機房 B 的應用如何訪問到數據呢?有兩種思路。
一個思路是直接跨機房讀取 A 機房的從庫:

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

無論是哪一種思路,都涉及到跨機房的數據傳輸,這就對機房之間延遲情況有比較高的要求了。而機房之間的延遲和機房之間的距離息息相關,你可以記住幾個數字。
- 北京同地雙機房之間的專線延遲一般在 1ms~3ms。
這個延遲會造成怎樣的影響呢?要知道,我們的接口響應時間需要控制在 200ms 之內,而一個接口可能會調用幾次第三方 HTTP 服務或者 RPC 服務。如果這些服務部署在異地機房,那么接口響應時間就會增加幾毫秒,是可以接受的。
一次接口可能會涉及幾次的數據庫寫入,那么如果數據庫主庫在異地機房,那么接口的響應時間也會因為寫入異地機房的主庫,增加幾毫秒到十幾毫秒,也是可以接受的。
但是,接口讀取緩存和數據庫的數量可能會達到十幾次甚至幾十次,那么這就會增加幾十毫秒甚至上百毫秒的延遲,就不能接受了。
- 國內異地雙機房之間的專線延遲會在 50ms 之內。
具體的延遲數據依據距離的不同而不同。比如,北京到天津的專線延遲會在 10ms 之內;而北京到上海的延遲就會提高到接近 30ms;如果想要在北京和廣州部署雙機房,那么延遲就會到達 50ms 了。在這個延遲數據下,要想保證接口的響應時間在 200ms 之內,就要盡量減少跨機房的服務調用,更要避免跨機房的數據庫和緩存操作了。
- 如果你的業務是國際化的服務,需要部署跨國的雙機房,那么機房之間的延遲就更高了,依據各大雲廠商的數據來看,比如,從國內想要訪問部署在美國西海岸的服務,這個延遲會在 100ms~200ms 左右。在這個延遲下,就要避免數據跨機房同步調用,而只做異步的數據同步。
如果你正在考慮多機房部署的架構,那么這些數字都是至關重要的基礎數據,你需要牢牢記住,避免出現跨機房訪問數據造成性能衰減問題。
機房之間的數據延遲在客觀上是存在的,你沒有辦法改變。你可以做的,就是盡量避免數據延遲對於接口響應時間的影響。那么在數據延遲下,你要如何設計多機房部署的方案呢?
逐步迭代多機房部署方案
-
同城雙活
制定多機房部署的方案不是一蹴而就的,而是不斷迭代發展的。我在上面提到,同城機房之間的延時在 1ms~3ms 左右,對於跨機房調用的容忍度比較高,所以,這種同城雙活的方案復雜度會比較低。
但是,它只能做到機房級別的容災,無法做到城市級別的容災。不過,相比於城市發生地震、洪水等自然災害來說,機房網絡故障、掉電出現的概率要大得多。所以,如果你的系統不需要考慮城市級別的容災,一般做到同城雙活就足夠了。那么,同城雙活的方案要如何設計呢?
假設這樣的場景:你在北京有 A 和 B 兩個機房,A 是聯通的機房,B 是電信的機房,機房之間以專線連接,方案設計時,核心思想是盡量避免跨機房的調用。具體方案如下。
- 首先,數據庫的主庫可以部署在一個機房中,比如部署在 A 機房中,那么 A 和 B 機房數據都會被寫入到 A 機房中。然后,在 A、B 兩個機房中各部署一個從庫,通過主從復制的方式,從主庫中同步數據,這樣雙機房的查詢請求可以查詢本機房的從庫。一旦 A 機房發生故障,可以通過主從切換的方式將 B 機房的從庫提升為主庫,達到容災的目的
- 緩存也可以部署在兩個機房中,查詢請求也讀取本機房的緩存,如果緩存中數據不存在,就穿透到本機房的從庫中加載數據。數據的更新可以更新雙機房中的數據,保證數據的一致性。
- 不同機房的 RPC 服務會向注冊中心注冊不同的服務組,而不同機房的 RPC 客戶端,也就是 Web 服務,只訂閱同機房的 RPC 服務組,這樣就可以實現 RPC 調用盡量發生在本機房內,避免跨機房的 RPC 調用。

你的系統肯定會依賴公司內的其他服務,比如審核、搜索等服務,如果這些服務也是雙機房部署的,那么也需要盡量保證只調用本機房的服務,降低調用的延遲。
使用了同城雙活架構之后,可以實現機房級別的容災,服務的部署也能夠突破單一機房的限制。但是,還是會存在跨機房寫數據的問題,不過由於寫數據的請求量不高,所以在性能上是可以容忍的。
-
異地多活
上面這個方案足夠應對你目前的需要,但是,你的業務是不斷發展的,如果有朝一日,你的電商系統的流量達到了京東或者淘寶的級別,那么你就要考慮即使機房所在的城市發生重大的自然災害,也要保證系統的可用性。而這時,你需要采用異地多活的方案(據我所知,阿里和餓了么采用的都是異地多活的方案)。
所以,在數據寫入時,你要保證只寫本機房的數據存儲服務再采取數據同步的方案,將數據同步到異地機房中。一般來說,數據同步的方案有兩種:
一種基於存儲系統的主從復制,比如 MySQL 和 Redis。也就是在一個機房部署主庫,在異地機房部署從庫,兩者同步主從復制實現數據的同步。
另一種是基於消息隊列的方式。一個機房產生寫入請求后,會寫一條消息到消息隊列,另一個機房的應用消費這條消息后再執行業務處理邏輯,寫入到存儲服務中。

總結
不同機房的數據傳輸延遲是造成多機房部署的主要原因,你需要知道,同城多級房的延遲一般 在 1-3ms,異地機房的延遲一般在 50ms 以下 ,而跨國機房一般在200ms以下。
同城多機房可以允許有數據跨機房寫入的情況,但是數據的讀取和服務的調用盡量保證在同一個機房。
異地多活方案 應該盡量避免跨機房同步數據的讀取和寫入操作,而是采用異步的方式,將數據從一個機房同步到另一個機房。
多級房部署是業務發展到一定階段考慮采用的方案,對於機房容災有需求時才考慮的方案,能不做盡量不要去做。一旦決定采用跨機房,首先考慮的就是同城跨機房的部署,這種方案 會簡單的多,而異地多機房部署相對來說就要復雜的多了。
盲目的追求架構的先進性 只能給系統帶來更加的復雜,造成運維成本的上升。從而帶來維護的不便。
作者:逗逼程序員
鏈接:https://www.jianshu.com/p/2eff993309ce
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。