天天看點

水準擴充太難了!PolarDB-X 為你支招

引言

水準擴充(Scale Out)對于資料庫系統是一個重要的能力。采用支援 Scale Out 架構的存儲系統在擴充之後,從使用者的視角看起來它仍然是一個單一的系統,對應用完全透明,是以,它可以使資料庫系統能有效應對不同的負載場景,對使用者非常用價值。

但是,資料庫本身是一個有狀态的系統,是以,它的水準擴充是一件比較困難的事情。資料庫通常需要管理着龐大的資料,系統在擴充期間,如何保證資料一緻性、高可用以及系統整體的負載均衡,更是整個水準擴充的難點。

水準擴充按不同資源類型分類,可以細分為計算節點的水準擴充與資料節點的水準擴充,後文若無特别說明,水準擴充特指資料節點的水準擴充。而資料節點的水準擴充,按查詢請求的類型,也可以進一步劃分為讀能力的擴充與寫能力的擴充。

單機資料庫的擴充

MySQL 主從複制

在單機資料庫時代,資料庫的讀寫流量全集中在一台實體機。是以,單機資料庫要做擴充,  一個簡單有效的思路,就是将單機資料庫的資料裡複制一份或多份隻讀副本,然後應用自己做讀寫分離。

早期 MySQL(5.5及以下版本)基于主從複制協定實作了主備庫架構[17],依靠備庫實作了讀能力的擴充,但主庫與備庫之間同步是采用異步複制或半同步複制,備庫的資料總會有一定資料延遲(毫秒級或亞秒級)。

MGR 與 多主模式

後來 MySQL 在5.7引入了基于Paxos協定[14]的狀态機複制技術:組複制[13]功能,徹底解決了基于傳統主備複制中資料一緻性問題無法保證的情況。組複制使MySQL可以在兩種模式下工作:

  • 單主模式(Single-Master)。單主模式下,組複制具有自動選主功能,每次隻有一個 Server成員接受寫入操作,其它成員隻提供隻讀服務,實作一主多備。
  • 多主模式(Multi-Master)。多主模式下,所有的 Server 成員都可以同時接受寫入操作,沒有主從之分,資料完全一緻,成員角色是完全對等的。

但是,無論是單主模式還是多主模式,都隻能支援讀能力的擴充,無法支援寫能力的擴充(事實上,MGR的多主模式更多的作用是用于高可用與容災)。原因很好了解,即使在多主模式下,每個Server節點内實際所接收的寫流量(來自用戶端寫流量+來自Paxos協定的複制流量)是大緻相同的。随着Paxos Group的成員增多,寫放大的現象将越來越嚴重,将大大影響寫吞吐。此外,MGR采用樂觀沖突檢測機制來解決不同節點的事務沖突,是以在沖突頻繁的場景下可能會出現大量事務復原,對穩定性影響很大。

分布式資料庫的擴充

與單機資料庫不同,分布式資料庫本身就是為了解決資料庫的擴充問題而存在。比如, 目前相對主流的以Google Spanner[10]、CockroachDB[5]、TiDB[4]等為代表NewSQL[9]資料庫,大多都是基于Shared-Nothing架構,并對資料進行了水準分區,以解決讀寫擴充問題;每個分區又通過引入Raft[14]/Paxos[15]等的一緻性協定來實作多副本的強一緻複制,并以此來解決分區的高可用與故障容災問題。是以,水準擴充在分布式資料庫中是一個重要而基礎能力。

這裡将以 CockroachDB  為例來探讨分布式資料庫的水準擴充過程。CockroachDB 是一個參考Google Spanner[10]論文的實作的開源的 NewSQL 資料庫。一個 CockroachDB 叢集是由多個 Cockroach Node 組成,每個Cockroach Node 會同時負責SQL執行與資料存儲。CockroachDB 底層的存儲引擎 RocksDB 會将資料組織成有序的 Key-Value 對形成一個KV map。

資料分區

為了支援水準擴充,CockroachDB 會按 KV map 的key的取值範圍,在邏輯上水準切分為多個分片,稱為 Range。每個 Range 之下會有多個副本(副本數目可配),這些副本會分布在不同的 Cockroach Node 中, 并共同組成了一個 Raft Group,借助 Raft 協定進行強一緻同步,以解決分區級别的高可用與故障容錯。Range中被選為 Raft Leader 的 Range 副本 稱為 LeaseHolder,它不但要負責承擔來自使用者端的寫入流量,還要負責 Range 後續的變更與維護(例如,Range 的分裂、合并與遷移);而其它非Leader 的副本則可以承擔讀流量。為了管理整個系統的中繼資料,CockroachDB 中有一個特殊 Range,名為 System Range,用以儲存各個 Table 中繼資料及其它各個 Range 的實體位置資訊。然後,CockroachDB 會基于實際負載情況與資源情況,去排程各個Range 的 LeaseHolder,讓它們均衡地散落在各個 Cockroach Node,以達到讀寫流量能均攤到不同機器節點的效果。

水準擴充太難了!PolarDB-X 為你支招

水準擴充

CockroachDB 在水準擴充新增加節點時,為了能将一些Range的流量排程到新加入的節點,它會反複多次做兩個關鍵的操作:遷移 Range與分裂 Range。

遷移 Range。它可用于解決不同 Cockroach Node 之間負載不均衡。例如,當系統增加了 Cockroach Node,CockroachDB 的均衡排程算法會檢測到新增 Cockroach Node 與其它老 Cockroach Node 形成負載不均衡的現象,于是會自動尋找合适的 Range 集合,并通知這批 Range 的 LeaseHolder 自動切換到新增的 Cockroach Node 中。借助 Raft 協定,LeaseHolder 要将自己從 Cockroach Node A 移動到 Cockroach Node B,可以按下述的步驟輕易完成:

  • 先往 Raft Group 中增加一個新副本B(它位于 Cockroach Node B );
  • 新副本B 通過回放全量的 Raft Log 來和 Leader 資料一緻;
  • 新副本B 完成同步後,則更新 Range 中繼資料,并且删除源副本A(它位于 Cockroach Node A)。

分裂 Range。若 Range 數目過少時,資料無法被完全打散的,流量就會被集中少數 Cockroach Node,造成負載不均。是以,CockroachDB 預設了單個 Range 最大允許是64MB(可配置),若空間超過門檻值,LeaseHolder 會自動對 Range 進行分裂。前邊說過,Cockroach Node 的 Range 劃分是邏輯劃分, 是以,分裂過程不涉及資料遷移。分裂時,LeaseHolder 會計算一個适當的候選Key作為分裂點,并通過 Raft 協定發起拆分,最後更新Range 中繼資料即可。

當 Range 經過多次分裂後,産生更多的LeaseHolder,CockroaachDB 的均衡排程算法就可以繼續使用遷移 Range 的操作讓讀寫流量分散到其它 Cockroach Node ,進而達到水準擴充且負載均衡的效果。

PolarDB-X 的水準擴充

PolarDB-X 作為阿裡巴巴自主研發的分布式資料庫,水準擴充的能力自然是其作為雲原生資料庫的基本要求。但談及分布式資料庫的擴充能力,通常離不開其架構與分區管理兩個方面。接下來,我們通過介紹其架構與分區管理,再來詳細說明  PolarDB-X 的水準擴充實作方案。

架構

為了最大限度地發揮其雲資料庫的彈性擴充能力,PolarDB-X 一開始就決定采用了基于存儲計算分離的Shared-Nothing架構,以下是 PolarDB-X 的架構圖:

水準擴充太難了!PolarDB-X 為你支招

如上圖所示,PolarDB-X整個架構核心可分為3個部分:

  1. GMS(Global Meta Service):負責管理分布式下庫、表、列、分區等的中繼資料,以及提供TSO服務;
  2. CN(Compute Node):負責提供分布式的SQL引擎與強一緻事務引擎;
  3. DN(Data Node):提供資料存儲服務,負責存儲資料與副本資料的強一緻複制。

PolarDB-X 存儲層使用的是 X-DB 。是以,每一個 DN 節點就是一個 X-DB 執行個體(X-DB的介紹請看這裡)。X-DB 是在 MySQL 的基礎之上基于 X-Paxos 打造的具備跨可用區跨地域容災的高可用資料庫,使用 InnoDB 存儲引擎并完全相容 MySQL 文法,  它能提供 Schema 級别的多點寫 與 Paxos Group 的 Leader 排程的能力 。PolarDB-X 的分區副本的高可用與故障容災就是建立在X-DB基礎上的。

相比其他同樣采用 Multi-Group Paxos / Raft 設計的 NewSQL,如 CockroachDB[5]、YugabyteDB[16]等,PolarDB-X  始終堅持與基于 MySQL 原有架構進行一體化的設計的 X-DB 相結合,一方面是考慮到這樣能讓 PolarDB-X 在MySQL相關的功能、文法以及上下遊生态的相容性與穩定性上更有優勢;另一方面是 X-DB 本身具有較強的複雜SQL處理能力(比如Join、OrderBy等),這使得 PolarDB-X 相對友善地通過向 X-DB 下推SQL來實作不同場景的計算下推(比如,Partition-wise Join 等),能大大減少網絡開銷,提升執行性能,是 PolarDB-X 的一個重要特性。

資料分區與表組

與 CockroachDB 等分布式資料庫類似, PolarDB-X 也會對資料進行切分。在 PolarDB-X 中,每個表(Table)的資料會按指定的分區政策被水準切分為多個資料分片,并稱之為分區(Partition)。這些分區會分布在系統的各個DN節點中,而各個分區在DN的實體位置資訊則由 GMS 來統一管理。每個分區在 DN節點中會被綁定到一個 Paxos Group,并基于 Paxos 協定建構資料強一緻的多副本來保證分區組的高可用與容災,以及利用多副本提供備庫強一緻讀。Paxos Group 會通過選舉産生分區 Leader, Leader 的分區組負責接收來自CN節點的讀寫流量;而 Follower 的分區組則負責接收CN節點的隻讀流量。

分區政策

我們知道,分布式資料庫常見的分區政策有多種,諸如  Hash / Range / List 等,分布式資料庫往往選取其中的一種作為其内部預設的分區方式,以組織與管理資料。像前邊提及的 CockroachDB[5] 的預設分區政策是按主鍵做 Range 分區,YugabyteDB[16] 的預設分區政策則是按主鍵做一緻性 Hash 分區。那麼,PolarDB-X 的預設分區政策采用是什麼呢?PolarDB-X 的預設分區也是采用一緻性 Hash 分區,之是以這樣選擇,主要是基于兩點的考量:

  1. 對一個主鍵做範圍查詢的場景在實際情況中并不是很常見,與Range分區相比,一緻性 Hash 分區能更有效将事務寫入打散到各個分區,能更好負載均衡;
  2. 分布式資料庫在進行水準擴充,往往需要添加新的DN節點,采用一緻性 Hash分區能做到按需移動資料,而不需要對全部分區資料進行rehash。

是以,相比于CockroachDB ,PolarDB-X 的預設的一緻性Hash分區能更好均攤寫入流量到各個分區,這對後邊的動态增加DN節點做水準擴充很有意義。

除了預設分區政策,PolarDB-X也支援使用者自己指定分區 Hash / Range / List 等分區政策來管理各分區的資料, 關于 PolarDB-X 分區方式的更多的思考,讀者可以參考

《探索 | PolarDB-X:實作高效靈活的分區管理》

這篇文章。

表組與分區組

在PolarDB-X中,為加速SQL的執行效率,優化器會嘗試将分區表之間Join操作優化為Partition-Wise Join來做計算下推。但是,當分區表的拓撲發生變更後,例如,在水準擴充中,分區會經常發生了分裂、合并或遷移後,原本分區方式完全相同的兩張分區表,就有可能出現分區方區不一緻,這導緻這兩張表之間的計算下推會出現失效(如下圖所示),進而對業務産生直接影響。是以,與CockroachDB相比, PolarDB-X 創造性地通過引入表組與分區組來解決這類問題。

水準擴充太難了!PolarDB-X 為你支招

在PolarDB-X中,如果有多個表都采用了相同的分區政策,那麼,它們在邏輯上會被PolarDB-X劃分為一個組,稱之為表組(Table Group)。表組内各個表所對應的相同分區的集合,也會被劃分成一個組,叫分區組(Partition Group)。是以,若兩張表是屬于同一個表組的,PolarDB-X可認為它們采用了完全一緻的分區政策,這兩張表的各個分區所處的實體位置可以被認為完全相同。這樣優化器就會根據兩張表是否屬于表組來判斷是否做計算下推。

基于上述定義的分區組,PolarDB-X 隻要限制所有的分區變更必須要以分區組為機關(即分區組内的各分區,要麼同時遷移、要麼同時分裂),即可保證在水準擴充的過程中,PolarDB-X 的計算下推不受影響。後文為闡述友善,如無特别說明,所有對分區的操作,預設都是指對分區組的操作。

當引入了表組與分區組後,PolarDB-X還可以額外地滿足使用者對容災隔離、資源隔離等場景的需求。因為表組與分區組本質上是定義了一組有強關聯關系的表集合及其分區的實體位置資訊,是以,同一分區組的分區集合所處的DN節點必然相同。例如, 使用者可以采用按使用者的ID進行LIST分區建表,然後通過指定分區組的實體位置資訊(PolarDB-X支援修改分區組的位置資訊),将業務的大客戶/重要客戶單獨的資料劃分到更高規格更可靠的DN節點,來實作資源隔離。

水準擴充流程

介紹完PolarDB-X的架構與分區政策後,我們開始介紹PolarDB-X的水準擴充。從效果來看,水準擴充的最終目标,可歸結為兩個:系統沒有明顯熱點,各分區負載均衡;系統的處理能力與所增加的資源(這裡的資源主要是DN節點)能呈線性的增長。前邊分析的 CockroachDB 的例子, CockroachDB 在做水準擴充過程中,系統的負載均衡其實是通過多次主動的分裂分區或合并,生成多個Range,   然後再通過Leader排程,将各Range的LeaderHolder (負責讀寫流量的Range) 均衡地散到新加入的CockroachDB節點中來實作。

事實上,CockroachDB 的水準擴充的過程, 放在 PolarDB-X 也是同樣适用的。當使用者通過 PolarDB-X 預設的一緻性Hash預建一些分區後, 它的均衡排程器在核心也會通過多次的分區分裂或合并,來讓各分區達到相對均衡的狀态(因為即使按預設一緻性Hash分區,使用者的業務資料本身或通路流量在各分區也可能是不均衡的),達到沒有現明顯的熱點分區。這時,當有新加DN節點加入時,均衡排程器就可以将一部分分區的流量通過分區遷移的方式,将它們切到新DN節點上,從達到擴充的效果。是以,PolarDB-X 的水準擴充,從大體上流程會有以下幾個步驟:

  1. 加入節點。系統添加一個新的空的DN節點;
  2. 分區排程。均衡排程器決定需要遷移到新DN節點的分區;
  3. 分區變更。執行分區遷移任務(這個過程可能同時還伴随有分區分裂或分區合并的操作);
  4. 流量切換。被遷移的分區的流量切換到新DN節點,達到負載均衡狀态。

整個過程的實作要依賴到的分區變更操作有3種:分區遷移、分區分裂與分區合并,這一點與 CockroachDB 類似。分區遷移主要用于解決不同DN節點之間負載不均衡的問題,而分區的分裂與合并則可用于解決不同分區之間的負載不均的問題以及因分區數目不足水準擴充受限的問題。下邊我們繼續關注 PolarDB-X 這3種分區變更操作是如何實作。

基于 Online DDL 的分區遷移

分區遷移通常需要兩個步驟分區複制與流量切換兩個階段。像 CockroachDB 基于 Raft 協定來完成跨節點間的資料複制以及 Leader切換(流量切換),是以它的分區遷移能幾乎全被封裝Raft協定裡進行。但是,PolarDB-X 跨DN節點之間的分區複制,并沒有基于  Raft/Paxos 協定 ,而是參考 SAP HANA 提出的非對稱分區複制[2] 的思路,采用了 Online DDL [1]  的方案。

更具體來說,就是 PolarDB-X 會将分區副本的資料複制操作,看作是一次給主表(源端DN節點)添加一個特殊索引(目标端DN節點)的DDL操作,這個特殊索引會備援主表所有的列。是以,整個分區複制的過程就等價于基于 Online DDL 添加一次索引。類似地,PolarDB-X的流量切換沒有借助走 Raft/Paxos 協定的切主來進行切流,而是采用基于 Online DDL 删除索引的方式來完成流量從源端(老DN節點)到目标端(新DN節點)的對應用近乎透明的平滑切換,這個過程在PolarDB-X中被稱為透明切換。

如下圖所示,組成 PolarDB-X 分區遷移的 分區複制 與 透明切換 兩個關鍵階段。

水準擴充太難了!PolarDB-X 為你支招

下邊将會詳細介紹PolarDB-X  是如何基于 Online DDL 來實作分區複制與透明切換,以及最終達對使用者透明的效果。這裡邊會涉及 Google F1 論文《Online, Asynchronous Schema Change in F1》一些細節,建議讀者可以先讀下PolarDB-X 的這篇文章

《PolarDB-X Online Schema Change》

了解 Online Schema Change中原理。

分區複制

分區複制的任務是要在目标DN節點上建構一個新的分區副本。借助 Online Schema Change,該階段會對目标分區進行一次添加“索引表”的操作,完成後該 “索引表” 便成為新的分區副本。是以,分區複制的DDL任務狀态與添加索引的類似,分為 Absent、DeleteOnly、WriteOnly、 WriteReorg 與 ReadyPublic 5個狀态(如下圖所示)。

水準擴充太難了!PolarDB-X 為你支招

前三個狀态 Absent、DeleteOnly、WriteOnly 的定義與添加索引的完全一緻,新引入的兩個狀态 Write Reorg 與 Ready Public 的定義如下:

  • WriteReorg。處于該狀态的節點的行為與 Write Only 完全一緻,即要負責維護主表(即原分區)所有的增量資料及其索引表(即新分區副本)資料的一緻性。可是,當節點處于該狀态時,說明 GMS 正在執行資料回填(BackFill)任務來為主表的存量資料補充其索引資料。
  • ReadyPublic。處于該狀态的節點的行為與 Write Only 也完全一緻。可是,當節點處于該狀态時,說明 GMS 的 BackFill 任務與相關的資料校驗工作已經完成,此時節點會認為目前主表與索引表的資料已完全一緻,可随時進入下一階。

    ◇ 分區複制的DDL任務狀态新引入上述兩個狀态,目的有兩個:(1)資料回填任務通常運作時間比較長(從幾分鐘到幾小時不等),通過将資料回填任務單獨抽象為 WriteReorg 狀态,可友善CN節點的SQL引擎能針對該狀态下的DML的執行計劃做一些優化工作;(2)當完成資料回填任務後,目标分區其實并不需要真的像索引表那樣要對外開放檢索,而是需要馬上進入下一階段,是以,需要 ReadyPublic (與Public區分)這個狀态來讓節點知道目前主表與索引表的資料已經完全一緻,達到進入下一階段的要求。

透明切換

透明切換的任務是要将原分區的讀寫流量全部切換到新的分區副本,并且要全程對應用保持透明。所謂保持透明,就是在整個切換過程中,不能産生讓應用感覺的報錯,不能讓應用的讀寫流量受影響,不能讓資料産生不一緻。那常見的流量切換方案,例如,直接切流、停寫後再切流等方案,是否能滿足“透明”的要求呢?我們可分情況讨論。

水準擴充太難了!PolarDB-X 為你支招

如果采用直接切流的方案(上圖左側),那切換期間分布式系統中便會因為節點狀态不相容(因為所有節點不可能在同一時間完成切換)而導緻出現資料不一緻;如果采用停寫後再切流的方案(上圖右側),那需要通知分布式系統所有節點來阻塞業務所有的寫操作,但通知過程本身時間不可控(或網絡故障或節點自身不可用),應用有可能導緻被長時間阻塞寫,進而使應用側會産生逾時異常。可見,無論是直接切流還是停寫後再切流的方案,都不能滿足保持透明的要求。

PolarDB-X為了實作透明的切換效果,其思路是将目标端分區看作是主表,将源端分區看作是索引表,并對主表進行一次标準的删除索引的 Online DDL 操作(其狀态過程是 Public-->WriteOnly-->DeleteOnly-->Absent ,與 Online Schema Change 定義的一緻)。

水準擴充太難了!PolarDB-X 為你支招

如上圖所示,在  Online DDL 期間,由于新索引表會被逐漸下線,CN節點的SQL引擎根據不同DDL狀态,将不同類型的流量分步驟地從源端(索引表)切換到目标端(主表):先切Select流量(WriteOnly狀态,索引表不可讀),再切Insert流量(DeleteOnly狀态,索引表不可插入增量),最後才切Update/Delete/加鎖操作等流量(Absent狀态,索引表不再接收寫入)。基于 Online DDL ,整個切換會有以下幾點的優勢:

  • 切期期間業務讀寫不會因被阻塞(不需要禁寫);
  • 切換期間不會産生死鎖(因為在WriteOnly與DeleteOnly狀态的節點,加鎖順序都是一緻);
  • 切換期間不會産生資料不一緻的異常(Online Schema Change 論文已證明)。

這些優勢使得流量切換全程能對應用做到了透明。

多表并行與流控

前邊說過,為了保持計算下推,PolarDB-X 的分區遷移其實是以分區組為來機關進行。一個分區組通常會有多個不同表的分區,是以,分區遷移過程産生的資料回填任務,通常是将分區組内的多個分區進行并行回填,以加速遷移的速度。

回填任務是一個比較消耗時間與消耗資源的背景操作,涉及源端到目标端的大量資料複制,如果其速率太快,容易過多地占用DN節點的 CPU 與 IO 資源,對業務的正常讀寫造成影響;如果其速率太慢,分區遷移過程的運作時間又可能會太長。是以,在Online DDL 的架構下,資料回填任務會支援進行動态流控:一方面允許按人工介入來調整任務的狀态(例如暫時任務),另一方面可以根據節點的資源情況來動态調整資料回填速率,以避免對業務産生過多影響或遷移過程太慢的問題;

透過資料回填的流控例子,PolarDB-X  基于 Online DDL 的分區遷移方案,相比于 CockroachDB 等基于 Raft 協定做一緻性複制的方案,雖然增加了一定的實作複雜度,但卻可以帶了更靈活的對使用者更友好的可控性。

基于  Online DDL 的分區分裂

PolarDB-X 分區 與 CockroachDB 分區 的存儲方式有一定的差異:同一 Cockroach Node 中不同 Range 隻是邏輯上的劃分,實體存儲是共用一棵 RocksDB 的 LSM-Tree;而 PolarDB-X 中同一DB節點的不同分區實際上是對應着的是 X-DB 中的不同的表(即MySQL中的一張表),每張表都是一棵 B+Tree,它們之間的實體存儲是分開的。是以,PolarDB-X 的 分區分裂本質上是将 InnoDB 的 B+Tree 由一棵拆分為兩棵的過程,這個過程中間必然需要涉及到資料的複制與重分布。諸如 CockroachDB 僅通過修改 Range 中繼資料來完成分區分裂的做法,對于 PolarDB-X 的分裂操作将不适用。考慮到分裂過程中資料複制與重分布,PolarDB-X 的分區分裂同樣是采用 Online DDL 的實作方式。套用 Online DDL 的架構,PolarDB-X 的分區分裂其實可看成是對分區遷移的一種擴充。回顧分區遷移的運作過程:

  • 首選,将源端分區看作主表,将目标端分區看作是主表的索引表,并通過一個添加索引的 Online DDL 操作實作從源端分區到目标端分區的資料複制;
  • 然後,重新将目标端分區看作是主表,将源端分區看作是索引表,再通過一個删除索引的 Online DDL 操作實作讀寫流量從源端分區切換到目标端分區。

在這過程中,源端分區與目标端分區一直被當作獨立主表與索引表來處理,主表與索引表本身的分區方式是否相同,不會對整個模型的運作産生影響。是以,在分裂場景中,若将分裂後的兩個新分區看作一個分區索引表(即該索引表有兩個分區),而該分區索引表依然可以看作是源端分區的一個副本。這樣,分區分裂便可以繼續套用分區遷移的全部流程,其中需要擴充的地方就是所有産生對分區索引的Insert/Update/Delete操作都要要再經過一次分區路由(Sharding)以确定要修改真實分區。于是,基于這個思路,分區分裂就可分下幾個階段來完成:

水準擴充太難了!PolarDB-X 為你支招
  • 準備分裂後的分區。在此階段,PolarDB-X GMS 找兩個空閑的DN節點, 根據分裂點(Split Point)将原分區的取值空間劃分成兩個部分,并在空閑的DN節點上建構這兩個新的空分區。
  • 帶分裂的分區複制。該階段與分區遷移的分區複制類似,不同的是所有源于主表修改而産生的對分區索引表的修改都需要先經過一次分區路由,以确定其實際的修改位置(如上圖所示)。
  • 帶分裂的透明切換。該階段與分區遷移的透明切換類似,不同的是所有切到分區索引表的讀寫流量都要先經過一次分區路由,以确定其實際的修改位置(如下圖所示)。
  • 資料清理。該階段與分區遷移資料清理類似,需要将被分裂的分區資料進行清理以及相關中繼資料的重新整理。

PolarDB-X 的分區分裂由于基本複用了分區遷移的流程。是以,分裂過程也是以分區組為機關進行,分裂前後 PolarDB-X  的計算下推不會受影響。

總結與展望

基于 Share-Nothing 架構的 PolarDB-X 通過對資料進行水準分區,解決了單機資料庫寫能力無法水準擴充的問題。每個分區基于 Paxos 協定實作多副本的強一緻複制,并支援分區級的高可用、錯誤容災與利用多副本提供讀擴充的能力。PolarDB-X  支援通過動态增加資料節點實作存儲層的水準擴充與自動負載均衡。但是,為了避免水準擴充過程中的負載不均衡,引入了分區遷移與分區分裂兩項必須的基本能力。

分區遷移能解決資料節點之間的負載不均衡的問題。可進行分區遷移之前必須先做分區複制,但以 X-DB 作為存儲的PolarDB-X,暫時無法借助 Paxos/Raft 協定實作跨機(跨資料節點)的分區複制與分區流量切換。是以,PolarDB-X 通過複用基于 Online DDL 的添加索引的過程來完成對應用透明的跨機分區複制。更進一步,PolarDB-X 還将  Online DDL 的機制推廣到跨機分區遷移,将通過複用删除索引的 Online DDL 過程來解決了分區遷移過程讀寫流量從源端到目标端的切換問題。PolarDB-X 基于 Online DDL 的分區遷移可以做到全程對應用無感覺,遷移過程的回填任務支援流控,避免資源占用過多并對應用産生影響。

分區分裂能解決分區之間的負載不均衡的問題。可是 PolarDB-X  的每一個分區對應一張實體表,分裂過程要将一張表拆分多張表,是以,該過程需要涉及到對分區的資料複制與重分布。鑒于要涉及分區的資料複制,PolarDB-X 的分區分裂同樣是采用 Online DDL 的實作方式,其思路是通過擴充分區遷移的模型:分區遷移是通過複用添加索引的DDL過程完成分區複制,而分區分裂則是将添加索引的操作擴充為添加分區索引,以解決分裂過程中涉及的資料重分布問題。

通過分區分裂,PolarDB-X 能産生更多分布在不同資料節點的分區;通過分區遷移,PolarDB-X能均衡不同資料節點間之間負載,如此往複,最後達到水準擴充的效果。

與諸如 CockrocachDB等主流的NewSQL資料庫相比,PolarDB-X 的水準擴充方案帶有與自己架構緊密相關的特色,以下是 PolarDB-X 水準擴充與其它 NewSQL 資料庫 的對比。

水準擴充太難了!PolarDB-X 為你支招

後記

分布式資料庫中,水準擴充通常與分區管理、負載均衡方面緊密結合。本文限于篇幅,暫時隻對PolarDB-X 水準擴充方面作了一些原理性的介紹,像動态分區管理、自動負載均衡(如分區實體位置的選擇、分裂點的選擇、如何分區做遷移等)的一些細節沒涉及太多說明,請讀者關注後續的文章。

參考文獻

  • [1] Online, Asynchronous Schema Change in F1.
  • [2] Asymmetric-Partition Replication for Highly Scalable Distributed Transaction Processing in Practice.
  • [3] Elastic Scale-out for Partition-Based Database Systems.
  • [4] TiDB: A Raft-based HTAP Database.
  • [5] CockroachDB: The Resilient Geo-Distributed SQL Database.
  • [8] In Search of an Understandable Consensus Algorithm.
  • [9] What’s Really New with NewSQL.
  • [10] Spanner: Google's Global-Distributed Database.
  • [12] Comparison of Different Repliacation Solutions.
  • [13] MySQL Group Replication.
  • [14] Paxos Made Simple
  • [15] In Search of an Understandable Consensus Algorithm
  • [16] YugabyteDB: Automatic Re-sharding of Data with Tablet Splitting
  • [17] MySQL:Replication for Scale-Out