三大雲原生資料庫:Aurora, PolarDB 與 Socrates

語言: CN / TW / HK

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 在許多公開的分享和文章中,強調了傳統資料庫架構上雲,存在很多問題,這裡列舉一些典型的:

擴充套件性相關:

  1. 由於物理機磁碟限制以及備份等策略,資料庫的資料大小不能太大,太大的例項是運維的災難。
  2. 活動上線時造成壓力突增,而資料庫卻來不及升級。
  3. 業務發展很快,來不及進行拆庫,也來不及分庫分表。

效能相關:

  1. 傳統備份技術,由於涉及到拷貝資料,並上傳廉價儲存,速度因此也受網路影響。一次全量資料備份需要大量時間,並且必須鎖表等。
  2. 讀寫例項和只讀例項各自擁有一份獨立的資料,新建一個只讀例項需要重新拷貝資料,考慮到網路限流,速度不會很快。
  3. MySQL資料庫早期的版本,對早期的系統/硬體做了很多優化,但是並沒有考慮到現代主流的系統/硬體的優秀特性,在高併發環境下,效能還有很大的提升空間。
  4. MySQL為了相容性,需要寫兩份日誌(事務日誌和複製日誌),與其他商業資料庫相比,效能相對較差。
  5. 讀寫例項和只讀例項通過增量邏輯資料同步,讀寫例項上所有的SQL需要在只讀例項上重新執行一遍(包括SQL解析,SQL優化等無效步驟),同時,複製併發讀最高是基於表維度,導致主備延遲非常普遍,進而影響各種切換任務。
  6. 應用擴容之後,上百臺ECS連線一臺資料庫,因此在高併發下效能很差。

成本相關:

  1. 讀寫例項和只讀例項各自擁有一份獨立的資料,使用者購買只讀例項,不僅需要付出計算的成本,也需要付出儲存資源的成本。

....

這些問題本質上都是單機資料庫所面臨的的問題,資料庫上雲,當然就是要解決這些問題。但是僅僅簡單的將單機資料庫部署在雲上,這些問題還是存在的。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的寫操作流程大致如下:

  1. POLARDB 通過 libpfs 傳送寫請求經由 ring buffer 到 PolarSwitch。
  2. PolarSwitch 根據本地快取元資料,將寫請求傳送至對應 Chunk 的 Chunk Server Leader 節點。
  3. 請求到達 ChunkServer 後,節點的 RDMA NIC 將 Request 加入 request 佇列。一個 IO 輪詢執行緒不斷輪詢該請求佇列,一旦發現有新請求則立即開始處理。
  4. IO 處理執行緒非同步將請求寫到 Chunk 對應的 WAL 塊上(通過 SPDK),同時將請求非同步發向給 Follower 節點。
  5. 寫請求到達 Follower 後,同樣通過 RDMA NIC 將其放到 request 佇列。
  6. Follower 節點上的 IO 輪詢執行緒被觸發,同樣非同步寫入。
  7. Follower 節點的寫請求成功,通過 RDMA 向 Leader 傳送應答。
  8. Leader節點收到 Followers 裡任一節點成功應答後,即形成 majority,同樣通過 SPDK 將寫請求寫到相應的資料塊。
  9. Leader 通過 RDMA NIC 向 PolarSwitch 返回請求處理結果。
  10. 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)存在以下幾個主要問題:

  1. 資料容量受到單機儲存能力的限制。
  2. 超大事務可能打爆本地磁碟。
  3. Backup/Restore、新拉節點等操作的成本,和資料的體量成正比。
  4. 每個節點儲存全量的資料,導致彈效能力較差。

微軟為了解決這些問題,設計了一種新型的雲原生資料庫,在計算儲存分離架構的基礎上,進一步分離儲存層,將 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 這樣的架構其實更容易跟進開源社群的新版本,因為計算層的功能性改動並不是特別大,主要是適配新的儲存和物理複製等。

至於這兩種方式誰更好,那就仁者見仁了。