天天看點

分布式資料庫:資料複制,如何保證資料在分布式場景下的高可用?

前面一篇我們講的是分片技術,它主要的目的是提高資料容量和性能。今天我們将介紹分布式資料庫另外一個重要根基:複制。

複制的主要目的是在幾個不同的資料庫節點上保留相同資料的副本,進而提供一種資料備援。這份備援的資料可以提高資料查詢性能,而更重要的是保證資料庫的可用性。

本講主要介紹兩種複制模式:單主複制與多主複制,并通過 MySQL 複制技術的演化來進行相應的展示。

現在讓我們開始學習單主複制,其中不僅介紹了該技術本身,也涉及了一些複制領域的話題,如複制延遲、高可用和複制方式等。

單主複制

單主複制,也稱主從複制。寫入主節點的資料都需要複制到從節點,即存儲資料庫副本的節點。當客戶要寫入資料庫時,他們必須将請求發送給主節點,而後主節點将這些資料轉換為複制日志或修改資料流發送給其所有從節點。從使用者的角度來看,從節點都是隻讀的。下圖就是經典的主從複制架構。

分布式資料庫:資料複制,如何保證資料在分布式場景下的高可用?

這種模式是最早發展起來的複制模式,不僅被廣泛應用在傳統資料庫中,如 PostgreSQL、MySQL、Oracle、SQL Server;它也被廣泛應用在一些分布式資料庫中,如 MongoDB、RethinkDB 和 Redis 等。

那麼接下來,我們就從複制同步模式、複制延遲、複制與高可用性以及複制方式幾個方面來具體說說這個概念。

複制同步模式

複制是一個非常耗費時間而且很難預測完成情況的操作。雖然其受影響的因素衆多,但一個複制操作是同步發生還是異步發生,被認為是極為重要的影響因素,可以從以下三點來分析。

  1. 同步複制:如果由于從庫已崩潰,存在網絡故障或其他原因而沒有響應,則主庫也無法寫入該資料。
  2. 半同步複制:其中部分從庫進行同步複制,而其他從庫進行異步複制。也就是,如果其中一個從庫同步确認,主庫可以寫入該資料。
  3. 異步複制:不管從庫的複制情況如何,主庫可以寫入該資料。而此時,如果主庫失效,那麼還未同步到從庫的資料就會丢失。

可以看到不同的同步模式是在性能和一緻性上做平衡,三種模式對應不同場景,并沒有好壞差異。使用者需要根據自己的業務場景來設定不同的同步模式。

複制延遲

如果我們想提高資料庫的查詢能力,最簡便的方式是向資料庫叢集内添加足夠多的從節點。這些從節點都是隻讀節點,故查詢請求可以很好地在這些節點分散開。

但是如果使用同步複制,每次寫入都需要同步所有從節點,會造成一部分從節點已經有資料,但是主節點還沒寫入資料。而異步複制的問題是從節點的資料可能不是最新的。

以上這些問題被稱為“複制延遲”,在一般的材料中,我們會聽到諸如“寫後讀”“讀單增”等名詞來解決複制延遲。但是這些概念其實是資料一緻性模型的範疇。

複制與高可用性

高可用(High availablity)是一個 IT 術語,指系統無中斷地執行其功能的能力。系統中的任何節點都可能由于各種出其不意的故障而造成計劃外停機;同時為了要維護系統,我們也需要一些計劃内的停機。采用主從模式的資料庫,可以防止單一節點挂起導緻的可用性降低的問題。

系統可用程度一般使用小數點後面多個 9 的形式,如下表所示。

可用性 年故障時間
99.9999% 32秒
99.999% 5分15秒
99.99% 52分34秒
99.9% 8小時46分
99% 3天15小時36分

一般的生産系統都會至少有兩個 9 的保證,追求三個 9。想要做到 4 個 9 是非常最具有挑戰的。

在主從模式下,為了支撐高可用,就需要進行故障處理。我這裡總結了兩種可能的故障及其處理方案。

  1. 從節點故障。由于每個節點都複制了從主庫那裡收到的資料更改日志,是以它知道在發生故障之前已處理的最後一個事務,由此可以憑借此資訊從主節點或其他從節點那裡恢複自己的資料。
  2. 主節點故障。在這種情況下,需要在從節點中選擇一個成為新的主節點,此過程稱為故障轉移,可以手動或自動觸發。其典型過程為:第一步根據逾時時間确定主節點離線;第二步選擇新的主節點,這裡注意新的主節點通常應該與舊的主節點資料最為接近;第三步是重置系統,讓它成為新的主節點。

複制方式

為了靈活并高效地複制資料,下面我介紹幾種常用的複制方式。

1. 基于語句的複制

主庫記錄它所執行的每個寫請求(一般以 SQL 語句形式儲存),每個從庫解析并執行該語句,就像從用戶端收到該語句一樣。但這種複制會有一些潛在問題,如語句使用了擷取目前時間的函數,複制後會在不同資料節點上産生不同的值。

另外如自增列、觸發器、存儲過程和函數都可能在複制後産生意想不到的問題。但可以通過預處理規避這些問題。使用該複制方式的分布式資料庫有 VoltDB、Calvin。

2. 日志(WAL)同步

WAL 是一組位元組序列,其中包含對資料庫的所有寫操作。它的内容是一組低級操作,如向磁盤的某個頁面的某個資料塊寫入一段二進制資料,主庫通過網絡将這樣的資料發送給從庫。

這種方法避免了上面提到的語句中部分操作複制後産生的一些副作用,但要求主從的資料庫引擎完全一緻,最好版本也要一緻。如果要更新從庫版本,那麼就需要計劃外停機。PostgreSQL 和 Oracle 中使用了此方法。

3. 行複制

它由一系列記錄組成,這些記錄描述了以行的粒度對資料庫表進行的寫操作。它與特定存儲引擎解耦,并且第三方應用可以很容易解析其資料格式。

4. ETL 工具

該功能一般是最靈活的方式。使用者可以根據自己的業務來設計複制的範圍和機制,同時在複制過程中還可以進行如過濾、轉換和壓縮等操作。但性能一般較低,故适合處理子資料集的場景。

多主複制

也稱為主主複制。資料庫叢集記憶體在多個對等的主節點,它們可以同時接受寫入。每個主節點同時充當主節點的從節點。

多主節點的架構模式最早來源于 DistributedSQL 這一類多資料中心,跨地域的分布式資料庫。在這樣的實體空間相距甚遠,有多個資料中心參與的叢集中,每個資料中心内都有一個主節點。而在每個資料中心的内部,卻是采用正常的單主複制模式。

這麼設計該類系統的目的在于以下幾點。

  1. 獲得更好的寫入性能:使資料可以就近寫入。
  2. 資料中心級别的高可用:每個資料中心可以獨立于其他資料中心繼續運作。
  3. 更好的資料通路性能:使用者可以通路到距離他最近的資料中心。

但是,此方法的最大缺點是,存在一種可能性,即兩個不同的主節點同時修改相同的資料。這其實是非常危險的操作,應盡可能避免。這就需要下一講要介紹的一緻性模型,配合沖突解決機制來規避。

還有一種情況是處理用戶端離線操作的一緻性問題。為了提高性能,資料庫用戶端往往會緩存一定的寫入操作,而後批量發送給服務端。這種情況非常類似于大家使用協作辦公文檔工具的場景。在這種情況下,每個用戶端都可以被看作是具有主節點屬性的本地資料庫,并且多個用戶端之間存在一種異步的多主節點複制的過程。這就需要資料庫可以協調寫操作,并處理可能的資料沖突。

典型的多主複制産品有 MySQL 的 Tungsten Replicator、PostgreSQL 的 BDR 和 Oracle 的 GoldenGate。

目前,大部分 NewSQL、DistributedSQL 的分布式資料庫都支援多主複制,但是大部分是用 Paxos 或 Raft 等協定來建構複制組,保證寫入線性一緻或順序一緻性;同時傳統資料庫如 MySQL 的 MGR 方案也是使用類似的方式,可以看到該方案是多主複制的發展方向。關于一緻性協定的内容我們将在後續課程中詳細介紹。

曆史的發展潮流是從單主複制向多主複制演變的,以上我們抽象地總結了複制的發展模式和需要關注的技術點。下面我将通過 MySQL 高可用技術的發展路徑,向你直覺地展示資料庫複制技術的發展脈絡。

MySQL 複制技術的發展

MySQL 由于其單機機能的限制,很早就發展了資料複制技術以提高性能。同時依賴該技術,MySQL 可用性也得到了長足的發展。

截止到現在,該技術經曆了四代的發展。第一代為傳統複制,使用 MHA(Master High Available)架構;第二代是基于 GTID 的複制,即 GTID+Binlog server 的模式;第三代為增強半同步複制,GTID+增強半同步複制;第四代為 MySQL 原生高可用,即 MySQL InnoDB Cluster。

資料庫的複制技術需要考慮兩個因素:資料一緻 RPO 和業務連續性 RTO。是以,就像前面的内容所強調的,複制與一緻性是一對如影随形的概念,本講内容聚焦于複制,但是會提到關于一緻性相關的概念。

下面我就從第一代複制技術開始說起。

MHA 複制控制

下圖是 MHA 架構圖。

分布式資料庫:資料複制,如何保證資料在分布式場景下的高可用?

MHA 作為第一代複制架構,有如下适用場景:

  1. MySQL 的版本≤5.5,這一點說明它很古老;
  2. 隻用于異步複制且一主多從環境;
  3. 基于傳統複制的高可用。

MHA 盡最大能力做資料補償,但并不保證一定可以成功;它也盡最大努力在實作 RPO,有 RTO 概念支援。可以看到它隻是一個輔助工具,本身的架構與機制對 RPO 和 RTO 沒有任何保障。

那麼由此可知,它會存在如下幾個問題:

  1. 它的 GTID 模型強依賴 binlog server,但是對于 5.7 後的 binlog 卻不能識别,同時對并行複制支援不好;
  2. 服務 IP 切換依賴自行編寫的腳本,也可以與 DNS 結合,其運維效果取決于運維人員的經驗;
  3. 運維上需要做 SSH 信任、切換判斷等人工操作,總體上處于“刀耕火種”的狀态,自動化程度較低,維護難度高;
  4. 現在項目基本無維護。

從上述問題中可以看到,MHA 作為第一代複制架構,功能相對原始,但已經為複制技術的發展開辟了道路,特别是對 GTID 和 binlog 的應用。但如果不是維護比較古老的 MySQL 叢集,目前已經不推薦采用它了。

半同步複制

這是第二代複制技術,它與第一代技術的差别表現在以下幾點。

  1. binlog 使用半同步,而第一代是異步同步。它保障了資料安全,一般至少要同步兩個節點,保證資料的 RPO。
  2. 同時保留異步複制,保障了複制性能。并通過監控複制的延遲,保證了 RTO。
  3. 引入配置中心,如 consul。對外提供健康的 MySQL 服務。
  4. 這一代開始需要支援跨 IDC 複制。需要引入監控 Monitor,配合 consul 注冊中心。多個 IDC 中 Monitor 組成分布式監控,把健康的 MySQL 注冊到 consul 中,同時将從庫複制延遲情況也同步到 consul 中。

下圖就是帶有 consul 注冊中心與監控子產品的半同步複制架構圖。

分布式資料庫:資料複制,如何保證資料在分布式場景下的高可用?

第二代複制技術也有自身的一些缺陷。

  1. 存在幻讀的情況。當事務同步到從庫但沒有 ACK 時,主庫發生當機;此時主庫沒有該事務,而從庫有。
  2. MySQL 5.6 本身半同步 ACK 确認在 dump_thread 中,dump_thread 存在 IO 瓶頸問題。

基于此,第三代複制技術誕生。

增強半同步複制

這一代需要 MySQL 是 5.7 以後的版本。有一些典型的架構來支援該技術,如 MySQL Replication Manager、GitHub-orchestrator 和國内青雲開源的 Xenon 等。

這一代複制技術采用的是增強半同步。首先主從的複制都是用獨立的線程來運作;其次主庫采用 binlog group commit,也就是組送出來提供資料庫的寫入性能;而從庫采用并行複制,它是基于事務的,通過資料參數調整線程數量來提高性能。這樣主庫可以并行,從庫也可以并行。

這一代技術體系強依賴于增強半同步,利用半同步保證 RPO,對于 RTO,則取決于複制延遲。

下面我們用 Xenon 來舉例說明,請看下圖(圖檔來自官網)。

分布式資料庫:資料複制,如何保證資料在分布式場景下的高可用?

從圖中可以看到。每個節點上都有一個獨立的 agent,這些 agent 利用 raft 建構一緻性叢集,利用 GTID 做索引選舉主節點;而後主節點對外提供寫服務,從節點提供讀服務。

當主節點發生故障後,agent 會通過 ping 發現該故障。由于 GTID 和增強半同步的加持,從節點與主節點資料是一緻的,是以很容易将從節點提升為主節點。

第三代技術也有自身的缺點,如增強半同步中存在幽靈事務。這是由于資料寫入 binlog 後,主庫掉電。由于故障恢複流程需要從 binlog 中恢複,那麼這份資料就在主庫。但是如果它沒有被同步到從庫,就會造成從庫不能切換為主庫,隻能去嘗試恢複原崩潰的主庫。

MySQL 組複制

組複制是 MySQL 提供的新一代高可用技術的重要組成。其搭配 MySQL Router 或 Proxy,可以實作原生的高可用。

從這一代開始,MySQL 支援多主複制,同時保留單主複制的功能。其單主高可用的原理與第三代技術類似,這裡我們不做過多分析了。

現在說一下它的多主模式,原理是使用 MySQL Router 作為資料路由層,來控制讀寫分離。而後組内部使用 Paxos 算法建構一緻性寫入。

它與第三代複制技術中使用的一緻性算法的作用不同。三代中我們隻使用該算法來進行選主操作,資料的寫入并不包含在其中;而組複制的多主技術需要 Paxos 算法深度參與,并去決定每一次資料的寫入,解決寫入沖突。

組複制有如下幾個優點。

  • 高可用分片:資料庫節點動态添加和移除。分片實作寫擴充,每個分片是一個複制組。可以結合上一講中對于 TiDB 的介紹,原理類似。
  • 自動化故障檢測與容錯:如果一個節點無法響應,組内大多數成員認為該節點已不正常,則自動隔離。
  • 方案完整:前面介紹的方案都需要 MySQL 去搭配一系列第三方解決方案;而組複制是原生的完整方案,不需要第三方元件接入。

當然,組複制同樣也有一些限制。主要集中在需要使用較新的特性,一些功能在多組複制中不支援,還有運維人員經驗缺乏等。

相信随着 MySQL 的發展,将會有越來越多的系統遷移到組複制中,多主模式也會逐漸去替代單主模式。

總結

我們深入介紹了複制技術在分布式資料庫中的作用;探讨了單主和多主兩種複制技術;而後通過 MySQL 複制技術的發展路徑來介紹了複制技術的應用案例。

如我在上面所描述的,複制往往需要與一緻性放在一起讨論。後續我們将詳細探讨一緻性問題,包括 CAP 理論與一緻性模型,并帶你研究它與複制的結合。

繼續閱讀