分享人:陳宗志(暴跳)
摘要:本篇論文收錄在 VLDB 2022,介紹了雲原生資料庫PolarDB在計算存儲分離架構下遇到的性能挑戰,分析了雲存儲相對于傳統本地存儲的工作特性差異及其根因,讨論了将各類存儲引擎部署至雲存儲上時所會遇到的問題挑戰,并提出了統一的優化架構 CloudJump。最後通過實驗證明優化架構CloudJump适用于PolarDB,也适用于 RocksDB。
一. 背景
1.計算存儲分離架構雲資料庫存在的問題
下圖左邊是本地集中式資料庫,右邊是計算存儲分離架構資料庫。本地資料庫通過本機 Cache 到 Local I/O再到 Local SSDs;計算存儲分離架構資料庫:在計算存儲分離架構下會帶來網絡開銷,同時也會産生其他存儲副本。
計算存儲分離架構帶來的網絡延遲、I/O 延遲、Pattern 改變等問題,在 PolarDB 上也同樣存在,并且還未被研究和解決。
2.項目目标
a. 計算存儲分離雲資料庫的優勢:
- 海量存儲能力;
- 快速彈性能力;
- 服務高可用,資料安全可靠;
- 極緻性能;
- Serverless、pay-as-you-go;
b. 雲端成熟的雲存儲服務的優勢:
- 海量存儲能力;
- 資料持久化、服務高可用;
- 聚合 I/O 吞吐性能高;
- 用量可選,彈性計費;
是以,本次項目的目标,是在通用雲存儲服務上建構雲/雲原生資料庫能力,避免雲存儲特性差異化(于本地存儲) ,高延遲、低隔離限制等。
- 充分運用規模化雲存儲能力;
- 存儲側不暴露容錯等複雜細節;
- 減少維護成本、加速資料庫開發周期。
3.早期實驗發現
雲存儲和本地 SSD 存儲在帶寬、延遲、彈性、容量等方面存在巨大差異。
下圖對比了在穩态條件下,本地 SSD 與雲存儲在 I/O 延時、吞吐量與工作線程的關系,其中紫色線是本地 SSD,橙色線是雲存儲,灰色線是雲存儲打撒 I/O。
左圖是 I/O 延遲與工作線程的關系,可以看到,本地 SSD 的 I/O 延遲遠優于雲存儲;
右圖是吞吐量和工作線程的關系,可以看到,雲存儲的吞吐量比本地 SSD 要高。
通過線上經驗和系統實驗發現以下挑戰:
- 由于遠端通路的高時延,采用雲存儲後出現慢 SQL;
- I/O 時延大、聚合帶寬高;
- 多節點一緻性造成資料庫網絡帶寬使用率低;
- I/O 隔離性問題導緻刷髒時 WAL 寫入性能下降。
4.雲存儲差異化特性帶來的挑戰
下圖中的表格總結了上述挑戰對資料庫設計的影響。對比基于 B-tree 結構(Update-in-place)和基于LSM-tree 結構(Append-only),其中有共性問題,如 WAL 路徑寫入變慢、共享存儲(分布式檔案系統)cache 一緻性代價等;也有個性問題,如 B-tree 結構在獨占資源情況下做遠端 I/O、遠端加劇 I/O LSM-tree 讀放大影響等。
二. 設計思考
前面論述了本地盤和雲盤在延遲、帶寬、防護模式、隔離等方面的差別,我們希望設計一個優化架構CloudJump,可以将本地盤 InnoDB 存儲引擎優化成面向雲盤設計的存儲引擎,并同時适用于 B-tree 和LSM-tree。
基于上述挑戰以及雲盤的特征,CloudJump提出7條優化準則:
1.Thread-level Parallelism
依據 I/O 特性實驗,采用(更)多線程的日志、資料 I/O 線程及多隊列異步 I/O 模型,将資料打散到多個存儲節點上,充分利用多個存儲節點的 I/O 能力;
2. Task-level Parallelism
對原集中 Log buffer 按 Page Partition 分片,多任務并行寫入;
基于分片進行并發 Recovery,進而規避雲盤 I/O 延遲高的問題;
3. Reduce remote read and Prefetching
通過收集并聚合原分散 meta 至統一的 superblock,實作 fast validating(fast startup);
通過預讀利用聚合讀帶寬,減少讀任務延時;
通過壓縮、filter 過濾,減少讀取資料量;
與本地 SSD 上相比,這些技術在雲存儲上更能獲得收益;
4. Fine-grained Locking and Lock-free Data Structures
雲存儲中較長的 I/O 延遲放大了同步開銷,主要針對 B-tree,實作無鎖刷髒、無鎖 SMO 等;
5. Scattering among Distributed Nodes
在雲存儲中,多個節點之間的分散通路可以利用更多的硬體資源,例如将單個大 I/O 并發分散至不同存儲節點 ,充分利用聚合帶寬的能力;
6. Bypassing Caches
通過 Bypassing Caches 來避免分布式檔案系統的 cache coherence,并在 DB 層面優化 I/O 格式,比對存儲最佳 request 格式;
7. Scheduling Prioritized I/O Tasks
由于通路鍊路更長(如路徑中存在更多的排隊情況),不同 I/O 請求間的隔離性相對本地存儲更低,是以需要在 DB 層面對不同 I/O 進行打标、排程優先級,例:優先 WAL、預讀分級。
三. 案例實踐:PolarDB
優化後的 PolarDB 架構如下圖所示,左上是讀寫節點(RW node),右上是隻讀節點(RO node),下面是共享存儲(雲存儲)。
基于 PolarDB 架構,我們做了許多适配分布式存儲特性、同時符合上述優化準則的性能優化,大幅提升了雲原生資料庫 PolarDB 的性能。
1.WAL寫入優化
下圖左邊的架構是針對本地盤的 WAL I/O設計,将多個 mlog 集中拷貝到 redo 的日志緩沖區(Buffer)中,然後順序向下寫入檔案(File),這種單線程順序的寫入的方式在本地盤表現良好,但是對于雲存儲,這種方式的問題在于:
- WAL 寫入性能優于 I/O 延遲高而降低;
- I/O 串行化,帶寬使用率低;
優化内容:
- 日志緩沖區(Log buffer)分片,寫入并行化;
将 redo 的日志緩沖區按其修改的 page 進行分片(partition),分别寫入不同的檔案中,支援并發寫 log,進而在适合并發寫入的分布式檔案系統上的獲得寫入性能優勢;
- 異步多任務線程,帶寬使用率高;
寫入不同的檔案就會映射到不同的存儲節點,利用存儲多節點的 I/O 能力可以提升帶寬使用率;
- 打散 I/O,利用分布式存儲分布寫性能。
下圖左将redo日志緩沖區分片:Log Buffer1&2&3,其中綠色的小方塊代表已經寫滿的連續的 redo 日志,旁邊的小方塊是有緩沖區的日志,橙色方塊是 pending 日志,需要将綠色和橙色塊之間的部分填滿,形成連續的 redo 日志後,再繼續往下寫。
下圖右是對于單個大 log I/O任務(如 group commit、BLOB record 等),log writer 會将I/O切片,并且并發的分發 I/O 請求至不同 split。
2.快速恢複
在建立、修改檔案時,将必要的元資訊集中記錄在一個 superblock 中,在啟動時僅掃描中繼資料塊檔案。是以,減少了啟動掃描過程中遠端 I/O 的通路開銷。
3.預讀取
有效的預讀取,能夠充分利用聚合讀帶寬,減少讀任務延時。
如下圖所示,如果連續通路 4 個 page 就會觸發異步并發預讀,這 4 個 page 屬于邏輯上連續但實體上非連續的,将它們提前讀取到BP,以減少讀任務延遲。
另外,對于具有二級索引和非覆寫列的回表操作,采用 Batched Key 預讀。
4.并行恢複
基于 Page Partition 分片,多任務并發恢複/日志解析和申請。
5.鎖優化
在 InnoDB 裡面, 全局的 index latch 存在,會導緻同一時刻在 B-tree 中隻有一個 SMO 能夠發生;另外,鎖同步期間 index 上其他可能 I/O 操作無法并行,存儲帶寬使用率較低。
鎖優化将去除 SMO 等操作時的備援鎖,提升記憶體、I/O 操作的并發度。
Shadow Page
首先對目前 page 建構記憶體副本,建構好記憶體副本後原有 page 的 sx 鎖被釋放,然後用這個 shadow page内容去做刷髒及相關刷寫資訊更新。
優化 page I/O 的長時間鎖占用,将長占有鎖(remote I/O時長)轉換為短占有鎖(記憶體複制時長),提升操作并發度。
6. I/O對齊和排程
a. 針對分布檔案 BypassCache 導緻的直接 I/O
- 對齊最優化的 I/O offset&length,加速 directI/O;
- 去除無效 I/O 合并,發揮随機寫特性;
- 多異步 I/O 任務隊列,充分并行化,發揮帶寬優勢。
b. 針對 Remoteaccess 路徑長、不同 I/O 隔離性低
- I/O 優先級排程,優先關鍵 I/O,消除低隔離影響。
7.資料測試結果
将 MySQL 分别運作在 PolarStore 和本地盤,以及優化後的 PolarDB 進行性能對比,從下面 Figure 10圖中可以看到,優化後的 PolarDB 在 CPU-bound, I/O-bound sysbench, TPC-C 等各個場景下,都表現出明顯的性能優勢。
圖11是不同的優化政策在 CPU-bound(隻寫、讀寫), I/O-bound(隻寫、讀寫), TPC-C 場景下的性能提升的力度和大小,可以看到優化政策在 CPU-bound場景下,性能普遍提升比較明顯。
圖12是不同優化政策在 WAL 加速方面的表現。
另外,還測試了雲存儲優化的 PolarDB 運作在 StorageX,、ESSD 等其他雲存儲上的性能, 發現均能獲得非常好的性能提升。如下表所示,對比這個雲存儲,在延遲性能上,PolarStore 的延遲最低。
四. 實踐案例:RocksDB
我們還将設計架構及部分優化政策拓展到基于雲存儲的 RocksDB 上,以驗證其通用性。
1.優化後的RocksDB架構
下圖是優化後的 RocksDB 架構圖,最上層是 WAL 日志、Compaction 和 Flush,到 I/O 對齊、打标和排程,通過多 I/O 隊列将 I/O 任務并行打散到雲存儲的 Log 和 Data 上。
2.資料測試結果
我們将以下優化方法移植到 RocksDB 上,獲得與設計架構分析一緻的性能收益:
- Scattered & Partitioned Global Log;
- Multi-queue Scatter I/O with Schedule;
- Direct I/O Alignment;
下圖是 RocksDB 在優化前後各種性能的對比,柱狀圖最左邊的是 Baseline,可以看到在不同場景下,RocksDB 的優化性能有不同的表現。
五. 總結
在這項論文工作中,主要分析了雲存儲的性能特征,将它們與本地 SSD 存儲進行了比較,總結了它們對B-tree 和 LSM-tree 類資料庫存儲引擎設計的影響,并推導出了一個架構 CloudJump 來指導本地存儲引擎遷移到雲存儲的适配和優化。并通過 PolarDB, RocksDB 兩個具體 Case 展示優化帶來的收益。
詳細内容請參閱論文《CloudJump: Optimizing Cloud Database For Cloud Storage》(https://www.vldb.org/pvldb/vol15/p3432-chen.pdf)