天天看點

Kudu

Kudu 主要面向 OLAP 應用,支援大規模資料存儲,支援快速查詢,并且支援實時資料更新。相比Hive 之類的SQL on Hadoop,性能會好不少,并且支援資料實時更新,這也是 Hive 的一個痛點;相比于一個傳統的 OLAP 資料庫,它所支援的資料規模可能要大一點,畢竟 Kudu 是水準擴充的。

Kudu 的paper裡提到,它的一個設計目标是統一存儲日志資料和線上資料,并且提供高效的查詢。這也是我們團隊目前想要實作的一個目标。

目前團隊使用的 Hive,Hive 能夠查詢大規模資料,但痛點也很明顯:一來占用資源很多,經常一個 MapReduce 的Job 就能跑半個小時幾十分鐘,對叢集資源的占用是相當大的;二來,查詢延遲相當高,如果隻是跑一些報表還沒有太大問題,但是如果着急需要一些資料,等上半個小時可能就是想當麻煩的;三來,Hive 不支援實時資料更新,雖然 ORC 看起來能實作資料更新,但延遲、吞吐量都想當捉急,略顯雞肋。

也有調研過 Hive on HBase 之類的方案,能夠實作資料實時更新,但最緻命的一點是,它的效率比 Hive 本身還要低,例如在 join 兩個大表的時候會用 hash join 的方式,并且赤裸裸地把其中一個表轉成 hash table load 到記憶體裡,但千萬級的表根本就很難 load 到記憶體裡。對于普通的查詢來說,效率也要低不少。究其原因,還是 HBase 的scan 性能不足,對于OLAP 來說,順序 scan 的性能相當關鍵,這也是 HDFS 能夠勝任的原因所在。

目前看來,基于 HDFS的方案通常都能提供不錯的查詢性能,但對于 實時更新的要求來說就有點捉襟見肘了;基于HBase、Cassandra的方案能夠支援實時資料更新,但 scan 的吞吐量不能滿足。

還有一些方案,例如 Facebook 的Presto,一些商業的 OLAP 資料庫,Vertica 之類,使用門檻也并不低,并且前景也不明确。

評價 Kudu,當然是先看性能。官方的 paper 上有一些性能的比較:對于順序 scan,比parquet 格式的 HDFS 存儲性能不相上下;相比于 Apache Phoenix,性能秒殺;而 Random Access 的性能,略遜色于 HBase。

對于這樣的結果,應該可以說是非常贊的。不過我們還是持謹慎的态度,自己又做了一次 benchmark。考慮到使用場景,我們并沒有采用 tpc-h benchmark,而是 采用了 tpc-ds ,這也是 Hive 所采用的 benchmark,能有效評價大規模資料下的表現。

機器性能一般,四台機器,12核,32GB 記憶體,SSD 硬碟。實際測試中發現記憶體和CPU 占用都不太高。

使用了10GB資料的benchmark,具體 benchmark 的結果過于冗長,簡而言之,在機器配置接近的情況下(Hive 用了另一個叢集跑的,性能要高一點),Kudu 的執行時間通常在 Hive 的十分之一左右。不得不服。不過也存在一些問題,不支援 bulk load,導入資料這一過程還是非常慢的,幾億行的資料要幾十分鐘了。

不過從目前的結果來看,基本能滿足我們的要求。

既然是面向 OLAP,那麼 Kudu 還是使用列式存儲,比 HBase 要好一點的是,它每列都是單獨存儲,幾乎沒有 column family 的限制。

Kudu 使用 C++ 開發,相比于 Hadoop 生态衆多使用 java 開發的程式來說,性能會有一定優勢,并且在 GC上,算是解決了 HBase GC停頓的痛點。由于使用了 C++,Kudu 在一些細節上也做了很多優化,例如 SSE 指令,在row projection 的時候使用 LLVM 進行 JIT編譯,據說這些優化帶來了顯著的性能提升。不過使用 C++ 也可能會存在一些問題,比如說和 Hadoop 生态的整合如何搞定呢?

Kudu 在開發時完全考慮 Hadoop 生态,盡量減少使用成本。首先查詢引擎使用 Impala,如果一開始就使用 Impala 的話使用成本會降低很多;與 Spark 內建時,也有相應的接口,可以把 Kudu 的資料 load 到一個 RDD中進行操作,或者一個 DataFrame,用SparkSQL 進行查詢。

實際使用了一番,雖然 API 确實很好用,跟開發一個普通的 Spark 程式别無二緻,但是其吞吐量還是差了不少,把整個資料庫的内容 load 到記憶體還是相當慢的。在這一點上應該沒辦法完全替代 HDFS。

Kudu 還是繼承了GFS、Bigtable 的傳統,叢集架構跟 Bigtable 很像,分為 master、tablet server。master 存儲中繼資料,tablet 管理資料。不過 master/slave 的 HA 做得并不好,master 通常還是存在單點問題。在這一點上,Kudu 采用了multi master 的方案:master 的資料用Raft做replication,多個master也分 leader/follower,用Raft 做 leader election。至于

tablet server,也分leader/follower,同樣使用 Raft 做replication和leader election。

使用 Raft這樣的一緻性協定貌似已經成了共識,新出現的分布式系統很少使用簡單的 master/slave 了。對于 multi master 的了解還不是很多,不知道會不會帶來新的問題。

Kudu 的 partition 政策有兩種,并且是正交的,一種是 hash partition,另一種是range partition。range partition 比較适合時間序列資料,例如日志,可以每天劃分一個partition,這樣的通路效率也會比較高。

Kudu 的存儲模型類似關系模型,支援primary key,資料也是強類型的,有 int、string之類的資料類型。不過目前還不支援輔助索引,也許以後會實作。

一緻性模型,支援snapshot scan,用MVCC保證,也就是說一次scan 過程中讀到的資料是一緻的。不過不支援多行事務,對于 AP資料來說也沒有太大的必要性。

時間戳,與 HBase 不同,不支援 write 操作指定時間戳,但是在read 的時候可以指定。

Kudu 最大的特點還是它的存儲引擎,也是它的性能保證。Kudu 的存儲引擎沒有像 HBase 一樣基于 HDFS,而是基于單機的檔案系統。(貌似現在的另一個流行趨勢,就是不再基于分布式檔案系統來搞分布式資料庫了,可能是基于 immutable 存儲來搞 mutable 确實比較累。)

單機的存儲引擎整合了 LSM、B tree等經典的結構,可以看到 LevelDB、Parquet的影子。存儲還是分為 memory 和 disk,資料先寫入 memory和 write ahead log,再刷到 disk。整個存儲抽象成 RowSet,細化為 MemRowSet 和 DiskRowSet。

MemRowSet,就是一個 B+ tree,樹葉節點的大小是 1K,剛好是4塊 cache-line(!!!);使用 SSE2 指令進行 scan,據說性能非常高。

對于 DiskRowSet,分為 base 和 delta,更新的資料寫到 delta,定時 compact 到 base,沒有像 LevelDB那樣使用多級的 LSM。base 是一個經典的列式存儲實作,針對不同的資料類型采用了不同的編碼方案,例如字典編碼、行程編碼、front encoding 等等技術都用上了,盡量減少空間占用。在資料存儲的基礎上,使用了B+ tree 對primary key 進行索引,也用了 BloomFilter 加速查找。值得一提的是,BloomFilter

的大小是4KB,剛好又是filesystem pagecache 的大小。DiskRowSet 的設計借鑒了很多 Parquet 的思想,值得深入學習。

部署安裝相當簡單,添加相應的 repository 就可以安裝,配置精簡,無須一些亂七八糟的配置

穩定性還可以,跑了幾天,也跑了一些負載比較高的任務,沒有挂掉

管理控制做的還不是很到位,指令行提供的功能相對較弱

資源占用很少,機器的負載很低

性能相當贊,碾壓 Hive 的快感

之後還會做一些使用跟調研,希望能夠盡快在生産環境中用上 Kudu。