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