1. 程式人生 > >Kudu:支援快速分析的新型Hadoop儲存系統

Kudu:支援快速分析的新型Hadoop儲存系統

Kudu 是 Cloudera 開源的新型列式儲存系統,是 Apache Hadoop 生態圈的新成員之一( incubating ),專門為了對快速變化的資料進行快速的分析,填補了以往 Hadoop 儲存層的空缺。本文主要對 Kudu 的動機、背景,以及架構進行簡單介紹。

背景——功能上的空白

        Hadoop 生態系統有很多元件,每一個元件有不同的功能。在現實場景中,使用者往往需要同時部署很多 Hadoop 工具來解決同一個問題,這種架構稱為 混合架構 (hybrid architecture) 。 比如,使用者需要利用 Hbase 的快速插入、快讀 random access 的特性來匯入資料, HBase 也允許使用者對資料進行修改, HBase 對於大量小規模查詢也非常迅速。同時,使用者使用 HDFS/Parquet + Impala/Hive 來對超大的資料集進行查詢分析,對於這類場景, Parquet 這種列式儲存檔案格式具有極大的優勢。

        很多公司都成功地部署了 HDFS/Parquet + HBase 混合架構,然而這種架構較為複雜,而且在維護上也十分困難。首先,使用者用 Flume 或 Kafka 等資料 Ingest 工具將資料匯入 HBase ,使用者可能在 HBase 上對資料做一些修改。然後每隔一段時間 ( 每天或每週 ) 將資料從 Hbase 中匯入到 Parquet 檔案,作為一個新的 partition 放在 HDFS 上,最後使用 Impala 等計算引擎進行查詢,生成最終報表。

這樣一條工具鏈繁瑣而複雜,而且還存在很多問題,比如:

  •   如何處理某一過程出現失敗?
  •   從 HBase 將資料匯出到檔案,多久的頻率比較合適?
  •   當生成最終報表時,最近的資料並無法體現在最終查詢結果上。
  •   維護叢集時,如何保證關鍵任務不失敗?
  •   Parquet 是 immutable ,因此當 HBase 中刪改某些歷史資料時,往往需要人工干預進行同步。

        這時候,使用者就希望能夠有一種優雅的儲存解決方案,來應付不同型別的工作流,並保持高效能的計算能力。 Cloudera 很早就意識到這個問題,在 2012 年就開始計劃開發 Kudu 這個儲存系統,終於在 2015 年釋出並開源出來。 Kudu 是對 HDFS 和 HBase 功能上的補充,能提供快速的分析和實時計算能力,並且充分利用 CPU 和 I/O 資源,支援資料原地修改,支援簡單的、可擴充套件的資料模型。

背景——新的硬體裝置

        RAM 的技術發展非常快,它變得越來越便宜,容量也越來越大。 Cloudera 的客戶資料顯示,他們的客戶所部署的伺服器, 2012 年每個節點僅有 32GB RAM ,現如今增長到每個節點有 128GB 或 256GB RAM 。儲存裝置上更新也非常快, 在很多普通伺服器中部署 SSD 也是屢見不鮮。 HBase 、 HDFS 、以及其他的 Hadoop 工具都在不斷自我完善,從而適應硬體上的升級換代。然而,從根本上, HDFS 基於 03 年 GFS , HBase 基於 05 年 BigTable ,在當時系統瓶頸主要取決於底層磁碟速度。當磁碟速度較慢時, CPU 利用率不足的根本原因是磁碟速度導致的瓶頸,當磁碟速度提高了之後, CPU 利用率提高,這時候 CPU 往往成為系統的瓶頸。 HBase 、 HDFS 由於年代久遠,已經很難從基本架構上進行修改,而 Kudu 是基於全新的設計,因此可以更充分地利用 RAM 、 I/O 資源,並優化 CPU 利用率。我們可以理解為, Kudu 相比與以往的系統, CPU 使用降低了, I/O 的使用提高了, RAM 的利用更充分了。

簡介

        Kudu 設計之初,是為了解決一下問題:

  •   對資料掃描 (scan) 和隨機訪問 (random access) 同時具有高效能,簡化使用者複雜的混合架構
  •   高 CPU 效率,使使用者購買的先進處理器的的花費得到最大回報
  •   高 IO 效能,充分利用先進儲存介質
  •   支援資料的原地更新,避免額外的資料處理、資料移動
  •   支援跨資料中心 replication

        Kudu 的很多特性跟 HBase 很像,它支援索引鍵的查詢和修改。 Cloudera 曾經想過基於 Hbase 進行修改,然而結論是對 HBase 的改動非常大, Kudu 的資料模型和磁碟儲存都與 Hbase 不同。 HBase 本身成功的適用於大量的其它場景,因此修改 HBase 很可能吃力不討好。最後 Cloudera 決定開發一個全新的儲存系統。

        Kudu 的定位是提供 ”fast analytics on fast data” ,也就是在快速更新的資料上進行快速的查詢。它定位 OLAP 和少量的 OLTP 工作流,如果有大量的 random accesses ,官方建議還是使用 HBase 最為合適。

架構與設計

1. 基本框架

        Kudu 是用於儲存結構化( structured )的表( Table )。表有預定義的帶型別的列( Columns ),每張表有一個主鍵( primary key )。主鍵帶有唯一性( uniqueness )限制,可作為索引用來支援快速的 random access 。

類似於 BigTable , Kudu 的表是由很多資料子集構成的,表被水平拆分成多個 Tablets. Kudu 用以每個 tablet 為一個單元來實現資料的 durability 。 Tablet 有多個副本,同時在多個節點上進行持久化。

        Kudu 有兩種型別的元件, Master Server 和 Tablet Server 。 Master 負責管理元資料。這些元資料包括 talbet 的基本資訊,位置資訊。 Master 還作為負載均衡伺服器,監聽 Tablet Server 的健康狀態。對於副本數過低的 Tablet , Master 會在起 replication 任務來提高其副本數。 Master 的所有資訊都在記憶體中 cache ,因此速度非常快。每次查詢都在百毫秒級別。 Kudu 支援多個 Master ,不過只有一個 active Master ,其餘只是作為災備,不提供服務。

        Tablet Server 上存了 10~100 個 Tablets ,每個 Tablet 有 3 (或 5 )個副本存放在不同的 Tablet Server 上,每個 Tablet 同時只有一個 leader 副本,這個副本對使用者提供修改操作,然後將修改結果同步給 follower 。 Follower 只提供讀服務,不提供修改服務。副本之間使用 raft 協議來實現 High Availability ,當 leader 所在的節點發生故障時, followers 會重新選舉 leader 。根據官方的資料,其 MTTR 約為 5 秒,對 client 端幾乎沒有影響。 Raft 協議的另一個作用是實現 Consistency 。 Client 對 leader 的修改操作,需要同步到 N/2+1 個節點上,該操作才算成功。

        Kudu 採用了類似 log-structured 儲存系統的方式,增刪改操作都放在記憶體中的 buffer ,然後才 merge 到持久化的列式儲存中。 Kudu 還是用了 WALs 來對記憶體中的 buffer 進行災備。

2. 列式儲存

        持久化的列式儲存儲存,與 HBase 完全不同,而是使用了類似 Parquet 的方式,同一個列在磁碟上是作為一個連續的塊進行存放的。例如,圖中左邊是 twitter 儲存推文的一張表,而圖中的右邊表示了表在磁碟中的的儲存方式,也就是將同一個列放在一起存放。這樣做的第一個好處是,對於一些聚合和 join 語句,我們可以儘可能地減少磁碟的訪問。例如,我們要使用者名稱為 newsycbot

的推文數量,使用查詢語句:

SELECT COUNT(*) FROM tweets WHERE user_name = ‘newsycbot’;

        我們只需要查詢 User_name 這個 block 即可。同一個列的資料是集中的,而且是相同格式的, Kudu 可以對資料進行編碼,例如字典編碼,行長編碼, bitshuffle 等。通過這種方式可以很大的減少資料在磁碟上的大小,提高吞吐率。除此之外,使用者可以選擇使用通用的壓縮格式對資料進行壓縮,如 LZ4, gzip, 或 bzip2 。這是可選的,使用者可以根據業務場景,在資料大小和 CPU 效率上進行權衡。這一部分的實現上, Kudu 很大部分借鑑了 Parquet 的程式碼。

        HBase 支援 snappy 儲存,然而因為它的 LSM 的資料儲存方式,使得它很難對資料進行特殊編碼,這也是 Kudu 聲稱具有很快的 scan 速度的一個很重要的原因。不過,因為列式編碼後的資料很難再進行修改,因此當這寫資料寫入磁碟後,是不可變的,這部分資料稱之為 base 資料。 Kudu 用 MVCC (多版本併發控制)來實現資料的刪改功能。更新、刪除操作需要記錄到特殊的資料結構裡,儲存在記憶體中的 DeltaMemStore 或磁碟上的 DeltaFIle 裡面。 DeltaMemStore 是 B-Tree 實現的,因此速度快,而且可修改。磁碟上的 DeltaFIle 是二進位制的列式的塊,和 base 資料一樣都是不可修改的。因此當資料頻繁刪改的時候,磁碟上會有大量的 DeltaFiles 檔案, Kudu 借鑑了 Hbase 的方式,會定期對這些檔案進行合併。

3. 對外介面

        Kudu 提供 C++ 和 JAVA API ,可以進行單條或批量的資料讀寫, schema 的建立修改。除此之外, Kudu 還將與 hadoop 生態圈的其它工具進行整合。目前, kudu beta 版本對 Impala 支援較為完善,支援用 Impala 進行建立表、刪改資料等大部分操作。 Kudu 還實現了 KuduTableInputFormat 和 KuduTableOutputFormat ,從而支援 Mapreduce 的讀寫操作。同時支援資料的 locality 。目前對 spark 的支援還不夠完善, spark 只能進行資料的讀操作。

使用案例——小米

小米是 Hbase 的重度使用者,他們每天有約 50 億條使用者記錄。小米目前使用的也是 HDFS + HBase 這樣的混合架構。可見該流水線相對比較複雜,其資料儲存分為 SequenceFile , Hbase 和 Parquet 。

在使用 Kudu 以後, Kudu 作為統一的資料倉庫,可以同時支援離線分析和實時互動分析。

效能測試

1. 和 parquet 的比較

        圖是官方給出的用 Impala 跑 TPC-H 的測試,對比 Parquet 和 Kudu 的計算速度。從圖中我們可以發現, Kudu 的速度和 parquet 的速度差距不大,甚至有些 Query 比 parquet 還快。然而,由於這些資料都是在記憶體快取過的,因此該測試結果不具備參考價值。

2. 和 Hbase 的比較

        圖是官方給出的另一組測試結果,從圖中我們可以看出,在 scan 和 range 查詢上, kudu 和 parquet 比 HBase 快很多,而 random access 則比 HBase 稍慢。然而資料集只有 60 億行資料,所以很可能這些資料也是可以全部快取在記憶體的。對於從記憶體查詢,除了 random access 比 HBase 慢之外, kudu 的速度基本要優於 HBase 。

3. 超大資料集的查詢效能

        Kudu 的定位不是 in-memory database 。因為它希望 HDFS/Parquet 這種儲存,因此大量的資料都是儲存在磁碟上。如果我們想要拿它代替 HDFS/Parquet + HBase ,那麼超大資料集的查詢效能就至關重要,這也是 Kudu 的最初目的。然而,官方沒有給出這方面的相關資料。由於條件限制,網易暫時未能完成該測試。下一步,我們將計劃搭建 10 臺 Kudu + Impala 伺服器,並用 tpc-ds 生成超大資料,來完成該對比測驗。