OceanBase 開源,11 張圖帶你瞭解分佈式數據庫的核心知識

螞蟻集團自研數據庫 OceanBase 已經開源,這對國產分佈式數據庫來說,是一個重磅消息。一直以來 OceanBase 作爲商業數據庫,披露的技術細節並不多, 以後又多了一個可以拿來研究的優秀分佈式數據庫。參考 1[1]

根據官網描述,在 5 月 20 日國際事務處理性能委員會 (TPC,Transaction Processing Performance Council) 官網發佈最新的數據分析型基準測試 (TPC-H) 榜單中,OceanBase 以 1526 萬 QphH 的性能總分排名 30,000 GB 第一。這意味着,OceanBase 成爲唯一在事務處理和數據分析兩個領域測試中都獲得第一的中國自研數據庫。

1 架構

主流的分佈式數據庫有兩種架構,PGXC 和 NewSql。

1.1 PGXC

PGXC 是指 PostgreSQL-XC,指以 PostgreSQL 爲內核的分佈式數據庫,整體架構如下:

PGXC 架構是對傳統單體數據庫做了集羣,在集羣的基礎上加了協調節點,協調節點具有如下作用:

同時還增加了分片管理和全局時鐘。分片管理用來管理集羣的分片信息,全局時鐘的介紹見下一節。

雖然 PGXC 名字的由來是 PostgreSQL 組成的分佈式數據庫,但是使用其他單體數據庫組成的分佈式數據庫,也可以理解爲 PGXC,比如 Golden 使用的就是 mysql 作爲內核。

1.2 NewSQL

跟 PGXC 採用傳統單體數據庫爲內核相比,NewSQL 是在 NoSQL 基於分佈式鍵值存儲系統的基礎上構建了分佈式事務處理能力。架構如下圖:

此外,NewSQL 還有兩個改進:

2 全局時鐘

2.1 線性一致性

線性一致性 (Linearizability) 是分佈式系統中最強的一致性模型,總體思想是保證讀取多個不同副本的客戶端,跟讀取同一個副本讀到的結果一樣,即整個系統看起來像只有一個副本。

先看兩個不符合線性一致性的示例。

2.1.1 同一個客戶端

如下圖:client1 第一次讀取了 x 的值是 0,第二次讀取時以爲 client3 修改了 x 的值,所以讀到了新的值 1,但是第三次讀取時因爲讀到了別的副本,因爲這個副本還沒有同步完成,所以讀到了舊的值 0。

2.1.2 不同客戶端

如下圖:

client1 第一次讀取了 x 的值是 0,第二次讀取時因爲 client3 修改了 x 的值,所以讀到了新的值 1,但是在 client1 第二次讀取之後,client2 來讀取 x 的值,因爲讀到了別的副本,因爲這個副本還沒有同步完成,所以讀到了舊的值 0。

線性一致性要求,任何一個客戶端讀取返回新值後,後面所有客戶端 (包括相同客戶端和不同客戶端) 讀取也必須返回新值

下面這個圖就是線性一致性的:

2.2 全局時鐘

從上面的描述可以看到,線性一致性是建立在事件的先後順序之上的。所有操作必須記錄在一條時間線上,任意兩個事件都有先後順序。但是,集羣中各個節點都有各自的時間線,怎麼實現時間上的順序性呢。這時就需要一個全局的絕對時間,就是這裏講的全局時鐘

一般來說,從一臺時間服務器獲取時間,就可以實現全局時鐘,但是必須保證高可用。下面介紹幾種全局時鐘的實現方式:

2.2.1 TrueTime

Google Spanner 採用 GPS 加原子鐘來分配時間,支持多點授時機制。有兩個明顯的優勢:

但是也存在一些問題:

從 Spanner 的介紹看,時間誤差在 7 毫秒以內。

2.2.2 混合邏輯時鐘 (HLC)

HLC(Hybrid Logical Clock),因爲 Truetime 依賴於硬件設備來實現,實現難度大,所以有的數據庫採用了混合邏輯時鐘,即物理時鐘和邏輯時鐘配合使用,同樣採多時間源、多點授時,所以也會有系統整體的時間誤差問題。

2.2.3 Timestamp Oracle

簡稱 TSO,中心化授時方案,採用單時間源、單點授時實現全局時鐘,用一個全局唯一的時間戳作爲 xid(全局事務 id)。

優點:

缺點也很明顯

目前,TiDB、OceanBase 都使用了這個方案。

2.2.4 總結

Spanner 需要藉助物理設備來實現,對其他開源數據庫的參考價值並不大。

其他無論採用 HLC 還是 TSO,都有各自的優缺點。

還有一種介於兩者之間的授時方案,單時間源,多點授時,使用比較少。

3 HTAP

HTAP 英文全稱是 Hybrid Transaction and Analytical Processing,即混合事務和分析處理,能夠將事務處理 (OLTP) 和數據分析 (OLAP) 請求在同一個數據庫系統中完成。

HTAP 需要在計算和存儲兩個層面支持 OLTP 和 OLAP,存儲是基礎。OLTP 通常使用行式存儲,OLAP 則一般使用列式存儲,差異很大。HTAP 解決這個差異的方式有兩種:

OceanBase 採用獨創的分佈式計算引擎,能讓系統中多個計算節點同時運行 OLTP 類型的應用和 OLAP 類型的應用,實現了用一套計算引擎同時支持混合負載的能力。

4 RANGE 動態分區

下圖有 4 條數據,

如果按照 HASH 進行分片,一般會選擇 id 作爲 key 進行 HASH 計算,之後根據計算結果把數據分配到不同的分片中。這樣做的好處是實現簡單,但也存在兩個問題:

Range 分片技術跟 HASH 相比,很大的不同是數據並沒有被打散。比如上表中,我們可以把數據按照城市進行分片,這樣數據讀取效率會更高。

Range 動態分區用在 NewSQL 架構的分佈式數據庫中,一般具有下面的特性:

4.1 自動合併和拆分

可以給分配的數據量設置閾值,當某個分片的數據量超過最大閾值時,可以自動拆分成 2 個分片,當分片數據量小於最小閾值時,進行分片合併。

4.2 自動負載

當某個分片上的熱點數據較多時,節點訪問壓力會很大,系統可以自動地將這些熱點數據訪問調度到不同節點,以均衡訪問壓力。

4.3 減少分佈式事務

分佈式事務的開銷會遠遠大於本地事務,分佈式數據庫可以把頻繁參與同一個分佈式事務的數據調度到同一個分片上,這樣就避開了分佈式事務。

Spanner 支持

4.4 就近訪問

在全球部署的場景下,給用戶分配最近節點的分片,可以減少訪問延時。

Spanner 支持

4.5 高可靠

分佈式數據庫的高可靠是分區級別的高可靠,下圖是 OceanBase 中一個 Zone 的架構圖:

OceanBase 基於 Paxos 算法來實現系統的高可用,最小的粒度可以做到分區級別。集羣中數據的每一個分區會被保存到所有的 Zone 上,分區的多個副本採用 Paxos 協議進行日誌同步。每個分區和它的副本構成一個獨立的 Paxos 複製組,其中一個分區爲 Leader,其它分區爲 Follower。所有針對這個副本的寫請求,都會自動路由到對應的主分區上進行。主分區可以分佈在不同的 OBServer 上,這樣對於不同副本的寫操作也會分佈到不同的數據節點上,從而實現數據多點寫入,提高系統性能。

5 percalator 模型

分佈式數據庫是在 BigTable 基礎上增加了分佈式事務解決方案。而 Percolator 模型就是 Google 提出的構建在 BigTable 之上的分佈式事務解決方案。參考 2[2]

percalator 模型採用了 2 階段提交的思想,這裏以銀行匯款爲例,賬戶 1 給賬戶 2 匯款 100 元,這 2 個賬戶位於不同的分區上。

5.1 初始狀態

初始階段,假如初始時賬戶 1 上有 300 元,賬戶 2 上有 500 元,如下圖:

上面表格中,":" 前面是用時間戳表示的數據版本,後面是數據值。第一列是表名,第二列的低版本保存了數據,第三列列保存了數據上加的鎖。第四列的高版本保存了指向保存數據版本的指針,比如 6 這個版本保存了指向了 5 這個版本數據的指針 6:data@5。

5.2 Prewrite

事務管理器向兩個分片發送了 Prepare 請求,分片收到請求後,爲每個要修改的數據行寫日誌,並且根據時間戳記錄事務的私有版本,這裏的私有版本就是 7,這樣就獲得了鎖,其他事務就不能操作這兩條數據了。

如下圖:

從第二列的數據可以看到,賬戶 1 上減少了 200 元,賬戶 2 上增加 600 元。從第三列可以看到賬戶 1 獲得了 primary lock,賬戶 2 上是指向 primary lock 的鎖指針。

注意: primary lock 的選擇是隨機的,賬戶 1 和賬戶 2 都可以選擇。

5.3 commit

commit 階段,協調節點只需要跟擁有 primary lock 的分片進行通信,這裏只需要跟賬戶 1 進行通信,從而保證了 commit 指令的原子性。這時數據如下表:

可以看到賬戶 1 的 primary lock 已經清除了,同時增加了 8 這個版本,8 這個版本的數據指向版本 7。這樣 7、8 兩個版本都不是私有版本了,其他事務就可以操作這條記錄了。

私有版本還有一個作用,就是賬戶 1 提交失敗後,賬戶 2 可以根據私有版本進行回滾。

5.4 事務結束

commit 成功後並沒有同步清除賬戶 2 上的私有版本和鎖指針,而是會啓動異步線程來清除,異步線程清除完成後,最終數據如下圖:

可以看到,最終賬戶 2 清除了鎖指針和私有版本。

賬戶 2 上的 lock 沒有同步清除,其他線程讀取賬戶 2 時會根據 primary@order.bal 查找 primary lock,如果發現 primary lock 已經清除,就可以繼續讀取。讀取的同時做一下 secondary lock 清理工作。

6 總結

本文主要從 5 個方面入手講了分佈式數據庫的關鍵知識,歡迎大家批評指正。

參考資料

[1]

參考 1: https://open.oceanbase.com/

[2]

參考 2: https://www.cs.princeton.edu/courses/archive/fall10/cos597B/papers/percolator-osdi10.pdf

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/w142iZm8FGQ8I7mg-NGe6w