讀Paimon原始碼聊設計:引子

發表於2024-02-26

最近我司開始探索Paimon在部分場景下的使用,因此我這邊需要做一些技術儲備,慢慢關注起來Paimon的一些實現細節。

簡單介紹一下前輩Iceberg

一般的資料湖都會設計成開放通用的,即不和特定的儲存、計算引擎(比如Spark和Flink)繫結。所以資料湖的定位是在計算引擎之下,又在儲存之上,將其稱之為table format。需要強調的是資料湖一般是面向OLAP場景的,所以一般儲存會選擇分散式檔案系統。現在OLAP底層儲存支援物件儲存基本算是快成業界共識了,這玩意兒挺划算的。

資料湖的前輩基本就是Hive了。當時大家用Hive碰到的問題就是Hive耦合HDFS很厲害,最主要體現在:

  1. Hive上的計算執行首先依賴於list操作。在物件儲存上做list是個很慢的操作。
  2. Hive的寫資料依賴於rename。但同樣這個操作在物件儲存上做特別的慢。

這兩個問題直接導致無法降本。從這點上來說,Iceberg是自己維護了一套後設資料,這塊網上非常的全,就不再贅述了,google上搜iceberg file layout一大把。

Hive還有其他的問題,如:

  1. metastore的瓶頸問題。
  2. 沒有ACID保證。
  3. parition欄位必須顯示的在query裡。
  4. 下推能力有限。Hive只能透過partition和bucket對需要掃描哪些檔案進行過濾,無法更加細緻。儘管parquet檔案裡儲存了max和min值可以用於進一步的過濾,但沒軟用。

Iceberg把這些都解了。基於快照實現事務、資料的更新,快照的資料也允許跳版本讀取來做時間回溯。同時收集的統計資訊也更加細粒度,不僅僅是檔案parition級別的,還會記錄檔案級的內容(比如一個檔案中的min、max值)和實現檔案內容級的資訊——一個檔案中的min、max等等。

聽起來一切都還很美好。唯一美中不足的就是Iceberg對於實時場景支援得不好:

  • Flink寫入Iceberg會引發小檔案的問題。
  • Iceberg不支援CDC(OLAP支援CDC的確有點離譜,但是的確有需求呀)。
  • Iceberg主鍵表不支援部分欄位更新。這在實時數倉的場景中有點離譜。

Paimon可以解決什麼問題

目前看來Paimon基於Iceberg的場景上,去支援流讀流寫(這塊後續會做原始碼分析),甚至還支援了點查和預聚合。本質是分散式檔案系統上套了一個LSM,這樣資料都是有序寫入——將多次寫入最佳化成一次順序寫入,對儲存系統上比較友好的。同時LSM可以作為一個簡單的快取,且有序寫入為後面查詢也可以減少代價,這都可以為查詢減少代價。

從場景上來說它可以解決一些準實時業務的場景。因為基於物件儲存來做底層儲存,尤其還是列式儲存。無論如何都不好做到實時場景:

  • Paimon的CDC根據不同的模式,會有不同的新鮮度。發出完整CDC的模式要選擇Lookup。一般是Checkpoint的間隔+10s多新鮮度,這是比較好的效能考量下。具體還要看資料量、分桶數、小檔案數量的影響。
  • 實時場景要求是毫秒級點查響應。Paimon支援的是秒級點查。

但現實中真正需要實時類場景的業務有多少呢?因為資料的新鮮度往往和業務決策週期有關係。這麼來看,資料新鮮度的要求從高到低,對於業務場景的總數來說,一定是一個金字塔形狀的。

我們前面提到過資料湖一般不會和任何計算引擎繫結。因此業界還有一種玩法叫湖上建倉,計算能力用的是OLAP,資料來自資料湖。這樣就很有想象力了,因此現在一些實時+離線的場景會用不同的儲存引擎,那麼資料就會複製好幾份。如果資料都放在同一個資料引擎中,這樣可以減少不少的儲存成本。(對於通用型設計 這塊後續會做原始碼分析

具體實現還是看對於效能的要求的:

  • 要求低就做一些簡單的最佳化直接撈資料。
  • 再高點就快取到OLAP裡。
  • 再高點就不僅僅是快取到OLAP裡,還會做物化檢視。

Trade Off

Serving、Trascantion、Analytics

根據業界常識,我們會發現:

  • 面向線上應用,高併發、快速、簡單,如:HBase、Redis
  • 面向分析的,大規模資料掃描、過濾、彙總,如:Hive、Presto
  • 面向事務、隨機讀寫的,如:MySQL,PostgreSQL

資料湖是典型的OLAP產物。但結合上文,它的確具有一定的隨機讀寫能力。

Buffer、Mutable、Ordered

儲存結構有三個常見變數:是否使用緩衝、使用不可變的還是可變的檔案,以及是否按順序儲存值(有序性)。

由於TiDB底層的RocksDB用了LSM。因此使用了緩衝、不可變性以及順序性。

RUM

有一種流行的儲存結構開銷模型考慮瞭如下三個因素:讀取(Read)、更新(Update)和記憶體(Memory)開銷。它被稱為RUM猜想。

RUM猜想指出,減少其中兩項開銷將不可避免地導致第三項開銷的惡化,並且最佳化只能以犧牲三個引數中的一個為代價。我們可以根據這三個引數對不同的儲存引擎進行比較,以瞭解它們針對哪些引數進行了最佳化,以及其中隱含著哪些可能的權衡。

一個理想的解決方案是擁有最小的讀取開銷,同時保持較低的記憶體與寫入開銷。但在現實中,這是無法實現的,因此我們需要進行取捨。

Paimon允許在配置中自由設定LSM的高度,以便獲取讀與寫之前的權衡。

內幕鳥瞰

前面說到過,計算部分是依賴於計算引擎實現的,本身Paimon沒有提供計算能力。儲存則是基於部分是檔案系統做了薄薄的一層LSM。

從檔案佈局來看,Partition相當於是一級索引,和Hive一樣。Bucket為二級索引,每個Bucket下都會有Data file和Change log file。這意味著如果命中了Parition和Bucket條件,有一些額外的條件查詢也不會太慢——一般都會收集檔案級的統計資訊,並對檔案的Reader做一些過濾最佳化。

整體的佈局還是和Iceberg挺像的,這邊不再過多贅述。

小結

在這篇文章中我簡單的介紹了一下Paimon要解決的問題,以及它的前輩Iceberg的強大與不足之處。

目前該專案還處於孵化中,後續我會一直關注其實現細節,敬請期待。

相關文章