Categories
程式開發

達達雙雲雙活實踐


引言

過去6年,達達集團秉承“萬千好物即時可得”的初心和願景,不斷迭代和升級技術能力,持續提升履約效率和服務體驗。 為保障系統持續穩定和業務不間斷地高效運行, 我們在數據庫高可用架構升級、數據庫垂直/水平拆分、 微服務治理及可觀測性、容量彈性和多活容災等方面進行了不斷實踐並取得一定成果。

本文主要分享達達在雙雲雙活容災能力建議方面的實踐和經驗。

為什麼做雙活?

首先,介紹一下高可用(High Availability)和容災(Disaster Recovery),兩者相互聯繫、相互補充,但也有明顯區別:

  • 從故障角度看,高可用主要處理單組件故障導致的負載在集群內服務器之間做切換,容災則是應對大規模故障導致的負載在數據中心之間做切換。
  • 從網絡角度看,局域網是高可用的範疇,廣域網是容災的範疇。
  • 從雲的角度看,高可用是一個雲環境內保持業務連續性的機制,容災是多個雲環境間保持業務連續性的機制。
  • 從目標角度看,高可用主要是保證業務高可用,而容災則是在保證數據可靠的基礎上,業務對外連續可用,以盡可能降低RPO(災難發生時丟失的數據量)和RTO(災難發生時系統恢復時長)。

由此,我們可以看出,高可用往往是指本地的高可用系統或架構,表示在任一服務器出現故障時,應用程序或系統能迅速切換到其他服務器上運行的能力;而容災是指異地(同城或者異地)的冷備/熱備/雙活系統,表示在大規模集群或云級別災難發生時,數據、應用和業務在災備數據中心的恢復能力。 容災通常可以從網絡接入、應用治理、主機、數據存儲等層面去實施,業界如大型銀行的“兩地三中心”同城雙活+異地災備、螞蟻金服的“三地五中心”異地多活、餓了麼的北京上海雙機房“異地雙活”都是典型的容災架構方案。

從支付寶527大規模宕機事故、攜程528數據庫全線崩潰、AWS北京光纜被挖斷、騰訊雲硬盤故障、谷歌云K8s服務(GKE)宕機19小時不可用、微盟刪庫事件,再到近期的華為雲香港機房因製冷設備故障導致整個機房崩潰,無論是天災,還是人禍,居安思危並建立容災能力對一個企業的重要性是不言而喻的。

達達在2017-2018年飽受網絡故障之苦,如云網關組件故障、NAT網關故障、單運營商線路網絡連接故障等,這些問題往往讓我們束手無策。 為規避單云災難級風險,我們在調研並比較業界容災方案後,最終選擇雙雲架構做同城雙活的探索。

雙雲雙活一期

雙活一期主要是圍繞服務雙雲部署、業務分流和接口功能/性能等方面的探索驗證。

雙雲雙活一期架構圖

達達雙雲雙活實踐 1

雙雲雙活一期方案細節

雙雲雙活一期方案主要有以下幾個方面:

  • 跨雲專線:雙雲間通過2家供應商建立了4根高可用的跨雲專線,帶寬4Gb,時延3-4ms
  • 服務註冊:達達重度使用Consul,並基於Consul 1.1.0版本二次開發,實現了服務註冊發現、鏈路隔離、數據源發現和高可用切換等高級功能。 Consul採用一致性算法Raft來保證服務列表數據在數據中心中各Server下的強一致性,這樣能保證同一個數據中心,不論哪一台Server宕機,請求從其他Server中同樣也能獲取最新的服務列表數據。 數據強一致性帶來的副作用是當數據在同步或Server在選舉Leader過程中,會出現集群不可用(在接下來遇到問題中會分享我們遇到的問題)。

在雙雲雙活一期中,雙雲共用原有生產Consul集群,J雲的服務節點處於單獨拉取的鏈路而非base基礎鏈路,確保部署在J雲的核心服務間調用在J雲內部閉環。

  • 配置中心:雙雲共用原有生產配置中心Config,通過Config獲取服務相關參數、緩存和數據庫的連接地址。
  • 服務部署:J雲只部署了核心服務,並註冊到原有Consul集群,而配置中心、緩存、隊列、數據庫等均跨雲訪問U雲側原有集群。
  • 流量分發:達達的負載均衡LB是基於OpenResty+Consul建設的,並結合自身業務特點自研了一套流量控制邏輯,具備生產流量、灰度流量、壓測流量的轉發控制。 在雙活一期針對J雲類似灰度鏈路的流量控制,根據J雲機器的tag標籤,可以做到指定域名根據CityId實現可調百分比的外網流量經由跨雲專線打到J雲的服務節點之上。
  • 監控告警、日誌系統、應用性能、發布系統等均共用原有U雲生產環境。

雙雲雙活一期遇到的問題

在雙雲雙活一期架構中,J雲側核心服務的訂運單主流程功能驗證通過,但也遇到棘手問題。

1.接口響應時間過長

由於只有部分核心服務部署在J雲,其依賴的Redis、DB、隊列和其他服務等仍需要跨雲讀寫訪問,跨雲專線的3-4ms時延在多次跨機房請求下將延遲問題徹底放大,例如U雲側一個發單接口響應時間約在200ms,而在J雲側需要500ms+,這個響應時間對業務而言是無法接受的。

2.跨雲共用同一Consul集群有偶發風險

跨雲專線的網絡波動和3-4ms時延,這會造成跨雲使用LAN Gossip協議通信的同一個Consul集群發生紊亂情況。 我們曾遇到過J雲側Consul節點將U雲側正常節點投票下線繼而影響U雲生產集群的問題,也遇到過這種紊亂情況下,J雲的節點會瘋狂地消息廣播投票確認並導致專線帶寬急劇上升。 基礎架構團隊針對這些問題專門優化了Consul Gossip協議以降低對網絡延遲的敏感度。

達達雙雲雙活實踐 2

3.灰度用戶前後請求體驗有明顯差異

雙雲雙活一期的流量分發方案可指定到域名+按百分比分發流量+默認負載均衡輪訓後端,這樣雖然可以灰度驗證業務功能,但開啟雙活流量城市的騎士前後兩次請求如果流向不同雲,接口響應時延差別較大,相應體驗上會有較大差異。

雙雲雙活一期總結

實際結果證明,按以上所描述的一期方案來實施的雙雲雙活,沒有辦法達到預期結果,特別是比較大地影響了用戶體驗,更無法支持諸如搶單這類實時性較高的場景。 達達的雙活一期最終也以失敗告終。

雙雲雙活二期

針對同城雙活一期遇到的跨機房調用時延問題、跨云網絡波動可能引發Consul集群紊亂,以及業務流量精準分發一致性體驗等問題,我們進行了深度思考,形成了服務間交互單云內內斂、數據庫雙雲雙向複製、流量總控精細化配置三大核心點,並且結合業務場景依據數據訪問頻次、時延要求和數據一致性要求等維度,我們對數據和關聯服務進行了梳理和RCG模型分級。

此外,我們還在雙雲統一配置中心、服務一致性部署和發布、系統可觀測性、工具系統主備、容量規劃和成本控制方面做了相應功能迭代和能力建設。

雙雲雙活二期架構圖

雙雲雙活二期的架構圖如下所示

達達雙雲雙活實踐 3

雙雲雙活二期方案的三大核心點

達達雙雲雙活實踐 4

1.Consul多DC方案

雙活一期遇到的跨機房調用時延問題及跨云網絡波動可能引發Consul集群紊亂,這讓我們更清楚地認識到服務間請求單云內內斂的重要性,對Consul LAN Gossip與WAN Gossip協議適用不同場景的理解。

因此,雙活二期,我們採用了Consul多數據中心方案,官方示意圖如下:

達達雙雲雙活實踐 5

每個云有各自的Consul Server集群,consul client默認以LAN Gossip協議join到所在雲的Consul Server,不同雲之間Consul Server通過WAN Gossip協議join到一起。 在達達內部,每個服務會默認攜帶一個Sidecar並join到所在雲的Consul集群, Mysql和Redis也同樣以consul client方式join到所在雲的Consul集群,這樣通過Consul多DC架構和Consul服務發現,我們實現了服務間交互、服務與絕大多數數據源間交互在單云內內斂,也盡可能規避了一期遇到的問題。

2.數據庫雙雲雙向複製

為實現RZone模型的DB本地讀寫,且在數據庫水平項目沒有大規模開展的情況下,我們調整了雙雲兩側數據庫的自增步長為2,即auto_increment_increment=2,主鍵也做奇偶數區分,即U雲側主鍵是奇數,J雲側主鍵是偶數。

為實現雙A數據庫雙雲雙向穩定同步,我們採用了阿里開源的分佈式數據庫同步系統Otter,其架構圖如下:

達達雙雲雙活實踐 6

生產環境中,我們通過Otter不同的Channel管理不同雙A數據庫的雙向同步

達達雙雲雙活實踐 7

如下是生產環境Otter同步列表的TOPN

達達雙雲雙活實踐 8

目前,數據庫雙向複製時延平均0.9s,最大時延為2.2s(瞬間)

3.流量精準分發

我們利用OpenResty根據請求頭/體中/CityId/TransporterID/ShopID及域名+URI以精準分流。

如下圖,相比一期我們可以做到,針對pop.imdada.cn的某兩個具體的和訂單相關的URI,對城市ID 313和146 流量分發到J雲,其餘城市或pop其他接口默認分發到U雲(默認主IDC)。

同時,我們也做到騎士ID對齊城市ID,即如果某個騎士屬於這個城市,而且這個城市針對該騎士對應的業務也開啟了雙活流量,那麼該騎士的每次請求都會走到J雲。

達達雙雲雙活實踐 9

雙雲雙活二期方案之RCG模型分級

參考業務雙活解決方案,並結合業務場景依據數據訪問頻次、時延要求和數據一致性要求等緯度,我們對數據和關聯服務進行了梳理和RCG模型分級,如下

達達雙雲雙活實踐 10

雙雲雙活二期之工具/系統適配雙活

主要有以下幾個方面的工具系統改造支持並適配雙活

  • 配置中心:配置中心從Config遷移至Apollo,涉及達達數百個服務,生產環境的Namespace下,通過不同集群Cluster區分U雲和J雲的個性化配置, 並通過服務本地配置文件server.porperties對齊apollo的cluster名字和consul 的datacenter名字以取得正確的配置信息。 同時,Apollo本身依賴的幾個DB也在雙雲間做了數據庫主從同步,以備災難時切換。
  • 發布系統:得益於配置中心和中間件包版本的統一,我們實現了服務一次打包雙雲一致發布,這裡包含發布系統對雙雲兩側同一服務版本的一致、發布/回滾/重啟等變更批次的一致、變更邏輯步驟及消息通知的一致性。
  • 業務監控:業務監控系統為了更好的支持雙雲服務監控,對齊Consul集群datacenter名,業務只需選擇對應dc的tag即可切換到具體某個雲上查看服務的監控情況。
  • 應用性能監控:為了更好的監控服務間在單云內斂的交互情況,我們在雙雲各自部署了一套Pinpoint系統。
  • NTP時間同步服務:雙雲間時間步調不統一會直接影響業務問題的排除,而且在流量切回瞬間同一個未完成狀態的訂單可能會發生意想不到的情況。 我們在雙雲間建立了NTP服務主備,雙雲所有服務器默認與U雲的NTP Server每分鐘同步時間。
  • 鏡像倉庫:目前Harbor在雙雲各部署一套,默認是從U雲增量同步到J雲,災難時會切換J雲的Harbor為主鏡像倉庫。

雙雲雙活二期之容量彈性和成本控制

通常建立雙活會使雲資源成本接近等量的增加,我們也面臨同樣的困難,如何做好成本控制,我們的答案是從容器規劃和彈性擴縮容方面下功夫。

  • 數據庫:幾乎等量,但在調研從一主多+冷備集群往MGR方案遷移

  • 無狀態服務:引入原生容器,即時即用,在效率和成本上得到有效控制

在業務流量總量一定的情況下,流量在雙雲間調配,意味了雙云無狀態服務的負載也在隨之變化。 鑑於此,我們基於K8s HPA算法自研了Auto Scaling自動擴縮容系統支持雙活架構下的容量彈性,通過實時收集業務系統的多種metrics指標,實現了雙雲依據各自業務負載實時調節所需資源。

這樣,我們在保障業務系統雙雲穩定性的同時,又做到了成本有效節約。

雙雲雙活二期方案與業界雙活方案對比

達達雙雲雙活實踐 11

雙雲雙活現狀

目前落地配業務已穩定運行在雙雲之上,並且達達也具備了以城市為粒度任意在指定雲間切換業務處理量的能力。 不僅具有了抗IDC級別故障的能力,也達到了按業務和地域靈活灰度切換的預期。

未來規劃

未來需要在業務入層增加更多的Sharding Key(城市ID/騎士ID/商家ID/訂運單ID等),引入API Router以便於其他業務更好地在雙活架構下流量分發到準確的雲或機房;兜底Job改造為Pulsar延遲消息並在各個雲內執行,以避免因數據庫雙向同步時延且Job單邊運行造成業務上數據的錯亂;業務監控特別是單量的監控水位,需要能及時對齊流量切換比例;賬戶服務目前是默認在U雲的全局服務,擬採用TiDB方案以適配雙活架構;最後,雙活需要對齊數據庫水平拆分,流量切換從CityID維度變化為ShardingID維度便於流量調配和管理。

總結

回顧雙雲雙活兩期,我們希望盡可能藉助架構和運維的方式來解決同城雙活中遇到的問題,盡量對業務透明,減少業務改造成本,同時以落地配業務作為同城雙雲雙活架構的業務試點,以減少全局風險。 同時,我們希望積累相關經驗,為後續開展單元化和多雲多活打好基礎。 雙雲雙活的建設是一項複雜的系統工程,需要有點、線、面、體的維度思考和前瞻規劃。 在這里特別感謝雲平台各團隊、落地配研發團隊、物流平台團隊)、落地配運營團隊對雙活項目的大力支持。