幹貨好文 | 兩地三中心到異地雙活演變及關鍵技術探討

兩地三中心和異地多活都是分佈式系統的關鍵技術,用於保證系統的高可用性和容錯性。其中最關鍵的技術無疑是數據同步、同步防環和數據沖突解決。

異地容災 & 兩地三中心

兩地三中心架構是一種分佈式系統的架構模式,用於保證系統的高可用性和容錯性。它將整個系統劃分為三個數據中心:兩個位於同城,一個位於異地。其中,同城的兩個數據中心分別承擔主備的角色,異地數據中心則作為備份。

在兩地三中心架構中,同城的兩個數據中心之間通過高速網絡進行數據同步,實現瞭主備切換和故障恢復。當主數據中心發生故障時,備份數據中心會自動接管服務,保證系統的連續性和可用性。同時,異地數據中心作為備份,可以在主備數據中心都出現故障時提供服務。

兩地三中心架構具有以下優點

  • 高可用性:通過主備切換和異地備份,保證瞭系統的高可用性和連續性。
  • 容錯性:當某個數據中心或服務器出現故障時,可以快速切換到其他可用的數據中心或服務器上,保證瞭系統的容錯性。
  • 靈活性:可以根據業務需求靈活配置數據中心的數量和位置,滿足不同的業務需求。
  • 性能優化:可以通過負載均衡等方式優化系統的性能,提高用戶體驗。
  • 安全性:可以通過數據同步和容災備份等方式保證數據的安全性和完整性。

以MySQL數據庫為例,可以通過同城雙向復制和異地異步復制來實現兩地三中心架構

以下是兩地三中心架構的部署架構:

  • 主數據中心:包括一個MySQL主庫和一個或多個MySQL從庫,主庫用於寫入操作,從庫用於讀取操作。
  • 同城備份數據中心1:包括一個MySQL主庫和一個或多個MySQL從庫,主庫用於備份主數據中心的數據,從庫用於讀取操作。
  • 異地備份數據中心2:包括一個MySQL主庫和一個或多個MySQL從庫,主庫用於備份主數據中心的數據,從庫用於讀取操作。

盡管兩地三中心架構具有很多優點,但也存在一些缺陷:

  • 成本高:由於需要建設多個數據中心和進行數據同步等操作,所以成本較高。
  • 配置復雜:兩地三中心架構需要對系統進行詳細的規劃和配置,包括主備切換、數據同步、負載均衡等方面,因此配置比較復雜。

配置這麼復雜,而且同城備份中心和異地備份中心基本上都用不到,造成瞭大量的資源浪費;並且大部分用戶並不能做到每個月/季度做一次容災演練,導致真正發生機房異常的情況下,同城或者異地容災中心並不能派上用場,用戶做兩地三中心並沒有什麼動力。

一般企業的選擇是:對部分核心業務和有監管要求的數據庫才會搭建同城容災,並且對異地容災會盡量縮減規模,例如:主中心是一主兩從,而異地容災中心可能隻有一個數據庫實例,去掉瞭從機。

總之,兩地三中心架構的部署需要對系統進行詳細的規劃和配置,並且需要考慮多個數據中心之間的協調和管理。

異地多活 & 單元化

上面說的兩地三中心和異地容災方案成本高、配置復雜、真正需要的時候不一定用的上,有些企業特別是業務在全國甚至全球范圍需要本地化訪問時會采用異地多活(或者稱為單元化)的解決方案。

異地多活架構(Active-Active Architecture)是一種分佈式系統架構,它允許多個數據中心同時處理用戶請求,並且這些數據中心之間可以相互協作,實現數據的共享和同步。異地多活架構有以下優缺點:

優點:

  • 高可用性:異地多活架構可以在多個數據中心之間進行負載均衡和故障轉移,從而提高瞭系統的可用性和容錯性。
  • 低延遲:由於數據中心之間可以相互協作,因此可以將數據盡可能地靠近用戶,減少網絡延遲和響應時間。
  • 數據共享:異地多活架構可以實現數據的共享和同步,從而提高瞭數據的可靠性和一致性。
  • 靈活性:異地多活架構可以根據實際需求進行擴展和縮減,從而滿足不同規模和復雜度的業務需求。

異地多活最大的挑戰來自於數據庫,最主要的來自於數據一致性:由於異地多活架構需要實現數據的共享和同步,因此需要解決數據一致性的問題,避免出現數據沖突和錯誤。

閑話少說,舉例為證:假設你是一個MySQL DBA,你們公司有三個機房:北京、廣州和上海。領導要求你提供一個解決方案:讓每個地區的客戶都就近訪問本地的數據庫,華北的客戶數據存儲在北京的數據庫,華東的客戶數據存儲在上海的數據庫,華南的客戶數據存儲在廣州的數據庫上。這些數據庫的數據需要能相互同步,保證數據一致,以便華北的用戶出差到上海以後可以就近訪問上海數據庫上的數據(這些數據是華北這個客戶的數據從北京同步到上海的),在上海出差產生的數據同樣應該同步回北京。這樣客戶出差回北京以後,他可以繼續訪問和更新“最新”的數據。

對應的,你就需要搭建一個異地多活架構來實現數據的就近訪問和不同中心的數據同步。具體的方案如下:

  • 在每個機房都部署一套MySQL數據庫。
  • 通過VPN隧道或者其他技術,打通各個機房的網絡,讓MySQL可以建立復制鏈路。
  • 配置MySQL GTID復制,搭建雙向復制,將不同機房之間的數據進行雙向同步,保證數據的一致性和可靠性。

簡單的示意圖如下:

總之,異地多活架構是一種高級別的分佈式系統架構,具有高可用性、低延遲、數據共享和靈活性等優點,但也存在復雜性、成本較高、數據一致性和安全性等缺點,需要根據實際情況進行選擇和應用。

同步防環

如前所述,不管是兩地三中心還是異地多活,其中比較關鍵的就是雙向同步(兩地三中心中的同城雙向同步,異地多活的多中心雙向同步),保證業務在一個中心寫的數據可以復制到另外一個中心。數據庫原生提供的復制有些本身是可以搭建雙向復制的,但是這種方式隻能做到實例級別同步(無法支持where條件過濾或者做對象名映射)、無法定制化修改(需要有內核修改能力並且修改後必須停業務以升級數據庫),監控和管理不直觀(命令行式,操作不便)。一般使用專業的雙向同步工具或者其他第三方工具來實現,以保證易用性、易維護性,提供定制化修改和監控管理功能。

沃趣科技的DBMotion實現瞭MySQL和openGauss的雙向同步,它不依賴於數據庫原生的復制,采用獨立的cdc解析模塊從源庫中獲取重做日志並解析,通過sink模塊將源庫中的變更並行應用到目標庫。如下圖所示,如果不做特殊處理,將會出現循環復制的問題。

還是以MySQL為例,上圖中兩個MySQL實例分別位於華東中心和華南中心,如果通過DBMotion做雙向同步,那麼在華東中心插入一行數據,通過DBMotion在華南回放,也會插入一行數據;但是反向的DBMotion解析到這條insert的數據,又會將它同步回華東中心。也就產生瞭循環復制,如果是無主鍵表,insert不產生唯一約束沖突,這個insert將在華東和華南永續循環復制下去。

當然,通過MySQL基於server-id是可以避免的。如圖,在db1插入的數據,插入到db2的時候,在日志中也記錄為server-id=1。這樣dbmotion的反向復制,檢查到server-id為1的日志要同步回來,就可以安全的過濾掉。

但是這種方式需要精準的控制每個中心所有數據庫的server-id,下圖中如果是server-id=1產生的更新,就會在華南中心的雙master實例間做無限循環復制。

當然,MySQL也可以利用GTID來實現,但是GTID並不是所有的客戶都開啟的,如何兼容是一個問題。

上面隻是以MySQL這種邏輯復制避免循環復制的方案。openGauss原生的復制目前是另外一種方案:華東中心復制寫入華南中心的時候不記錄日志。這樣反向復制同步時,取不到正向同步的數據,也就不會形成循環復制。當然這種方式會導致華南中心的備庫沒有華東中心過來的數據,對於多中心數據同步也是無法級聯同步數據的。

DBMotion采用的是類似於server-id打標的方式,在數據寫入華南中心的時候對日志進行標記, 保證DBMotion寫入的數據,在DBMotion日志解析的時候能夠被認出來,避免數據被復制回華東中心。

如果擴展到多中心,還是會存在循環復制的問題,如圖:在華北中心插入的數據被標識為region3,復制到華東和華南中心時,他們發現數據都不是自己發出的時候,就會出現循環復制的問題。

此時,DBMotion就需要做額外的處理,在華東中心把華北過來的數據和業務請求的數據統一標記成region1,這樣在華南過來的業務數據沒有標記,而從華東過去的數據都有標記,就可以將打標的更新成功過濾。

當然,這種同步還是避免不瞭用戶故意搭建的環形復制鏈路產生循環復制,所以DBMotion支持的異地多活,目前隻能支持樹形復制,類似於下圖的結構。在region-id=6的數據庫上插入一筆數據,通過DBMotion同步到region-id=2的節點時,會將2標記為同步到region-id為1和5的節點,並且從1和5同步回來時會自動被過濾掉,之後會依次被同步到3,4;7;8。

綜上,“同步防環”可以解決一條更新在多個中心上循環復制的問題,異地雙活的關鍵技術難點“循環復制”,可以通過打標忽略的方式解決。

沖突解決

異地多活又稱為單元化,前提是業務可以單元化,讓客戶同時隻在一個單元上操作。

如前文中提到的,北京的用戶無論是在北京還是在上海,隻會在不同的時間點更新自己的數據,不會出現在多個中心同時更新同一筆數據的情況。如果需要在同時在同一個時間點更新同一個數據,如北京和上海的用戶同時匯款給廣州的客戶,就可能同時對廣州的客戶賬戶有兩個增加餘額的操作。

這種同時在多中心操作同一筆數據的方式,需要在業務上嚴格避免,或在業務架構上使用集中式架構,在同一個中心(或者通過同城多中心的分佈式數據庫)應對所有單元的更新請求;或對業務進行單元化分拆(以上面的匯款案例為例,廣州的用戶應該在北京和上海都有子賬戶,收到匯款隻是在北京和上海的子賬戶上增加餘額,對應的廣州的這個用戶查詢餘額就需要匯總所有中心的賬戶餘額瞭)。

另外,復制延遲也有可能導致沖突,例如北京的客戶出差到瞭上海來更新自己的數據,此時在北京的部分更新還沒有同步到上海,那麼也會出現類似於兩邊同時寫同一份數據的沖突。

上述數據沖突的問題,都必須在業務或者說在數據庫的上層解決。通過數據同步將數據已經寫入到數據庫後,數據沖突在“下層”是無法解決的,隻能檢測沖突,提醒客戶有沖突發生,並提供相關的沖突解決策略去輔助客戶解決這個問題。

DBMotion通過匹配前鏡像和後鏡像更新報錯來發現沖突,目前提供兩種機制來處理沖突

  1. 復制鏈路可以指定沖突錯誤忽略列表,用戶可以指定對部分沖突報錯直接忽略報錯,類似於MySQL的replica_skip_errors錯誤。例如:用戶需要對Duplicate Key報錯進行忽略,可以直接在沖突錯誤忽略列表中增加1062錯誤。
  2. 復制檢測到沖突可以按照復制沖突策略來自動處理沖突。

DBMotion復制檢測到沖突目前有三種沖突解決策略可以指定:

  • 報錯:DBMotion在檢測到沖突以後就報錯停止,配合上短信和郵件報警,用戶收到報錯後可以查看並手工解決沖突以後,點“繼續”會讓DBMotion斷點續傳從上次報錯的位置繼續同步。
  • 忽略:DBMotion在檢測到沖突後,隻會在日志中記錄沖突,忽略錯誤並繼續同步。
  • 覆蓋:DBMotion會直接以主鍵或者唯一鍵對目標庫進行覆蓋,保證目標庫和源庫一致,繼續同步。

總結

綜上,沖突解決是異地多活和分佈式數據庫面臨的通用問題,需要在業務架構上盡量避免。DBMotion在數據庫同步的時候提供瞭兩種機制,三種策略來輔助客戶檢測沖突和設置沖突解決策略。

目前DBMotion已經在Squids上上線,為客戶提供異地、跨雲的MySQL和openGauss多活業務訪問,未來將繼續支持更多的多活場景。

赞(0)