OceanBase開源,11張圖帶你了解分布式數(shù)據(jù)庫的核心知識
本文轉(zhuǎn)載自微信公眾號「程序員jinjunzhu」,作者jinjunzhu。轉(zhuǎn)載本文請聯(lián)系程序員jinjunzhu公眾號。
螞蟻集團自研數(shù)據(jù)庫OceanBase已經(jīng)開源,這對國產(chǎn)分布式數(shù)據(jù)庫來說,是一個重磅消息。一直以來OceanBase作為商業(yè)數(shù)據(jù)庫,披露的技術(shù)細(xì)節(jié)并不多,以后又多了一個可以拿來研究的優(yōu)秀分布式數(shù)據(jù)庫。參考1[1]
根據(jù)官網(wǎng)描述,在5月20日國際事務(wù)處理性能委員會(TPC,Transaction Processing Performance Council)官網(wǎng)發(fā)布最新的數(shù)據(jù)分析型基準(zhǔn)測試(TPC-H)榜單中,OceanBase以 1526 萬 QphH 的性能總分排名 30,000 GB 第一。這意味著,OceanBase 成為唯一在事務(wù)處理和數(shù)據(jù)分析兩個領(lǐng)域測試中都獲得第一的中國自研數(shù)據(jù)庫。
1 架構(gòu)
主流的分布式數(shù)據(jù)庫有兩種架構(gòu),PGXC和NewSql。
1.1 PGXC
PGXC是指PostgreSQL-XC,指以PostgreSQL為內(nèi)核的分布式數(shù)據(jù)庫,整體架構(gòu)如下:
PGXC架構(gòu)是對傳統(tǒng)單體數(shù)據(jù)庫做了集群,在集群的基礎(chǔ)上加了協(xié)調(diào)節(jié)點,協(xié)調(diào)節(jié)點具有如下作用:
- 客戶端接入
- 進(jìn)程管理
- 分布式事務(wù)管理
- 查詢處理
同時還增加了分片管理和全局時鐘。分片管理用來管理集群的分片信息,全局時鐘的介紹見下一節(jié)。
雖然PGXC名字的由來是PostgreSQL組成的分布式數(shù)據(jù)庫,但是使用其他單體數(shù)據(jù)庫組成的分布式數(shù)據(jù)庫,也可以理解為PGXC,比如Golden使用的就是mysql作為內(nèi)核。
1.2 NewSQL
跟PGXC采用傳統(tǒng)單體數(shù)據(jù)庫為內(nèi)核相比,NewSQL是在NoSQL基于分布式鍵值存儲系統(tǒng)的基礎(chǔ)上構(gòu)建了分布式事務(wù)處理能力。架構(gòu)如下圖:
此外,NewSQL還有兩個改進(jìn):
- 對于HA,放棄傳統(tǒng)數(shù)據(jù)庫的主從復(fù)制,使用Paxos、Raft等共識算法來保證多副本的一致性。
- 對于存儲,使用LSM樹模型替換B+樹,寫入性能更高。
2 全局時鐘
2.1 線程一致性
線性一致性(Linearizability)是分布式系統(tǒng)中最強的一致性模型,總體思想是保證讀取多個不同副本的客戶端,跟讀取同一個副本讀到的結(jié)果一樣,即整個系統(tǒng)看起來像只有一個副本。
先看兩個不符合線性一致性的示例。
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 全局時鐘
從上面的描述可以看到,線性一致性是建立在事件的先后順序之上的。所有操作必須記錄在一條時間線上,任意兩個事件都有先后順序。但是,集群中各個節(jié)點都有各自的時間線,怎么實現(xiàn)時間上的順序性呢。這時就需要一個全局的絕對時間,就是這里講的全局時鐘。
一般來說,從一臺時間服務(wù)器獲取時間,就可以實現(xiàn)全局時鐘,但是必須保證高可用。下面介紹幾種全局時鐘的實現(xiàn)方式:
2.2.1 TrueTime
Google Spanner采用GPS加原子鐘來分配時間,支持多點授時機制。有兩個明顯的優(yōu)勢:
- 多點授時去中心化,實現(xiàn)了高可靠。
- 支持全球化部署,這樣可以減少客戶端和時間服務(wù)器的通信時長。
但是也存在一些問題:
- 采用物理時鐘可以出現(xiàn)時鐘偏移和時鐘回?fù)堋?/li>
- 多點授時可能出現(xiàn)系統(tǒng)整體的時間誤差。
從Spanner的介紹看,時間誤差在7毫秒以內(nèi)。
2.2.2 混合邏輯時鐘(HLC)
HLC(Hybrid Logical Clock),因為Truetime依賴于硬件設(shè)備來實現(xiàn),實現(xiàn)難度大,所以有的數(shù)據(jù)庫采用了混合邏輯時鐘,即物理時鐘和邏輯時鐘配合使用,同樣采多時間源、多點授時,所以也會有系統(tǒng)整體的時間誤差問題。
2.2.3 Timestamp Oracle
簡稱TSO,中心化授時方案,采用單時間源、單點授時實現(xiàn)全局時鐘,用一個全局唯一的時間戳作為xid(全局事務(wù)id)。
優(yōu)點:
- 實現(xiàn)簡單
- 單時間源單調(diào)遞增,可以減少事務(wù)沖突
缺點也很明顯
- 單點授時,性能會有瓶頸
- 不適合大規(guī)模集群部署
目前,TiDB、OceanBase都使用了這個方案。
2.2.4 總結(jié)
Spanner需要借助物理設(shè)備來實現(xiàn),對其他開源數(shù)據(jù)庫的參考價值并不大。
其他無論采用HLC還是TSO,都有各自的優(yōu)缺點。
還有一種介于兩者之間的授時方案,單時間源,多點授時,使用比較少。
3 HTAP
HTAP英文全稱是 Hybrid Transaction and Analytical Processing,即混合事務(wù)和分析處理,能夠?qū)⑹聞?wù)處理(OLTP)和數(shù)據(jù)分析(OLAP)請求在同一個數(shù)據(jù)庫系統(tǒng)中完成。
HTAP需要在計算和存儲兩個層面支持OLTP和OLAP,存儲是基礎(chǔ)。OLTP通常使用行式存儲,OLAP則一般使用列式存儲,差異很大。HTAP解決這個差異的方式有兩種:
- Google Spanner的PAX,一種新的融合性存儲,即在行存儲的基礎(chǔ)上融合列存儲的特點。
- TiDB的思路,借助Raft協(xié)議在OLTP與OLAP之間異步復(fù)制數(shù)據(jù),通過OLAP的特殊設(shè)計來彌補異步帶來的數(shù)據(jù)不一致。
OceanBase采用獨創(chuàng)的分布式計算引擎,能讓系統(tǒng)中多個計算節(jié)點同時運行OLTP類型的應(yīng)用和OLAP類型的應(yīng)用,實現(xiàn)了用一套計算引擎同時支持混合負(fù)載的能力。
4 RANGE動態(tài)分區(qū)
下圖有4條數(shù)據(jù),
如果按照HASH進(jìn)行分片,一般會選擇id作為key進(jìn)行HASH計算,之后根據(jù)計算結(jié)果把數(shù)據(jù)分配到不同的分片中。這樣做的好處是實現(xiàn)簡單,但也存在兩個問題:
- 分片不具備業(yè)務(wù)屬性,可能會存在業(yè)務(wù)熱點訪問的問題。
- 分片規(guī)模變化時,遷移數(shù)據(jù)問題。
Range分片技術(shù)跟HASH相比,很大的不同是數(shù)據(jù)并沒有被打散。比如上表中,我們可以把數(shù)據(jù)按照城市進(jìn)行分片,這樣數(shù)據(jù)讀取效率會更高。
Range動態(tài)分區(qū)用在NewSQL架構(gòu)的分布式數(shù)據(jù)庫中,一般具有下面的特性:
4.1 自動合并和拆分
可以給分配的數(shù)據(jù)量設(shè)置閾值,當(dāng)某個分片的數(shù)據(jù)量超過最大閾值時,可以自動拆分成2個分片,當(dāng)分片數(shù)據(jù)量小于最小閾值時,進(jìn)行分片合并。
4.2 自動負(fù)載
當(dāng)某個分片上的熱點數(shù)據(jù)較多時,節(jié)點訪問壓力會很大,系統(tǒng)可以自動地將這些熱點數(shù)據(jù)訪問調(diào)度到不同節(jié)點,以均衡訪問壓力。
4.3 減少分布式事務(wù)
分布式事務(wù)的開銷會遠(yuǎn)遠(yuǎn)大于本地事務(wù),分布式數(shù)據(jù)庫可以把頻繁參與同一個分布式事務(wù)的數(shù)據(jù)調(diào)度到同一個分片上,這樣就避開了分布式事務(wù)。
Spanner支持
4.4 就近訪問
在全球部署的場景下,給用戶分配最近節(jié)點的分片,可以減少訪問延時。
Spanner支持
4.5 高可靠
分布式數(shù)據(jù)庫的高可靠是分區(qū)級別的高可靠,下圖是OceanBase中一個Zone的架構(gòu)圖:
OceanBase基于Paxos算法來實現(xiàn)系統(tǒng)的高可用,最小的粒度可以做到分區(qū)級別。集群中數(shù)據(jù)的每一個分區(qū)會被保存到所有的Zone上,分區(qū)的多個副本采用Paxos協(xié)議進(jìn)行日志同步。每個分區(qū)和它的副本構(gòu)成一個獨立的Paxos復(fù)制組,其中一個分區(qū)為Leader,其它分區(qū)為Follower。所有針對這個副本的寫請求,都會自動路由到對應(yīng)的主分區(qū)上進(jìn)行。主分區(qū)可以分布在不同的OBServer上,這樣對于不同副本的寫操作也會分布到不同的數(shù)據(jù)節(jié)點上,從而實現(xiàn)數(shù)據(jù)多點寫入,提高系統(tǒng)性能。
5 percalator模型
分布式數(shù)據(jù)庫是在BigTable基礎(chǔ)上增加了分布式事務(wù)解決方案。而Percolator模型就是Google提出的構(gòu)建在BigTable之上的分布式事務(wù)解決方案。參考2[2]
percalator模型采用了2階段提交的思想,這里以銀行匯款為例,賬戶1給賬戶2匯款100元,這2個賬戶位于不同的分區(qū)上。
5.1 初始狀態(tài)
初始階段,假如初始時賬戶1上有300元,賬戶2上有500元,如下圖:
上面表格中,":"前面是用時間戳表示的數(shù)據(jù)版本,后面是數(shù)據(jù)值。第一列是表名,第二列的低版本保存了數(shù)據(jù),第三列列保存了數(shù)據(jù)上加的鎖。第四列的高版本保存了指向保存數(shù)據(jù)版本的指針,比如6這個版本保存了指向了5這個版本數(shù)據(jù)的指針 6:data@5。
5.2 Prewrite
事務(wù)管理器向兩個分片發(fā)送了Prepare請求,分片收到請求后,為每個要修改的數(shù)據(jù)行寫日志,并且根據(jù)時間戳記錄事務(wù)的私有版本,這里的私有版本就是7,這樣就獲得了鎖,其他事務(wù)就不能操作這兩條數(shù)據(jù)了。
如下圖:
從第二列的數(shù)據(jù)可以看到,賬戶1上減少了200元,賬戶2上增加600元。從第三列可以看到賬戶1獲得了primary lock,賬戶2上是指向primary lock的鎖指針。
注意:primary lock的選擇是隨機的,賬戶1和賬戶2都可以選擇。
5.3 commit
commit階段,協(xié)調(diào)節(jié)點只需要跟擁有primary lock的分片進(jìn)行通信,這里只需要跟賬戶1進(jìn)行通信,從而保證了commit指令的原子性。這時數(shù)據(jù)如下表:
可以看到賬戶1的primary lock已經(jīng)清除了,同時增加了8這個版本,8這個版本的數(shù)據(jù)指向版本7。這樣7、8兩個版本都不是私有版本了,其他事務(wù)就可以操作這條記錄了。
私有版本還有一個作用,就是賬戶1提交失敗后,賬戶2可以根據(jù)私有版本進(jìn)行回滾。
5.4 事務(wù)結(jié)束
commit成功后并沒有同步清除賬戶2上的私有版本和鎖指針,而是會啟動異步線程來清除,異步線程清除完成后,最終數(shù)據(jù)如下圖:
可以看到,最終賬戶2清除了鎖指針和私有版本。
賬戶2上的lock沒有同步清除,其他線程讀取賬戶2時會根據(jù)primary@order.bal查找primary lock,如果發(fā)現(xiàn)primary lock已經(jīng)清除,就可以繼續(xù)讀取。讀取的同時做一下secondary lock清理工作。
6 總結(jié)
本文主要從5個方面入手講了分布式數(shù)據(jù)庫的關(guān)鍵知識,歡迎大家批評指正。
參考資料
[1]參考1: https://open.oceanbase.com/
[2]參考2: https://www.cs.princeton.edu/courses/archive/fall10/cos597B/papers/percolator-osdi10.pdf