螞蟻集團自研數據庫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還有兩個改進:
- 對于HA,放棄傳統數據庫的主從復制,使用Paxos、Raft等共識算法來保證多副本的一致性。
- 對于存儲,使用LSM樹模型替換B+樹,寫入性能更高。
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解決這個差異的方式有兩種:
- Google Spanner的PAX,一種新的融合性存儲,即在行存儲的基礎上融合列存儲的特點。
- TiDB的思路,借助Raft協議在OLTP與OLAP之間異步復制數據,通過OLAP的特殊設計來彌補異步帶來的數據不一致。
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個方面入手講了分布式數據庫的關鍵知識,歡迎大家批評指正。