天天看點

KUDU - Cloudera開發的又一個Hadoop系存儲系統

作者:劉旭晖 Raymond 轉載請注明出處

  原文: http://blog.csdn.net/colorant/article/details/50803226?utm_source=tuicool&utm_medium=referral

  ## == 是什麼 ==

  Kudu 是 Todd Lipcon @ Cloudera 帶頭開發的存儲系統,其整體應用模式和HBase比較接近,即支援行級别的随機讀寫,并支援批量順序檢索功能。

  那既然有了HBase,為什麼還需要Kudu呢,簡單的說,就是嫌棄HBase在OLAP場合,SQL/MR類的批量檢索場景中,性能不夠好。通常這種海量資料OLAP場景,要不走預處理的路,比如像EBAY麒麟這樣走Cube管理的,或者像谷歌Mesa這樣按業務需求走預定義聚合操作。再有就是自己建構資料通道,串接實時和批量處理兩種系統,發揮各自的特長。

  但是OLAP是個複雜的問題,場景衆多,必然不可能有完美的通用解決方案,Kudu定位于應對快速變化資料的快速分析型資料倉庫,希望靠系統自身能力,支撐起同時需要高吞吐率的順序和随機讀寫的應用場景(可能的場景,比如時間序列資料分析,日志資料實時監控分析),提供一個介于 HDFS 和 HBase 的性能特點之間的一個系統,在随機讀寫和批量掃描之間找到一個平衡點,并保障穩定可預測的響應延遲

  那為什麼不能想辦法改進HBase呢?Todd自己做為HBase的重要貢獻者之一,沒有選擇這條路,自然是因為任何系統設計時都有Tradeoff,基于HBase的設計思想很難實作Kudu所定位的目标

  相關連結:

  http://getkudu.io/kudu.pdf

  http://getkudu.io/

  ## == 核心思想 ==

  ### 資料模型:

  資料模型定義上,K udu 管理的是類似關系型資料庫的結構化的表,表結構由類Sql的Schema進行定義,相比于HBase這樣的NoSql類型的資料庫,Kudu的行資料是由固定個數有明确類型定義的列組成,并且需要定義一個由一個或多個列組成的主鍵來對每行資料進行唯一索引,相比于傳統的關系型資料庫,kudu在索引上有更多的限制,比如暫時不支援二級索引,不支援主鍵的更新等等。

  盡管表結構類似于關系型資料庫,但是Kudu自身并不提供SQL類型的文法接口,而是由上層其他系統實作,比如目前通過Impala提供SQL文法支援。

  Kudu底層API,主要面對簡單的更新檢索操作,Insert/Update/Delete等必須指定一個主鍵進行,而Scan檢索類型的操作則支援條件過濾和投影等能力。

  ### 叢集架構:

  Kudu 的叢集架構基本和HBase類似,采用主從結構,Master節點管理中繼資料,Tablet節點負責分片管理資料,

  和HBase不同的是,Kudu沒有借助于HDFS存儲實際資料,而是自己直接在本地磁盤上管理分片資料,包括資料的Replication機制,kudu的Tablet server 直接管理Master分片和Slave分片,自己通過raft協定解決一緻性問題等,多個Slave可以同時提供資料讀取服務,相對于HBase依托HDFS進行Region資料的管理方式,自主性會強一些,不過比如Tablet節點崩潰,資料的遷移拷貝工作等,也需要Kudu自己完成。

  ### 存儲結構:

  因為資料是有嚴格Schema類型定義,是以Kudu底層可以使用列式存儲的方案來提高存儲和投影檢索效率(不過,設計kudu時,因果關系我估計是倒過來的,先決定要使用列式存儲,再決定需要schema)

  和HBase一樣,Kudu也是通過Tablet的分區來支援水準擴充,與HBase不同的是,Kudu的分區政策除了支援按照Key Range 來分區以外,還支援Hash based 的政策,實際上,在主鍵上,Kudu可以混合使用這兩種不同的政策

  Hash分區的政策在一些場合下可以更好的做到負載均衡,避免資料傾斜,但是它最大的問題就是分區數一旦确定就很難再調整,是以目前Kudu的分區數必須預先指定(對Range的分區政策也有這個要求,估計是先簡單化統一處理),不支援動态分區分裂,合并等,是以表的分區一開始就需要根據負載和容量預先進行合理規劃。

  在處理随機寫的效率問題方面,Kudu的基本流程和HBase的方案差不多,在記憶體中對每個Tablet分區維護一個MemRowSet來管理最新更新的資料,當尺寸超過一定大小後Flush到磁盤上形成DiskRowSet,多個DiskRowSet在适當的時候進行歸并處理

  和HBase采用的LSM(Log Structured Merge )方案不同的是,Kudu對同一行的資料更新記錄的合并工作,不是在查詢的時候發生的(HBase會将多條更新記錄先後Flush到不同的Storefile中,是以讀取時需要掃描多個檔案,比較rowkey,比較版本等),而是在更新的時候進行,在Kudu中一行資料隻會存在于一個DiskRowSet中,避免讀操作時的比較合并工作。那Kudu是怎麼做到的呢? 對于列式存儲的資料檔案,要原地變更一行資料是很困難的,是以在Kudu中,對于Flush到磁盤上的DiskRowSet(DRS)資料,實際上是分兩種形式存在的,一種是Base的資料,按列式存儲格式存在,一旦生成,就不再修改,另一種是Delta檔案,存儲Base資料中有變更的資料,一個Base檔案可以對應多個Delta檔案,這種方式意味着,插入資料時相比HBase,需要額外走一次檢索流程來判定對應主鍵的資料是否已經存在。是以,Kudu是犧牲了寫性能來換取讀取性能的提升。

KUDU - Cloudera開發的又一個Hadoop系存儲系統

  既然存在Delta資料,也就意味着資料查詢時需要同時檢索Base檔案和Delta檔案,這看起來和HBase的方案似乎又走到一起去了,不同的地方在于,Kudu的Delta檔案與Base檔案不同,不是按Key排序的,而是按被更新的行在Base檔案中的位移來檢索的,号稱這樣做,在定位Delta内容的時候,不需要進行字元串比較工作,是以能大大加快定位速度。但是無論如何,Delta檔案的存在對檢索速度的影響巨大。是以Delta檔案的數量會需要控制,需要及時的和Base資料進行合并。由于Base檔案是列式存儲的,是以Delta檔案合并時,可以有選擇性的進行,比如隻把變化頻繁的列進行合并,變化很少的列保留在Delta檔案中暫不合并,這樣做也能減少不必要的IO開銷。

  除了Delta檔案合并,DRS自身也會需要合并,為了保障檢索延遲的可預測性(這一點是HBase的痛點之一,比如分區發生Major Compaction 時,讀寫性能會受到很大影響),Kudu的compaction政策和HBase相比,有很大不同,kudu的DRS資料檔案的compaction,本質上不是為了減少檔案數量,實際上Kudu DRS 預設是以 32 MB 為機關進行拆分的,DRS的compaction并不減少檔案數量,而是對内容進行排序重組,減少不同DRS之間key的overlap,進而在檢索的時候減少需要參與檢索的DRS的數量。

KUDU - Cloudera開發的又一個Hadoop系存儲系統

  以 32 MB 這樣小的機關進行拆分,也是為了能夠以有限的資源快速的完成compaction的任務,及時根據系統負載調整Compaction行為,而不至于像HBase一樣,Major Co mpaction動作成為導緻性能不穩定的一個重要因素。是以對于Kudu來說,IO操作可以是一個持續平緩的過程,這點對響應的可預測性至關重要。

  ### 其它

  Kudu 底層核心代碼使用 C++ 開發,對外提供Java API 接口,沒有使用Java開發核心代碼,也許有部分原因是希望通過自己管理記憶體,更好的适應和利用目前伺服器上普遍越來越大的記憶體空間( 256 G +),另外也便于在關鍵邏輯中更好的優化代碼。

  ## == 小結 ==

  總體來說,個人感覺,Kudu本質上是将性能的優化,寄托在以列式存儲為核心的基礎上,希望通過提高存儲效率,加快字段投影過濾效率,降低查詢時CPU開銷等來提升性能。而其他絕大多數設計,都是為了解決在列式存儲的基礎上支援随機讀寫這樣一個目的而存在的。比如類Sql的中繼資料結構,是提高列式存儲效率的一個輔助手段,唯一主鍵的設定也是配合列式存儲引入的定制政策,至于其他如Delta存儲,compaction政策等都是在這個設定下為了支援随機讀寫,降低latency不确定性等引入的一些Tradeoff方案

  官方測試結果上,如果是存粹的随機讀寫,或者單行的檢索請求這類場景,由于這些Tradeoff的存在,HBASE的性能吞吐率是要優于Kudu不少的( 2 倍到 4 倍),kudu的優勢還是在支援類SQL檢索這樣經常需要進行投影操作的批量順序檢索分析場合。

  目前kudu還處在Incubator階段,并且還沒有成熟的線上應用(小米走在了前面,做了一些業務應用的嘗試),在資料安全,備份,系統健壯性等方面也還要打個問号,是以是否使用kudu,什麼場合,什麼時間點使用,是個需要好好考量的問題 ;)