連續兩篇文章都聊了不同的儲存格式,這篇我們繼續深入來看看在儲存格式的演變之上有什麼新的“黑科技”。華為公司在2016年開源了類parquet的列存格式:CarbonData,並且貢獻給了Apache社群。CarbonData僅僅用了不到一年的時間就成功畢業,成為了Apache社群的頂級專案,CarbonData是首個由華人公司主導的Apache頂級專案,(來源自eBay的Kylin算是首個由華人主導的頂級開源專案)筆者這裡還是要向華為的小夥伴們致敬,能夠完成這樣一個從0到1的突破。
本篇筆者嘗試從技術細節來梳理CarbonData與其“前輩”到底有何不同之處,我們在實際應用與設計儲存格式時有什麼可以借鑑汲取之處。
1.CarbonData
首先我們來看看CarbonData本身的定位,如下圖所示:
- 1、支援海量資料掃描並取其中幾列;
- 2、支援根據主鍵進行查詢,並在秒級響應;
- 3、支援在海量資料進行類似於OLAP的互動式查詢,並且查詢中涉及到許多過濾條件,這種型別的workload應該在幾秒鐘內響應;
- 4、支援快速地抽取單獨的記錄,並且從該記錄中獲取到所有列資訊;
- 5、支援HDFS,無縫對接Hadoop生態圈,天生帶有分散式基因。
對於OLAP查詢來說,存在多種不同型別的查詢,儲存結構的不同會影響到不同查詢的資料表現。所以CarbonData的定位是作為一種通用的查詢儲存資料,通過Spark SQL來解決海量查詢的問題,並且能夠與Hadoop生態圈進行無縫對接。CarbonData最初的應用是與Spark SQL和Spark DataFrame深度結合,後續由攜程團隊將CarbonData引入了Presto,滴滴團隊將CarbonData引入Hive。
其實無論是多維的OLAP查詢,還是完整的掃描查詢,還是部分範圍查詢。CarbonData的前輩ORCFile與Parquet都可以同樣完成任務,那麼作為新人,CarbonData有什麼過人之處呢?
快,更快
下圖是華為提供進行實測的資料,在絕大多數的測試場景之中CarbonData的效能都略優於Parquet。
當然快速的查詢是需要付出代價的,查詢的快速所犧牲的是壓縮率的減小與入庫時間的延長。
那我們接下來就是要詳盡討論CarbonData的效能表現與底層設計之間的邏輯關係。
檔案結構
下圖展示了CarbonData的資料儲存格式:
-
File Header
檔案頭的格式比較簡單,儲存了儲存格式的版本和模式資訊。(這部分通常是穩定不可變的內容) -
Blocklet
單Blocklet最大的容量閥值為64M,也就是說單個HDFS的Block可以容納多個Blocklet(視Block的大小而定)。這塊內容與ORCFile與Parquet的設計一脈相承,都是利用Pax的儲存模型來優化資料查詢時的效能表現。 -
File Footer
在檔案尾部儲存了儲存資料的索引和摘要,索引是CarbonData最為核心的關鍵實現,正是由於索引的存在,大大提高了CarbonData在不同查詢場景之下的效能表現。
二級索引
CarbonData通過支援了二級索引,大大的提高了CarbonData資料查詢的效能表現。
由上圖所示CarbonData在HDFS Block級別與內部的Blocklet級別都分別建立起索引,這樣可以大大減少非必要的任務啟動與非必要的磁碟IO操作。眾所周知,引入索引的的確確能夠加快資料的查詢速率,但是天下沒有免費的午餐。我想CarbonData壓縮率縮減與資料匯入時間的延長的原因,想必讀者心中也有了答案。
我們可以看到在CarbonData的檔案尾部,通過B+樹的方式來實現索引。由於HDFS追加寫的特性,所以我想讀者應該也能明白為何這些索引資料與統計資料需要存放在CarbonData的末尾。
上圖完整的展現了一次過濾查詢的流程,這個過程在二級索引的作用之下,規避了大量非必要的查詢互動,由此帶來的效能優化是十分明顯的。
相對於ORCFile與Parquet相對簡要的摘要索引,CarbonData在索引層面頗費心思。通過這樣的方式來超越前輩,當然這樣的選擇設計同樣也要付出額外的代價。
全域性字典編碼
這是CarbonData之中頗具爭議的功能,在CarbonData之前的版本是預設新增的內容,目前在1.3版本之中是作為可選項加入其中的。(筆者在華為高斯部門工作的師兄也曾經和筆者吐槽過在生產環境之中,全域性字典編碼的似乎還存在一些`坑`)所以看起來能夠運用好字典編碼的確是個值得探討的問題,筆者在此也簡單聊一聊:
如上圖所示,全域性字典編碼的方式很簡單,就是通過數字和字典來替換表格之中重複出現的資料。 這樣的好處很明顯:
-
大大減少了表格資料所需要儲存的資料量
-
某些需要進行group by的欄位進行全域性字典編碼,可以大量減少計算時的shuffle的資料量。以達到效能提升的目的。
但是在將資料匯入CarbonData的過程之中,對與重複率較低的列,一旦建立起全域性字典,顯然會大大拖慢資料的匯入速度,並且影響資料的壓縮程度。而如果對於資料重複率較高的資料,例如性別,年齡等高重複資料,通過建立全域性字典能夠大大提升CarbonData的壓縮程度,並且對資料匯入的速率影響不大。
筆者建議:對於字典編碼的使用,還是要根據具體也業務場景進行分析壓測,給出較為合適的使用方式,盲目使用字典編碼反而會對效能帶來負優化。
2.小結
到此為止,筆者也大致聊完了對CarbonData儲存結構的理解以及筆者在簡單實踐之中所引發的思考。 作為華人圈子之中首個由華人公司主導的Apache的頂級專案,筆者也會繼續對CarbonData進行關注與學習,也希望將來華人程式設計師能夠在開源圈之中繼續擴大影響力。