三大云原生數(shù)據(jù)庫:Aurora, PolarDB 與 Socrates
1.何謂「云原生數(shù)據(jù)庫」
云計算的出現(xiàn),加速了企業(yè)信息技術的發(fā)展。云計算供應商將海量的計算、存儲、通信資源放入「池子」中,企業(yè)或個人用戶按需購買計算資源,快速、低成本搭建信息系統(tǒng)。在系統(tǒng)的 workload 發(fā)送變化時,還可以按需擴縮計算機資源。對于與計算供應商來說,所有用戶使用的海量的資源統(tǒng)一管理,規(guī)模效應顯著,邊際成本低。對于云計算用戶來說,資源獲取快捷、方便,按需使用比自建機房、搭建和運維基礎系設施成本更低。站在全社會的角度來看,整體資源的利用率更加高,environmentally-friendly。
數(shù)據(jù)庫是最常用的基礎軟件之一,它通常能提供 計算 和 存儲 的能力。存儲當然是數(shù)據(jù)的基礎能力。計算能力對外體現(xiàn)在:數(shù)據(jù)庫可以完成用戶發(fā)出的復雜分析與計算請求(用 SQL 可以寫出強大的計算邏輯),對內(nèi)體現(xiàn)在:查詢優(yōu)化、事務處理、索引維護等內(nèi)部計算。
單機數(shù)據(jù)庫部署在普通主機上,其存儲和計算能力受限于主機的硬件,難以擴展。分布式數(shù)據(jù)庫可以通過適當增加機器,來拓展數(shù)據(jù)庫的容量和計算能力,但是集群節(jié)點的能力依舊受到機器資源的限制。如果將它們簡單的搬遷到云上,不做任何改造,普通主機換成云主機。
第一,數(shù)據(jù)庫直接部署在云上,可能會有大量新的問題出現(xiàn),例如網(wǎng)絡瓶頸、可能會帶來嚴重的寫放大問題等;再比如:即使給單機數(shù)據(jù)庫掛一個無限大的存儲,當數(shù)據(jù)量極大時性能會很差。第二,無法完全發(fā)揮云計算最大的優(yōu)勢「資源彈性管理、按需使用」,也無法靈活運用琳瑯滿目的云存儲產(chǎn)品。第三,信息化、數(shù)字化的高速發(fā)展,對數(shù)據(jù)庫提出了更多要求:更高的性能、更低的成本、更好的靈活性,這些也是僅僅將單機數(shù)據(jù)庫搬上云解決不了的。
雖然分布式數(shù)據(jù)庫也做到了很好的擴展性,但它不能算是「云原生」。第一,概念上,它彈性擴展的單位是「機器」,而非更加細粒度的「計算和存儲資源」。第二,它在設計的時候,并不會考慮云平臺的特征,沒有相應的優(yōu)化,以達到最優(yōu)性能和成本。第三,引入分布式事務、分布式集群管理等模塊,也讓系統(tǒng)變得更加復雜。(這里沒有拉踩的意味,分布式數(shù)據(jù)庫這條路也有巨大的優(yōu)勢,例如數(shù)據(jù)量極大、需要寫擴展性、需要全球部署等場景)
「云原生數(shù)據(jù)庫」的核心,是要設計 一種更加符合「資源彈性管理」這一理念、充分利用云平臺池化資源、適配云平臺已有的基礎設置的數(shù)據(jù)庫架構(gòu)。
由于云計算平臺的存儲和計算資源是可以分開擴展的,所以云原生數(shù)據(jù)庫必定是存儲計算分離架構(gòu)。
2. Aurora
2.1 關鍵問題
Aurora 是 AWS 推出的 OLTP 云數(shù)據(jù)庫先驅(qū),在 MySQL 代碼基礎上改造出存儲計算分離架構(gòu)。AWS 認為在云上構(gòu)建數(shù)據(jù)庫,存儲資源很容易擴展,那么系統(tǒng)的瓶頸就落在網(wǎng)絡上了,因為數(shù)據(jù)庫實例與所有存儲節(jié)點的交互都需要通過網(wǎng)絡。因此 Aurora 最核心的理念就是要減少數(shù)據(jù)的網(wǎng)絡傳輸量。
Aurora 論文里舉了這樣一個 MySQL 直接搬遷到云上的例子:
單機 MySQL 事務提交需要日志落盤,同時后臺線程會異步刷臟頁,為了避免頁斷裂,刷臟頁時還需要將數(shù)據(jù)頁寫入 double write 區(qū)域。如下圖所示,如果再考慮到生產(chǎn)環(huán)境中需要主備復制,AZ1 和 AZ2 各部署一個MySQL 實例同步鏡像復制(這里應該是 DRBD 的方案?),底層存儲采用 Elastic Block Store(EBS),每個EBS還有自己的一份鏡像,另外部署Simple Storage Service(S3) 歸檔 redo 日志和 binlog 日志,以支持基于時間點的恢復。
以上寫入同步,每個步驟都需要傳遞5種類型的數(shù)據(jù):redo log,binlog,data page,double write 和 frm 元數(shù)據(jù)。由于是基于鏡像的同步復制,因此圖中的1,3,5步驟是順序的,這種模型響應時間非常糟糕,要進行4次網(wǎng)絡IO,且其中3次是同步串行的。從存儲角度看,數(shù)據(jù)在 EBS 上存 4 份,需要 4 份都寫成功才能返回。 所以在這種架構(gòu)下,無論是 IO 量還是串行化模型都會導致性能非常糟糕。
Aurora 為了減少 IO 的數(shù)量,所有節(jié)點之間的數(shù)據(jù)傳輸,只有 redo。為了做到這一點,需要將部分數(shù)據(jù)庫的能力下推到存儲節(jié)點。當然除了減少 IO,Aurora 的設計還帶來了不少其他好處。
2.2 核心技術
2.2.1 存儲計算分離架構(gòu)
Aurora 下推到存儲的主要功能主要和 redo 相關,包括:日志回放、故障恢復和備份還原。技術層保留了查詢處理、事務處理、緩存管理、鎖管理、訪問控制等大部分功能。
Aurora 的整體由跨 AZ 的一個主實例、多個副本(最多15個)實例及多個存儲節(jié)點組成。主實例與只讀實例/存儲節(jié)點之間只傳遞 redo log 和元信息。主實例與副本實例共享一套分布式存儲,因此增加副本實例是零存儲成本的,這大大提高了 Aurora 的讀擴展性。
主實例會異步向副本實例發(fā)送 redo log,副本實例收到后開始回放。如果日志對應的 page 不在 本地的 page cache,該 redo log 可以直接丟棄,因為存儲節(jié)點擁有所有的 page 及 redo log,有需要時直接從存儲節(jié)點請求即可。
存儲節(jié)點收到 redo log 后會持久化,而回放日志和回收舊版本數(shù)據(jù)頁的工作,可以一直異步在后臺執(zhí)行。存儲節(jié)點可以較為靈活的分配資源做前臺/后臺的工作。同時相較于傳統(tǒng)數(shù)據(jù)庫,Aurora 不用后臺去推進 checkpoint(這個動作往往會影響前臺請求),分離的存儲層不斷地推進 checkpoint,對數(shù)據(jù)庫實例絲毫沒有影響,而且推進的越快,對讀請求越有利。
存儲層不斷推進 checkpoint 也能加快故障恢復的速度,一般情況下,在 10w TPS 壓力下,Aurora 可以在 10s 恢復完成。在故障恢復過程中,
詳細來說,Aurora 寫流程如下:
(1) 存儲節(jié)點接收主實例的日志,追加到其內(nèi)存隊列。
(2) 存儲節(jié)點持久化日志后應答主實例。
(3) 按分片歸類日志,確認是否有日志丟失。
(4) 與其它存儲節(jié)點交互,填充丟失日志。
(5) 回放日志,生成數(shù)據(jù)頁。
(6) 定期備份數(shù)據(jù)和日志到 S3。
(7) 定期回收過期數(shù)據(jù)頁版本。
(8) 定期 CRC 校驗數(shù)據(jù)頁。
上述所有操作,只有第 (1) (3)是串行同步的,會直接影響請求響應時間,其它均為異步操作。
為了保證可用性,Aurora 持久化采用 Quorum 協(xié)議。假設復制集合包含 V 個節(jié)點,讀請求需要得到 Vr 個節(jié)點響應,寫請求需要得到 Vw 個節(jié)點詳細,為了保證讀寫一致性,Quorum 協(xié)議主要有兩個條件(1)Vr + Vw > V ;(2)Vw > V/2。
主實例的每次寫入會發(fā)送到位于 3 個 AZ 的 6 個存儲節(jié)點,收到 4 個持久化成功的回復便認為寫入成功。因此 Aurora 的 Quorum 協(xié)議中,V = 6,Vw = 4,Vr = 3。當然在實際讀請求中,不用真的去 3 個存儲節(jié)點查詢,只需要查詢擁有最新數(shù)據(jù)的那個存儲節(jié)點就行 。
Quorum 協(xié)議可以保證,只要 AZ 級別故障和節(jié)點故障不同時發(fā)生,數(shù)據(jù)庫的可用性就能得到保證。同時 Aurora 采用分片管理的策略,每個分片 10G,6 個 10G 的副本組成一個 Protected Group,每個分片是一個故障恢復的單位,在 10G/s 網(wǎng)絡下,一個分片可以在 10s 內(nèi)恢復。因此只有當 10s 內(nèi)同時發(fā)生超過2個分片的故障,可用性才會受到影響,這幾乎是不可能發(fā)生的。
sysbench write only 測試,Aurora是基于鏡像MySQL吞吐能力的35倍,每個事務的日志量比基于鏡像MySQL日志量要少7.7倍。
總體來講,Aurora 存儲計算分離的架構(gòu)帶來了如下好處:(1)在云上部署,所有節(jié)點之間只傳輸 redo,網(wǎng)絡壓力小。(2)前后臺線程互不干擾,后臺任務可以不停歇的異步執(zhí)行。(3)存儲節(jié)點跨 AZ 高可用。(4)讀副本、存儲節(jié)點可線性擴展(有上限)。(5)故障恢復時間快。
2.2.2 一致性保證
從 MySQL 到 Aurora,單機系統(tǒng)進化為分布式系統(tǒng),那么存儲節(jié)點與數(shù)據(jù)庫實例之間就需要保證數(shù)據(jù)一致性(consistency)。 Aurora 強調(diào),傳統(tǒng)保證分布式一致性的方法 2PC 協(xié)議復雜且容錯性非常差,Aurora 依賴Quorum + Gossip 協(xié)議及基于 LSN 的算法來保證一致性。
我其實不太理解 Aurora 為啥要在論文中 cue 一下 2PC,雖然 2PC 能解決它的一致性問題,但是一般人肯定不會在這種場景下使用 2PC。一來,事務提交管理這種會改變數(shù)據(jù)庫狀態(tài)的操作主實例控制,也就意味著整個系統(tǒng)的一致性完全由主實例單機決定,存儲節(jié)點只需要告知主實例其持久化結(jié)果,這一點和和單機數(shù)據(jù)庫沒有區(qū)別,看不出來哪里需要分布式的兩階段提交協(xié)議。二來,相較于分布式事務提交,Aurora 存儲節(jié)點只有 redo 持久化這一個簡單需求,沒有其他資源的要求(例如:鎖、事務上下文創(chuàng)建等),也沒有提交結(jié)束釋放資源的需求,完全沒必要上 2PC。
說白了,要不要用 2PC 就是看數(shù)據(jù)庫的狀態(tài)變化由誰控制,存儲節(jié)點雖然持久化了,但是數(shù)據(jù)庫狀態(tài)的變化,完全由事務管理器來控制。需要兩階段提交的情況是,事務處理器分布在不同節(jié)點(這樣大大提高可了寫擴展性),大家就事務應該提交還是回滾做出協(xié)商。
比較有意思的對比倒是在大部分系統(tǒng)都傾向于使用 Paxos/Raft 這樣的共識算法,在底層實現(xiàn)一個強一致的存儲系統(tǒng)來保證高可用時(例如 PolarDB, Spanner, OB...),Aurora 只是使用簡單的 Quorum ,計算層和存儲層結(jié)合起來實現(xiàn)高可用強一致。
以上是個人思考,其實在 Aurora 這種事務邏輯和單機數(shù)據(jù)庫幾乎沒有區(qū)別的數(shù)據(jù)庫,正常情況下,一致性保證沒什么區(qū)別。主要的區(qū)別在于,數(shù)據(jù)庫實例宕機重啟時,需要這些宕機前未執(zhí)行完的事務,決定哪些數(shù)據(jù)頁中未完成的事務,應該提交還是回滾。因為單機數(shù)據(jù)庫恢復依據(jù)的是單份日志,而 Aurora 需要從多個存儲節(jié)點獲得的多份日志,Aurora 需要決定哪些日志需要回放,哪些需要截斷。
Aurora 事務都是由主實例發(fā)起的,因此主實例可以按時間順序為每一個 redo 日志分配一個 Log Sequence Number(LSN)。為了保證一致性,Aurora 定義了如下幾個關鍵日志點位。
Volume Complete LSN(VCL),表示存儲層擁有 VCL 前的所有完整日志。故障恢復時,需要銷毀所有 LSN 大于 VCL 的日志。
Consistency Point LSNs(CPLs),MySQL(InnoDB) 的事務由內(nèi)部多個 Mini-Transaction 組成,每個 Mini-Transaction 是原子操作的最小單位。例如 B+-Tree 分裂需要修改多個 page,它們必須是原子的,必須由一組原子的 redo 日志來表示。CPL 是 Mini-Transaction 的最后一個日志的 LSN,日志回放時,需要以 CPL 為單位。一個事務通常由多個 CPL 組成。
Volume Durable LSN(VDL),所有 CPLs 中已經(jīng)持久化的最大 LSN,它代表了數(shù)據(jù)庫處于一致狀態(tài)的最新位點,VDL 一定小于等于 VCL。為了保證 Mini-Transaction 的原子性,所有大于 VDL 的日志也需要被銷毀。在故障恢復階段,數(shù)據(jù)庫實例通過 Quorum 讀可以計算得到最新的 VDL。
舉個例子,VCL=1007,CPLs={900,1000,1100},那么 1000 以后的日志都應該被截斷。
3.PolarDB
PolarDB 是阿里云推出的云原生數(shù)據(jù)庫,雖然都是計算存儲分離架構(gòu),但是與 Aurora 在設計理念上有非常大的區(qū)別。
3.1 關鍵問題
PolarDB 在許多公開的分享和文章中,強調(diào)了傳統(tǒng)數(shù)據(jù)庫架構(gòu)上云,存在很多問題,這里列舉一些典型的:
擴展性相關:
- 由于物理機磁盤限制以及備份等策略,數(shù)據(jù)庫的數(shù)據(jù)大小不能太大,太大的實例是運維的災難。
- 活動上線時造成壓力突增,而數(shù)據(jù)庫卻來不及升級。
- 業(yè)務發(fā)展很快,來不及進行拆庫,也來不及分庫分表。
性能相關:
- 傳統(tǒng)備份技術,由于涉及到拷貝數(shù)據(jù),并上傳廉價存儲,速度因此也受網(wǎng)絡影響。一次全量數(shù)據(jù)備份需要大量時間,并且必須鎖表等。
- 讀寫實例和只讀實例各自擁有一份獨立的數(shù)據(jù),新建一個只讀實例需要重新拷貝數(shù)據(jù),考慮到網(wǎng)絡限流,速度不會很快。
- MySQL數(shù)據(jù)庫早期的版本,對早期的系統(tǒng)/硬件做了很多優(yōu)化,但是并沒有考慮到現(xiàn)代主流的系統(tǒng)/硬件的優(yōu)秀特性,在高并發(fā)環(huán)境下,性能還有很大的提升空間。
- MySQL為了兼容性,需要寫兩份日志(事務日志和復制日志),與其他商業(yè)數(shù)據(jù)庫相比,性能相對較差。
- 讀寫實例和只讀實例通過增量邏輯數(shù)據(jù)同步,讀寫實例上所有的SQL需要在只讀實例上重新執(zhí)行一遍(包括SQL解析,SQL優(yōu)化等無效步驟),同時,復制并發(fā)讀最高是基于表維度,導致主備延遲非常普遍,進而影響各種切換任務。
- 應用擴容之后,上百臺ECS連接一臺數(shù)據(jù)庫,因此在高并發(fā)下性能很差。
成本相關:
- 讀寫實例和只讀實例各自擁有一份獨立的數(shù)據(jù),用戶購買只讀實例,不僅需要付出計算的成本,也需要付出存儲資源的成本。
....
這些問題本質(zhì)上都是單機數(shù)據(jù)庫所面臨的的問題,數(shù)據(jù)庫上云,當然就是要解決這些問題。但是僅僅簡單的將單機數(shù)據(jù)庫部署在云上,這些問題還是存在的。PolarDB 的研發(fā)就是為了解決這一系列問題。
當然,我認為 Aurora 也是能夠解決上述大部分問題的,只是 PolarDB 選擇的技術路線與 Aurora 截然不同。
3.2 核心技術
3.2.1 存儲計算分離架構(gòu)
PolarDB 同樣采用存儲計算分離架構(gòu),計算節(jié)點是一個 MySQL 實例負責存儲 SQL 解析、事務處理等,存儲節(jié)點是 PolarDB 的核心組件 PolarStore,負責數(shù)據(jù)可靠存儲。同一個集群的多個計算節(jié)點(1個讀寫實例和多個只讀實例)共享一份數(shù)據(jù),正因為如此,擴展只讀實例的速度和成本都非常低。數(shù)據(jù)庫實例的高可用通過只讀實例在 failover 時迅速轉(zhuǎn)變?yōu)樽x寫實例保證,數(shù)據(jù)的高可用和一致性由 PolarStore 內(nèi)部實現(xiàn)的 Parallel-Raft(支持亂序提交,性能比 raft 更好) 保證。
計算節(jié)點與存儲節(jié)點采用高速網(wǎng)絡互聯(lián),并通過RDMA協(xié)議進行數(shù)據(jù)傳輸,使網(wǎng)絡不再成為瓶頸。
PolarDB 的設計重點是一套高性能的分布式文件系統(tǒng) PolarFS,能夠向多個數(shù)據(jù)庫實例提供高性能、高可靠的數(shù)據(jù)存取服務(支持同時掛載)。
3.2.2 PolarFS
PolarFS 是一個極低延遲,高可靠,利用了大量新硬件的分布式文件系統(tǒng),對外的接口是 libpfs,數(shù)據(jù)庫通過這一層與 PolarFS 交互。
PolarFS 存儲層次上可以分為三級:Volume,Chunk,Block。用戶創(chuàng)建 PolarDB 數(shù)據(jù)庫實例時,系統(tǒng)就會為該實例創(chuàng)建一個 Volume,其大小范圍可以是 10G~100T。每個 Volume 由多個 Chunk 組成,Chunk 是數(shù)據(jù)移動/高可用/分布式的最小單位,其必落在某塊 SSD 盤上。每個 Chunk 大小為 10GB,遠大于其他分布式文件系統(tǒng)(GFS為64MB)。這樣做可以減少 Volume 到 Chunk 映射的元數(shù)據(jù)量大小,更有利于管理與緩存。不足之處在于熱點不易打散。每個 Chunk 都有3 個副本,通過 ParallelRaft 協(xié)議保證高可用。Chunk 被進一步劃分為 163,840 個 Block,每個塊大小為 64KB。是預分配空間的最小單位。
PolarFS 的主要組件包括:
libpfs: 用戶空間文件系統(tǒng)(User Space File System)庫,是計算節(jié)點訪問底層存儲的API接口。
PolarSwitch :部署在計算節(jié)點的Daemon,負責將 IO 請求轉(zhuǎn)化為對具體 ChunkServer leader 的訪問。
ChunkServer :用于管理 Chunk,處理 Block IO 請求。一個存儲節(jié)點可以部署多個 ChunkServer,每個ChunkServer 綁定一個CPU核,管理一塊獨立的 NVMe SSD 盤,ChunkServer 之間沒有資源競爭。Chunk 修改會先 WAL,保證原子性和持久性。ChunkServer使用了 3D XPoint SSD 和普通 NVMe SSD 混合型WAL buffer,Log 會優(yōu)先存放到更快的 3DXPoint SSD 中。
PolarCtrl :系統(tǒng)的控制平面,是PolarFS集群的控制核心,負責監(jiān)控和 Balance ChunkServer、各種元信息維護、更新 PolarSwitch 元信息緩存等。
PolarFS的寫操作流程大致如下:
- POLARDB 通過 libpfs 發(fā)送寫請求經(jīng)由 ring buffer 到 PolarSwitch。
- PolarSwitch 根據(jù)本地緩存元數(shù)據(jù),將寫請求發(fā)送至對應 Chunk 的 Chunk Server Leader 節(jié)點。
- 請求到達 ChunkServer 后,節(jié)點的 RDMA NIC 將 Request 加入 request 隊列。一個 IO 輪詢線程不斷輪詢該請求隊列,一旦發(fā)現(xiàn)有新請求則立即開始處理。
- IO 處理線程異步將請求寫到 Chunk 對應的 WAL 塊上(通過 SPDK),同時將請求異步發(fā)向給 Follower 節(jié)點。
- 寫請求到達 Follower 后,同樣通過 RDMA NIC 將其放到 request 隊列。
- Follower 節(jié)點上的 IO 輪詢線程被觸發(fā),同樣異步寫入。
- Follower 節(jié)點的寫請求成功,通過 RDMA 向 Leader 發(fā)送應答。
- Leader節(jié)點收到 Followers 里任一節(jié)點成功應答后,即形成 majority,同樣通過 SPDK 將寫請求寫到相應的數(shù)據(jù)塊。
- Leader 通過 RDMA NIC 向 PolarSwitch 返回請求處理結(jié)果。
- PolarSwitch 標記請求成功并通知 POLARDB 數(shù)據(jù)庫實例。
PolarFS 讀寫使用 SPDK 直接通過 DMA 操作 SSD,而非 OS 內(nèi)核 IO 協(xié)議棧,通過輪詢的方式監(jiān)聽硬件設備 IO完成事件。IO 線程和 CPU 核綁定,也不共享任何數(shù)據(jù)結(jié)構(gòu),相互之間沒有競爭。這種 bypass OS IO 協(xié)議棧的方式,大大提升了高速設備的 IO 處理性能。同時通過 RDMA 網(wǎng)絡大大提升網(wǎng)絡 IO 性能?;窘鉀Q了 HDFS 和Ceph 等分布式文件系統(tǒng)存在的性能差、延遲大的問題。
3.2.3 物理復制
PolarDB 讀寫實例和只讀實例共享一份數(shù)據(jù),需要保證一致性,例如讀寫實例新寫的 Page,即使沒有刷臟,只讀實例也應該可以看到。因此實例之間應當有一定的同步機制(為了保證主備之間的一致性,)。
MySQL 有兩種主要日志: Binlog 和 InnoDB 的 Redo log。Binlog 是 tuple 級的數(shù)據(jù)變更日志,方便 MySQL 易構(gòu)存儲引擎之間同步數(shù)據(jù),也方便下游消費。Redo log,記錄的是文件物理頁面的修改,是 InnoDB 為了支持事務的 ACID 特性。
Binlog 是 tuple 級別的,只讀實例回放的效率太低,回放過程中只讀實例可能還得去請求一些自己根本不需要的 Page。Redo log 顯然是更合適做主備之間的數(shù)據(jù)同步。并且,使用 Binlog 復制目前只能按表級別并行復制,而物理復制可以按照數(shù)據(jù)頁級別并發(fā),粒度更細,并行效率更加高,主備之間的延遲可以保持在毫秒級別。同時在 Binlog 非必須的情況下,關閉 Binlog 也會對性能帶來提升。
所有節(jié)點共享一份全量數(shù)據(jù)和 Redo log,增加只讀節(jié)點非常容易,主備之間的同步只需要元數(shù)據(jù)即可。這使得系統(tǒng)在主節(jié)點發(fā)生故障進行 Failover 時候,切換到只讀節(jié)點的故障恢復時間能縮短到 30 秒以內(nèi)。
通過物理復制保證主備節(jié)點之間的一致性,其實有非常復雜的算法和策略去解決各種各樣可能出現(xiàn)不一致的 case,這里就不詳述了,可以閱讀這篇 http:// mysql.taobao.org/monthl y/2017/09/01/
4.Socrates
4.1 關鍵問題
Socrates 是 Azure 在 SQL Server 基礎上研發(fā)的云原生數(shù)據(jù)庫,依舊采用計算存儲分離的架構(gòu),和 Aurora 相比,分離的更加徹底,在存儲層又將 Page 和日志存儲分開,目的是將持久化和高可用分離。
Azure 認為云上的基于 log 主備同步的 SQL DB(RDS)存在以下幾個主要問題:
- 數(shù)據(jù)容量受到單機存儲能力的限制。
- 超大事務可能打爆本地磁盤。
- Backup/Restore、新拉節(jié)點等操作的成本,和數(shù)據(jù)的體量成正比。
- 每個節(jié)點保存全量的數(shù)據(jù),導致彈性能力較差。
微軟為了解決這些問題,設計了一種新型的云原生數(shù)據(jù)庫,在計算存儲分離架構(gòu)的基礎上,進一步分離存儲層,將 Log 從存儲層分離出來,單獨設計高性能 log 服務。從更高的層面來講就是實現(xiàn)持久性(Durability,由日志實現(xiàn))和高可用性(Availability,由存儲層實現(xiàn))分離。絕大部分數(shù)據(jù)庫這兩個能力均是由存儲層提供的。
Socrates 分離這兩個概念的思路在于: (1)持久化不完全需要昂貴的存儲設備 (詳見5.2.2) 。(2)高可用不完全需要跟多副本 (例如常規(guī)的3副本,詳見 5.2.3)。
如果把這倆概念的需求分開,那么 Socrates 就需要(1)更少昂貴的告訴存儲資源和計算資源,(2)更少的數(shù)據(jù)拷貝。那么他具體是怎么做的呢?
4.2 核心技術
Socrates 將數(shù)據(jù)庫的各個組件拆成獨立服務,提供不同的能力。并盡量使用異步的方式通信,減少響應時間,加快處理速度。Socrates 大體由 4 個組件組成
4.2.1 計算節(jié)點
和上述兩種云原生數(shù)據(jù)庫一樣,Socrates 計算層包括一個讀寫實例和多個只讀實例。讀寫實例如出現(xiàn)故障,則某個只讀會被選為新的讀寫實例。
如上面架構(gòu)圖所示,數(shù)據(jù)庫實例如果需要讀取本都未緩存的 Page,需要通過 GetPage@LSN(實際上是 GetPage(PageID, LSN)) 的 RPC 從響應的 Page Server 獲取。PageID 是 Page 的唯一標識,LSN 則告訴 Page Server 需要返回 應用此 LSN 或者更新的 Page。
一個簡單的例子:
- 讀寫實例在本地緩存更新 Page X 。
- 某種原因,本地 Buffer Pool 中 Page X 被淘汰(需要保證其修改已經(jīng) flush 到 XLOG)。
- 讀寫實例再次讀 Page X。
為了保證可以讀到最新版本的 Page X,需要指定的 LSN。讀寫實例向 Page Server 發(fā)送 GetPage(X, X_LSN) 請求,Page Server 會等待所有小于 X_LSN 的日志都 Apply 完成了再返回 Page X。讀寫節(jié)點維護了一個 PageID -> Page LSN 的映射。
讀寫實例和只讀實例之間沒有直接交互,只讀節(jié)點收到的日志,全部是 XLOG 廣播過來的。只讀節(jié)點收到后需要回放,回放過程中如果遇到相應 Page 不在 Buffer Pool,會直接丟棄。但是它也提供了另一種策略:從 Page Server 獲取 Page 并回放,這就保證了主備之間緩存大體一致,當發(fā)生 failover 時,會更加穩(wěn)定。
4.2.2 XLOG
XLOG 是 Socrates 日志服務層,上圖展示了 XLOG 服務的內(nèi)部實現(xiàn)。
首先,讀寫節(jié)點直接將日志同步寫到 Landing Zone(LZ) ,一個快速持久化存儲服務,以降低寫入延遲,它由 Azure 高級存儲服務 (XIO) 實現(xiàn),為了保證可靠性,數(shù)據(jù)也是三副本存儲。
同時,讀寫節(jié)點異步寫日志到 XLOG Process,該進程將日志傳送到 Page Server 和只讀節(jié)點。LZ 存在的目標僅是為了持久性,而非可用性,可用性由 Page Server 和計算節(jié)點保證。
讀寫節(jié)點并行寫日志到 LZ 和 XLOG Process。因此,日志可能在 LZ 持久化之前到達只讀節(jié)點,可能會在故障發(fā)生時,出現(xiàn)數(shù)據(jù)不一致的情況。為此 XLOG Process 只廣播已在 LZ 中持久化的日志。讀寫節(jié)點首先將日志寫入到 XLOG Process 的 Pending Blocks,一旦日志持久化成功,XLOG Process 將它從 Pending Blocks 移動到LogBroker 用于廣播分發(fā)。
后臺還有一個 Destaging 線程,將已經(jīng)持久化的日志移動到本地 SSD 緩存,以實現(xiàn)快速訪問。同時移動到XStore 長期歸檔保存(Long-Term Archieve, LT)。XStore 使用廉價存儲,成本低、速度慢。LZ 和 LT 保存了所有的日志,共同實現(xiàn)持久化的目標。Socrates 默認將日志記錄保留30天,用于指定時間點恢復和災難恢復。顯然,在 LZ 中保留 30 天的日志,成本非常高,XStore 可以完美接替這個任務。
LZ 快速但昂貴,有利于事務快速提交,XStore 廉價但慢,有利于節(jié)省成本。
4.2.3 Page Server
Page Server 主要負責三件事
- 通過回放日志,管理數(shù)據(jù)庫分區(qū)
- 響應計算節(jié)點的 GetPage 請求
- 打 Checkpoint 和向 XStore 備份
每個 Page Server 只需要關心和自己存儲的 Page 相關的日志,日志中會增加充分的注釋信息,標明日志記錄需要應用到哪些分區(qū)中。XLOG Process 利用這些信息,可以為日志找到目標 Page。
Page Serve 和計算節(jié)點一樣,也使用RBPEX(Resilient Buffer Pool Extention)。但計算節(jié)點緩存是傳統(tǒng)數(shù)據(jù)庫的緩存方式:緩存最熱 Page 達到最好的性能。而 Page Server 緩存本分區(qū)的所有 Page。這對 GetPage 請求的性能非常友好,并且可以容忍 XStore 一定時間宕機。
新拉起一個 Page Server 也非常方便,RBPEX 緩存異步建立,同時 Page Server 可以接受請求和應用日志了。因為每個 Page Server 管理的數(shù)據(jù)并不大,恢復起來還非??斓?。高可用通過數(shù)據(jù)單副本和廉價存儲一份數(shù)據(jù)來共同實現(xiàn)。
4.2.4 XStore
數(shù)據(jù)庫所有的數(shù)據(jù)保存在 XStore 中,Page Server 相當于是其一份緩存。XStore 是一個廉價、跨 AZ 高度復制的存儲系統(tǒng),幾乎不會丟數(shù)據(jù)。XStore 相當于傳統(tǒng)數(shù)據(jù)庫中硬盤,計算節(jié)點和 Page Server 的內(nèi)存和 SSD 緩存(RBPEX),相當于傳統(tǒng)數(shù)據(jù)庫的內(nèi)存。
總體來講,XLOG + XStore 實現(xiàn)了持久性,計算節(jié)點 + Page Server 實現(xiàn)高可用性。
5.對比
對比下來,Aurora 是云原生數(shù)據(jù)庫的先驅(qū),首次將數(shù)據(jù)庫的存儲和計算能力分割,并且將部分數(shù)據(jù)庫的能力下沉到存儲節(jié)點(主要是 Redo),大大減少數(shù)據(jù)的傳輸量,以提升性能和效率。Socrates 則在其之上更近一步,將數(shù)據(jù)庫的組件拆的更加細,行成多個服務層。這種架構(gòu)更加靈活,可用性和成本的控制粒度更細,可以幫助系統(tǒng)在保證性能和可用性的情況下,大幅控制成本。(并不是說 Socrates 比 Aurora 先進,Aurora 近幾年發(fā)展非常快,在 Multi-Master、Serveless 等領域都有一定的突破,在云數(shù)據(jù)庫領域依舊處于領先地位)
雖然 PolarDB 也是存儲計算分離架構(gòu),多個節(jié)點共享一份數(shù)據(jù),但它的切面與 Aurora/Socrates 不同,存儲層是借助各種新硬件能力,保證高可靠、高性能的分布式文件系統(tǒng),然后多個節(jié)點掛載在上面。PolarDB 認為高速網(wǎng)絡和各類新硬件的發(fā)展讓網(wǎng)絡不再是大瓶頸,而瓶頸是在軟件自身,因此做了大量的工作適配新新硬件,使用 OS-bypass 和 zero-copy 的技術提高 CPU 使用效率。PolarDB 這樣的架構(gòu)其實更容易跟進開源社區(qū)的新版本,因為計算層的功能性改動并不是特別大,主要是適配新的存儲和物理復制等。
至于這兩種方式誰更好,那就仁者見仁了。