大數據技術棧速覽之:KUDU

Kudu是什麼?有什麼特性?它和Hadoop生態的關係是什麼?有了HDFS和HBase,爲什麼還要用kudu?

目錄

 

Kudu產生的背景

Kudu是什麼

kudu的使用場景

Kudu設計優勢

kudu使用時的優勢

kudu使用時的劣勢

kudu基本原理

表與schema

kudu的底層數據模型

Tablet的發現過程

kudu的寫流程

kudu的讀流程

 kudu的更新流程

Kudu在使用過程中的各種限制 

有了HBase爲什麼還要Kudu?

使用注意點(踩坑記錄)

如何入門和實戰


Kudu產生的背景

在KUDU之前,大數據主要以兩種方式存儲;

(1)靜態數據:

以 HDFS 引擎作爲存儲引擎,適用於高吞吐量的離線大數據分析場景。這類存儲的侷限性是數據無法進行隨機的讀寫。

(2)動態數據:

以 HBase、Cassandra 作爲存儲引擎,適用於大數據隨機讀寫場景。這類存儲的侷限性是批量讀取吞吐量遠不如 HDFS,不適用於批量數據分析的場景。

這兩種數據在存儲方式上完全不同,導致使用場景完全不同。在真實的場景中,面對既需要隨機讀寫,又需要批量分析的大數據場景,該如何選擇呢?顯然單種存儲引擎無法滿足業務需求,我們需要通過多種大數據工具組合來滿足這一需求。

例如,Online Report採用HDFS/Parquet on Impala的架構,數據每隔一小時通過MapReduce從生產db增量同步到HDFS,再通過HIVE/MAPREDUCE增量MERGE到數倉中,最終通過IMPALA查詢在報表展示。類似這樣:

如圖所示,數據實時寫入 HBase,實時的數據更新也在 HBase 完成,爲了應對 OLAP 需求,我們定時(通常是 T+1 或者 T+H)將 HBase 數據寫成靜態的文件(如:Parquet)導入到 OLAP 引擎(如:HDFS)。這一架構能滿足既需要隨機讀寫,又可以支持 OLAP 分析的場景,但他有如下缺點:

(1)架構複雜。從架構上看,數據在HBase、消息隊列、HDFS 間流轉,涉及環節太多,運維成本很高。並且每個環節需要保證高可用,都需要維護多個副本,存儲空間也有一定的浪費。最後數據在多個系統上,對數據安全策略、監控等都提出了挑戰。

(2)時效性低。數據從HBase導出成靜態文件是週期性的,一般這個週期是一天(或一小時),在時效性上不是很高。

(3)難以應對後續的更新。真實場景中,總會有數據是延遲到達的。如果這些數據之前已經從HBase導出到HDFS,新到的變更數據就難以處理了,一個方案是把原有數據應用上新的變更後重寫一遍,但這代價又很高。

這種架構可以支持超大數據集的查詢和分析,但是數據更新執行過程很久,效率較差。而Apache Kudu結合了Hbase和HDFS的優勢,可以同時提供高效的隨機訪問以及數據掃描能力,支持數據的實時插入和分析,爲Online Report提供了另外一種選擇。

Kudu是什麼

KUDU的定位是Fast Analytics on Fast Data,把analytics 和 online兩個應用場景進行了整合,是一個既支持隨機讀寫、又支持 OLAP 分析的大數據存儲引擎。

Kudu---This new open source complement to HDFS and Apache HBase is designed to fill gaps in Hadoop’s storage layer that have given rise to stitched-together, hybrid architectures.

(一個彌補HDFS和HBase之間的缺口的新型的存儲,它能夠更有效的利用現代硬件的CPU和IO資源,既能夠支持分析,又能夠支持更新、刪除和實時查詢。)

可以看出,KUDU 是一個折中的產品,在 HDFS 和 HBase 這兩個偏科生中平衡了隨機讀寫和批量分析的性能。

Kudu集HDFS的順序讀和HBASE的隨機讀於一身,同時具備高性能的隨機寫,以及很強大的可用性(單行事務,一致性協議),支持Impala spark計算引擎。是一個融合HDFS和HBase的功能的新組件,具備介於兩者之間的新存儲組件。可以同時提供低延遲的隨機讀寫和高效的數據分析能力,支持水平擴展,高可用,與Cloudera Impala和Apache Spark等當前流行的大數據查詢和分析工具結合緊密。

 

kudu的使用場景

官方表述:

  • Strong performance for both scan and random access to help customers simplify complex hybrid architectures(適用於那些既有隨機訪問,也有批量數據掃描的複合場景)
  • High CPU efficiency in order to maximize the return on investment that our customers are making in modern processors(高計算量的場景)
  • High IO efficiency in order to leverage modern persistent storage(使用了高性能的存儲設備,包括使用更多的內存)
  • The ability to update data in place, to avoid extraneous processing and data movement(支持數據更新,避免數據反覆遷移)
  • The ability to support active-active replicated clusters that span multiple data centers in geographically distant locations(支持跨地域的實時數據備份和查詢)

  更貼近業務的適用場景解讀:

  • Streaming Input with Near Real Time Availability(具有近實時可用性的流輸入)

       剛剛到達的數據就馬上要被終端用戶使用訪問到。

       數據分析中的一個共同挑戰就是新數據快速而不斷地到達,同樣的數據需要靠近實時的讀取,掃描和更新。Kudu 通過高效的列式掃描提供了快速插入和更新的強大組合,從而在單個存儲層上實現了實時分析用例。

  • Time-series application with widely varying access patterns(具有廣泛變化的訪問模式的時間序列應用)

              需要同時支持:

    根據海量歷史數據查詢。
    必須非常快地返回關於單個實體的細粒度查詢。

              time-series(時間序列)模式是根據其發生時間組織和鍵入數據點的模式。這可以用於隨着時間的推移調查指標的性能,或者根據過去的數據嘗試預測未來的行爲。例如,時間序列的客戶數據可以用於存儲購買點擊流歷史並預測未來的購買,或由客戶支持代表使用。雖然這些不同類型的分析正在發生,插入和更換也可能單獨和批量地發生,並且立即可用於讀取工作負載。Kudu 可以用 scalable (可擴展)和 efficient (高效的)方式同時處理所有這些訪問模式。由於一些原因,Kudu 非常適合時間序列的工作負載。隨着 Kudu 對基於 hash 的分區的支持,結合其對複合 row keys(行鍵)的本地支持,將許多服務器上的表設置成很簡單,而不會在使用範圍分區時通常觀察到“hotspotting(熱點)”的風險。Kudu 的列式存儲引擎在這種情況下也是有益的,因爲許多時間序列工作負載只讀取了幾列,而不是整行。 過去,您可能需要使用多個數據存儲來處理不同的數據訪問模式。這種做法增加了應用程序和操作的複雜性,並重復了數據,使所需存儲量增加了一倍(或更糟)。Kudu 可以本地和高效地處理所有這些訪問模式,而無需將工作卸載到其他數據存儲。

  • Predictive Modeling(預測建模)

支持根據所有歷史數據週期地更新模型。

數據科學家經常從大量數據中開發預測學習模型。模型和數據可能需要在學習發生時或隨着建模情況的變化而經常更新或修改。此外,科學家可能想改變模型中的一個或多個因素,看看隨着時間的推移會發生什麼。在 HDFS 中更新存儲在文件中的大量數據是資源密集型的,因爲每個文件需要被完全重寫。在 Kudu,更新發生在近乎實時。科學家可以調整值,重新運行查詢,並以秒或分鐘而不是幾小時或幾天刷新圖形。此外,批處理或增量算法可以隨時在數據上運行,具有接近實時的結果。

  • Combining Data In Kudu With Legacy Systems(結合 Kudu 與遺留系統的數據)

  公司從多個來源生成數據並將其存儲在各種系統和格式中。例如,您的一些數據可能存儲在 Kudu,一些在傳統的 RDBMS 中,一些在 HDFS 中的文件中。您可以使用 Impala 訪問和查詢所有這些源和格式,而無需更改舊版系統。

  有關這些和其他方案的更多信息,請參閱 Example Use Cases。

      國內使用的kudu一些案例可以查看《構建近實時分析系統.pdf》文檔。

 

Kudu設計優勢

  • OLAP工作流的快速處理

    能夠快速更新/獲取新數據,並進行在線查詢分析

  • 列式存儲結構
  • 集成Hadoop生態組件

    Spark/Flume/MapReduce/Impala等

  • 服務的高可用性

    TabletServer以及Master都使用*Raft*一致性算法。該算法確保只要可用副本數爲總數的一半以上,Tablet就可以進行讀寫操作。即使在leader發生故障的情況下,follower也可以爲程序提供只讀服務。

  • 結構化數據模型

    類關係型數據庫,強字段類型,主鍵索引,表分區設計

  • NOSQL APIs

    支持 C++, Java and Python (INSERT/UPDATE/SCAN/DELETE等)

kudu使用時的優勢

1)一個table由多個tablet組成,對分區查看、擴容和數據高可用支持非常好
2)支持update和upsert操作。
3)與imapla集成或spark集成後(dataframe)可通過標準的sql操作,使用起來很方便
4)可與spark系統集成

kudu使用時的劣勢

1)只有主鍵可以設置range分區,且只能由一個主鍵,也就是一個表只能有一個字段range分區,且該字段必須是主鍵。
2)如果是pyspark連接kudu,則不能對kudu進行額外的操作;而scala的spark可以調用kudu本身的庫,支持kudu的各種語法。
3)kudu的shell客戶端不提供表schema查看。如果你不通過imapla連接kudu,且想要查看錶的元數據信息,需要用spark加載數據爲dataframe,通過查看dataframe的schema查看錶的元數據信息。
3)kudu的shell客戶端不提供表內容查看。如果你想要表的據信息,要麼自己寫腳本,要麼通過spark、imapla查看。
4)如果使用range 分區需要手動添加分區。假設id爲分區字段,需要手動設置第一個分區爲1-30.第二個分區爲30-60等等
5)時間格式是utc類型,需要將時間戳轉化爲utc類型,注意8個小時時差。

 

kudu基本原理

表與schema

Kudu設計是面向結構化存儲的,因此,Kudu的表需要用戶在建表時定義它的Schema信息,這些Schema信息包含:列定義(含類型),Primary Key定義(用戶指定的若干個列的有序組合)。數據的唯一性,依賴於用戶所提供的Primary Key中的Column組合的值的唯一性。 Kudu提供了Alter命令來增刪列,但位於Primary Key中的列是不允許刪除的。 Kudu當前並不支持二級索引。 從用戶角度來看,Kudu是一種存儲結構化數據表的存儲系統。在一個Kudu集羣中可以定義任意數量的table,每個table都需要預先定義好schema。每個table的列數是確定的,每一列都需要有名字和類型,每個表中可以把其中一列或多列定義爲主鍵。這麼看來,Kudu更像關係型數據庫,而不是像HBase、Cassandra和MongoDB這些NoSQL數據庫。不過Kudu目前還不能像關係型數據一樣支持二級索引。

Kudu使用確定的列類型,而不是類似於NoSQL的"everything is byte"。這可以帶來兩點好處: 確定的列類型使Kudu可以進行類型特有的編碼。 可以提供 SQL-like 元數據給其他上層查詢工具,比如BI工具。

kudu的底層數據模型

Kudu的底層數據文件的存儲,未採用HDFS這樣的較高抽象層次的分佈式文件系統,而是自行開發了一套可基於

Table/Tablet/Replica視圖級別的底層存儲系統。

這套實現基於如下的幾個設計目標:

• 可提供快速的列式查詢

• 可支持快速的隨機更新

• 可提供更爲穩定的查詢性能保障

一張表會分成若干個tablet,每個tablet包括MetaData元信息及若干個RowSet,RowSet包含一個MemRowSet及若干個DiskRowSet,DiskRowSet中包含一個BloomFile、Ad_hoc Index、BaseData、DeltaMem及若干個RedoFile和UndoFile(UndoFile一般情況下只有一個)。

MemRowSet:用於新數據insert及已在MemRowSet中的數據的更新,一個MemRowSet寫滿後會將數據刷到磁盤形成若干個DiskRowSet。每次到達32M生成一個DiskRowSet。

DiskRowSet:用於老數據的變更(mutation),後臺定期對DiskRowSet做compaction,以刪除沒用的數據及合併歷史數據,減少查詢過程中的IO開銷。

BloomFile:根據一個DiskRowSet中的key生成一個bloom filter,用於快速模糊定位某個key是否在DiskRowSet中存在。

Ad_hocIndex:是主鍵的索引,用於定位key在DiskRowSet中的具體哪個偏移位置。

BaseData是MemRowSet flush下來的數據,按列存儲,按主鍵有序。

UndoFile是基於BaseData之前時間的歷史數據,通過在BaseData上apply UndoFile中的記錄,可以獲得歷史數據。

RedoFile是基於BaseData之後時間的變更(mutation)記錄,通過在BaseData上apply RedoFile中的記錄,可獲得較新的數據。

DeltaMem用於DiskRowSet中數據的變更mutation,先寫到內存中,寫滿後flush到磁盤形成RedoFile。

 

MemRowSets可以對比理解成HBase中的MemStore, 而DiskRowSets可理解成HBase中的HFile。MemRowSets中的數據按照行試圖進行存儲,數據結構爲B-Tree。

MemRowSets中的數據被Flush到磁盤之後,形成DiskRowSets。

DisRowSets中的數據,按照32MB大小爲單位,按序劃分爲一個個的DiskRowSet。 DiskRowSet中的數據按照Column進行組織,與Parquet類似。

這是Kudu可支持一些分析性查詢的基礎。每一個Column的數據被存儲在一個相鄰的數據區域,而這個數據區域進一步被細分成一個個的小的Page單元,與HBase File中的Block類似,對每一個Column Page可採用一些Encoding算法,以及一些通用的Compression算法。 既然可對Column Page可採用Encoding以及Compression算法,那麼,對單條記錄的更改就會比較困難了。

前面提到了Kudu可支持單條記錄級別的更新/刪除,是如何做到的?

   

與HBase類似,也是通過增加一條新的記錄來描述這次更新/刪除操作的。DiskRowSet是不可修改了,那麼 KUDU 要如何應對數據的更新呢?在KUDU中,把DiskRowSet分爲了兩部分:base data、delta stores。base data 負責存儲基礎數據,delta stores負責存儲 base data 中的變更數據.

如上圖所示,數據從 MemRowSet 刷到磁盤後就形成了一份 DiskRowSet(只包含 base data),每份 DiskRowSet 在內存中都會有一個對應的DeltaMemStore,負責記錄此 DiskRowSet 後續的數據變更(更新、刪除)。DeltaMemStore 內部維護一個 B-樹索引,映射到每個 row_offset 對應的數據變更。DeltaMemStore 數據增長到一定程度後轉化成二進制文件存儲到磁盤,形成一個 DeltaFile,隨着 base data 對應數據的不斷變更,DeltaFile 逐漸增長。

Tablet的發現過程

當創建Kudu客戶端時,其會從主服務器上獲取tablet位置信息,然後直接與服務於該tablet的服務器進行交談。

爲了優化讀取和寫入路徑,客戶端將保留該信息的本地緩存,以防止他們在每個請求時需要查詢主機的tablet位置信息。

隨着時間的推移,客戶端的緩存可能會變得過時,並且當寫入被髮送到不再是tablet領導者的tablet服務器時,則將被拒絕。然後客戶端將通過查詢主服務器發現新領導者的位置來更新其緩存。

kudu的寫流程

如上圖,當 Client 請求寫數據時,先根據主鍵從Master Server中獲取要訪問的目標 Tablets,然後到依次對應的Tablet獲取數據。

因爲KUDU表存在主鍵約束,所以需要進行主鍵是否已經存在的判斷,這裏就涉及到之前說的索引結構對讀寫的優化了。一個Tablet中存在很多個RowSets,爲了提升性能,我們要儘可能地減少要掃描的RowSets數量。

首先,我們先通過每個 RowSet 中記錄的主鍵的(最大最小)範圍,過濾掉一批不存在目標主鍵的RowSets,然後在根據RowSet中的布隆過濾器,過濾掉確定不存在目標主鍵的 RowSets,最後再通過RowSets中的 B-樹索引,精確定位目標主鍵是否存在。

如果主鍵已經存在,則報錯(主鍵重複),否則就進行寫數據(寫 MemRowSet)。

kudu的讀流程

如上圖,數據讀取過程大致如下:先根據要掃描數據的主鍵範圍,定位到目標的Tablets,然後讀取Tablets 中的RowSets。

在讀取每個RowSet時,先根據主鍵過濾要scan範圍,然後加載範圍內的base data,再找到對應的delta stores,應用所有變更,最後union上MemRowSet中的內容,返回數據給Client。

 kudu的更新流程

數據更新的核心是定位到待更新數據的位置,這塊與寫入的時候類似,就不展開了,等定位到具體位置後,然後將變更寫到對應的delta store 中。


 

Kudu在使用過程中的各種限制 

主鍵

  • 表創建後,主鍵不能修改。必須刪除重建表指定新的主鍵。
  • 主鍵列必須在非主鍵列之前
  • 主鍵列的值不能使用UPDATE函數修改。如果要修改主鍵的值只能刪除該行重新插入。
  • DOUBLE、FLOAT或BOOL類型的列不能作爲主鍵,此外,主鍵列必須爲NOT NULL。
  • 不支持自動生成的主鍵(如自增列)
  • 組合主鍵的所有列在編碼後,大小不能大於16K

  • 不支持CHAR、VARCHAR、DATE和數組等複雜類型。
  • 不能通過ALTER TABLE更改現有列的類型和是否可爲空屬性
  • DECIMAL類型列的精度和規模不能通過ALTER TABLE進行修改(Kudu 1.7+才支持decimal類型)
  • 表最多可以有300列。

  • 表的副本數必須爲奇數,最多爲7。
  • 副本數在建表時指定,之後無法更改。

單元格

  • 單個單元格的值在編碼或壓縮前不能大於64KB。

其他使用限制

  • kudu主要是爲分析用例設計的,如果單行中包含多個千字節的單元格,則可能會遇到問題。
  • 不支持二級索引。
  • 不支持多行事務。
  • 不支持外鍵等關係特性。
  • 表名和列名必須爲有效的UTF-8字符串,最大長度爲256個字符。
  • 刪除列並不會立即釋放空間,compaction運行後纔會釋放。
  • 無法手動執行compaction,但是刪表會立即釋放空間。

分區限制

  • 表必須使用簡單或複合主鍵手動分區。目前不支持自動分區。
  • Range 分區可以在建表後添加或刪除。
  • 表中已有的數據無法重新自動分區。有一種解決方案,創建一個新表並制定新的分區,然後將舊錶的數據插入新表。
  • 失去大部分副本的tablet(比如三個副本中的一個)需要人工干預才能恢復。

集羣管理

  • 不支持機架感知。
  • 不支持多數據中心。
  • 不支持滾動重啓。

 

服務器管理

  • 生產部署時應該爲tablet server分配至少4G內存,在接近數據和tablet的限制時,最好配置大於16G的內存。
  • 預寫日誌(WAL)只能存儲在磁盤上。
  • 磁盤故障是無法容忍的,一旦檢測到磁盤故障,tablet server就會崩潰。
  • 無法恢復數據的磁盤需要格式化該tablet server的所有Kudu數據,然後才能重新啓動。
  • 無法添加或刪除數據目錄,必須對所有目錄進行重新格式化以更改目錄集。
  • Tablet servers不能優雅地退役。
  • 不能更改tablet servers的地址和端口。
  • Kudu對時鐘同步有嚴格的要求,一旦時鐘不同步,Kudu的master和tablet server就會崩潰。
  • Kudu發行版只在NTP中進行過測試,其他時鐘同步程序不保證能正常工作。

 

規模

  • 建議tablet server最多爲100臺。
  • 建議master最多爲3個。
  • 建議的最大數據存儲量爲,複製和壓縮後,每個tablet server 8TB。
  • 建議每個tablet server管理的tablet爲2000,包含tablet的副本。
  • 在創建表時,每個Tablet server的每個表的最大tablet數爲60。
    基於以上限制,可以推測出一下內容:
    Kudu中存儲的總數據量建議爲:tablet server總數
    單個tablet server的數據量=100*8TB=800TB,即Kudu不適用於存儲PB級數據。
    單個tablet的數據量建議爲:單個tablet server的數據量/每個tablet server中tablet的總數=8TB/2000=4G。Kudu支持的壓縮方式有LZ4, Snappy,或zlib。鑑於各種壓縮算法的壓縮比一般不超過50%,則每個tablet中的數據量在壓縮前的大小建議應小於2G。

複製和備份

  • kudu目前沒有任何內置備份和恢復功能。建議用戶在必要的時候使用spark或impala等工具導入或導出表。

 

其他已知的問題

  • 如果Kudu master配置了-log_force_fsync_all選項、 tablet servers和客戶端將經常超時,集羣可能變得不可用。
  • 如果一個tablet server 有大量的tablet,啓動可能需要幾分鐘。建議將每臺服務器的tablet數量限制在100或更少。在預拆分表時,請考慮這個限制。如果您注意到啓動時間較慢,您可以在web UI中監視每個服務器的tablet數量。
  • Kerberos身份驗證在主機名中包含大寫字母的主機上不能正常運行。
  • 如果在krb5.conf中配置rdns = false,Kerberos身份驗證將不能正常工作。

有了HBase爲什麼還要Kudu?Kudu與HBase的簡要分析與對比

有了HBase爲什麼還要Kudu

kudu和Hbase類似也是一個分佈式數據庫,據官方給它的定位是提供”fast analytics on fast data”(在更新更及時的數據上做更快的分析),希望支撐起同時需要高吞吐率的順序和隨機讀寫的應用場景(可能的場景,比如時間序列數據分析,日誌數據實時監控分析),提供一個介於HDFS和HBase的性能特點之間的一個系統,在隨機讀寫和批量掃描之間找到一個平衡點,並保障穩定可預測的響應延遲。

 Kudu的數據模型和磁盤存儲都與Hbase不同。

0.作爲Hadoop生態圈的一部分,對接生態系統的其他組件方便,會有官方提供的接口

1.kudu自己存儲數據不依賴與HDFS存儲;不依賴於zookeeper,將它的功能集成進了自身的TMaster;

2.和HBase類似的LSM結構,用於支持數據的隨機讀寫。

3.有表結構,需定義Schema信息

- 必須定義唯一鍵,這就造成了寫數據時多了一個判斷唯一的過程。

需在寫入數據前定義好每一列的類型(方便做類似於parquet的列式存儲)

可以像關係型數據庫一樣用Alter增刪列,不具有HBase動態列的特性

4.支持行級別的ACID

5.目前不支持二級索引

6.目前不支持BloomFilter優化join

7.核心模塊用的C++來實現,沒有full gc的風險

kudu解決了什麼問題?

HDFS和HBase是大數據最常用的兩種存儲方式,它們的優缺點非常明顯:

HDFS,使用列式存儲格式Apache Parquet,Apache ORC,適合離線分析,不支持單條記錄級別的update操作,隨機讀寫性能差。這個就不多說了,用過HDFS的同學應該都知道這個特點。

HBase,可以進行高效隨機讀寫,卻並不適用於基於SQL的數據分析方向,大批量數據獲取時的性能較差

那爲什麼HBase不適合做分析呢?

因爲分析需要批量獲取數據,而HBase本身的設計並不適合批量獲取數據

1)都說HBase是列式數據庫,其實從底層存儲的角度來說它並不是列式的,獲取指定列數據時是會讀到其他列數據的。相對而言Parquet格式針對分析場景就做了很多優化。

2)HBase是LSM-Tree架構的數據庫。LSM 的中心思想就是將隨機寫轉換爲順序寫來大幅提高寫入操作的性能,但是犧牲了部分讀的性能。這導致了HBase讀取數據路徑比較長,從內存到磁盤,可能還需要讀多個HFile文件做版本合併。

隨機讀寫是指對任意一個位置的讀和寫,磁盤隨機讀寫慢是因爲需要尋道,倒帶纔可以訪問到指定存儲點,而內存不需要,可以任意指定存儲點。

爲了讓數據平臺同時具備隨機讀寫和批量分析能力,傳統的做法是採用混合架構(hybrid architecture),也就是我們常說的T+1的方式,數據實時更新在HBase,第二天凌晨同步到HDFS做離線分析。這樣的缺點很明顯,時效性差,數據鏈路長,過程複雜,開發成本高。

Kudu不及HDFS批處理快,也不及HBase隨機讀寫能力強,但是反過來它比HBase批處理快(適用於OLAP的分析場景),而且比HDFS隨機讀寫能力強(適用於實時寫入或者更新的場景),這就是它能解決的問題。

Kudu與HBase的簡要分析與對比

轉自:https://www.cnblogs.com/163yun/p/9646008.html

Hadoop生態圈中的技術繁多,HDFS作爲底層數據存儲的地位一直很牢固。而HBase作爲Google BigTable的開源產品,一直也是Hadoop生態圈中的核心組件,其數據存儲的底層採用了HDFS,主要解決的是在超大數據集場景下的隨機讀寫和更新的問題。Kudu的設計有參考HBase的結構,也能夠實現HBase擅長的快速的隨機讀寫、更新功能。那麼同爲分佈式存儲系統,HBase和Kudu二者有何差異?兩者的定位是否相同?我們通過分析HBase與Kudu整體結構和存儲結構等方面對兩者的差異進行比較。

HBase的整體結構

HBase的主要組件包括Master,zookeeper服務,RegionServer,HDFS。

Master:用來管理與監控所有的HRegionServer,也是管理HBase元數據的模塊。

zookeeper:作爲分佈式協調服務,用於保存meta表的位置,master的位置,存儲RS當前的工作狀態。

RegionServer:負責維護Master分配的region,region對應着表中一段區間內的內容,直接接受客戶端傳來的讀寫請求。

HDFS:負責最終將寫入的數據持久化,並通過多副本複製實現數據的高可靠性。

Kudu的整體結構

Kudu集羣中存在兩種主要組件:

(1)TServer,負責管理Tablet,tablet是負責一張表中某塊內容的讀寫,接收其他TServer中leader tablet傳來的同步信息。

(2)Master,集羣中的管理節點,用於管理tablet的基本信息,表的信息,並監聽TServer的狀態。多個Master之間通過Raft協議實現數據同步和高可用。

主要區別  

Kudu結構看上去跟HBase差別並不大,主要的區別包括:

1、Kudu將HBase中zookeeper的功能放進了Master內,Kudu中Master的功能比HBase中的Master任務要多一些。

2、Hbase將數據持久化這部分的功能交給了Hadoop中的HDFS,最終組織的數據存儲在HDFS上。Kudu自己將存儲模塊集成在自己的結構中,內部的數據存儲模塊通過Raft協議來保證leader Tablet和replica Tablet內數據的強一致性,和數據的高可靠性。爲什麼不像HBase一樣,利用HDFS來實現數據存儲,猜測可能是因爲HDFS讀小文件時的時延太大,所以Kudu自己重新完成了底層的數據存儲模塊,並將其集成在TServer中。

數據存儲方式  

HBase  

HBase是一款Nosql數據庫,典型的KV系統,沒有固定的schema模式,建表時只需指定一個或多個列族名即可,一個列族下面可以增加任意個列限定名。一個列限定名代表了實際中的一列,HBase將同一個列族下面的所有列存儲在一起,所以HBase是一種面向列族式的數據庫。  

HBase將每個列族中的數據分別存儲,一個列族中的每行數據中,將rowkey、列族名、列名、timestamp組成最終存取的key值,另外爲了支持修改,刪除,增加了一個表徵該行數據是否刪除的標記。在同一個列族中的所有數據,按照rowkey:columnfamily:columnQulifier:timestamp組成的key值大小進行升序排列,其中rowkey、columnfamily、columnQulifier採用的是字典順序,其值越大,key越大,而timestamp是值越大,key越小。HBase通過按照列族分開存儲,相對於行式存儲能夠實現更高的壓縮比,這也是其比較重要的一個特性。

 HBase對一行數據進行更新時,HBase也是相當於插入一行新數據,在讀數據時HBase按照timestamp的大小得到經過更新過的最新數據。

Kudu

Kudu是一種完全的列式存儲引擎,表中的每一列數據都是存放在一起,列與列之間都是分開的。

爲了能夠保存一部分歷史數據,並實現MVCC,Kudu將數據分爲三個部分。一個部分叫做base data,是當前的數據;第二個部分叫做UNDO records,存儲的是從插入數據時到形成base data所進行的所有修改操作,修改操作以一定形式進行組織,實現快速查看歷史數據;第三個部分是REDO records,存儲的是還未merge到當前數據中的更新操作。下圖中表示的是在Kudu中插入一條數據、更新數據兩個操作的做法,當然做法不唯一,不唯一的原因是Kudu可以選擇先不將更新操作合併到base data中。

差異分析

(1)HBase是面向列族式的存儲,每個列族都是分別存放的,HBase表設計時,很少使用設計多個列族,大多情況下是一個列族。這個時候的HBase的存儲結構已經與行式存儲無太大差別了。而Kudu,實現的是一個真正的面向列的存儲方式,表中的每一列都是單獨存放的;所以HBase與Kudu的差異主要在於類似於行式存儲的列族式存儲方式與典型的面向列式的存儲方式的差異。

(2)HBase是一款NoSQL類型的數據庫,對錶的設計主要在於rowkey與列族的設計,列的類型可以不指定,因爲HBase在實際存儲中都會將所有的value字段轉換成二進制的字節流。因爲不需要指定類型,所以在插入數據的時候可以任意指定列名(列限定名),這樣相當於可以在建表之後動態改變表的結構。Kudu因爲選擇了列式存儲,爲了更好的提高列式存儲的效果,Kudu要求在建表時指定每一列的類型,這樣的做法是爲了根據每一列的類型設置合適的編碼方式,實現更高的數據壓縮比,進而降低數據讀入時的IO壓力。

(3)HBase對每一個cell數據中加入了timestamp字段,這樣能夠實現記錄同一rowkey和列名的多版本數據,另外HBase將數據更新操作、刪除操作也是作爲一條數據寫入,通過timestamp來標記更新時間,type來區分數據是插入、更新還是刪除。HBase寫入或者更新數據時可以指定timestamp,這樣的設置可以完成某些特定的操作。

Kudu也在數據存儲中加入了timestamp這個字段,不像HBase可以直接在插入或者更新數據時設置特殊的timestamp值,Kudu的做法是由Kudu內部來控制timestamp的寫入。不過Kudu允許在scan的時候設置timestamp參數,使得客戶端可以scan到歷史數據。

(4)相對於HBase允許多版本的數據存在,Kudu爲了提高批量讀取數據時的效率,要求設計表時提供一列或者多列組成一個主鍵,主鍵唯一,不允許多個相同主鍵的數據存在。這樣的設置下,Kudu不能像HBase一樣將更新操作直接轉換成插入一條新版本的數據,Kudu的選擇是將寫入的數據,更新操作分開存儲。

(5)當然還有一些其他的行式存儲與列式存儲之間在不同應用場景下的性能差異。

寫入和讀取過程

一、HBase 

HBase作爲一種非常典型的LSM結構的分佈式存儲系統,是Google bigtable的apache開源版本。經過近10年的發展,HBase已經成爲了一個成熟的項目,在處理OLTP型的應用如消息日誌,歷史訂單等應用較適用。在HBase中真正接受客戶端讀寫請求的RegionServer的結構如下圖所示:

關於HBase的幾個關鍵點:

(1)在HBase中,充當寫入緩存的這個結構叫做Memstore,另外會將寫入操作順序寫入HLOG(WAL)中以保證數據不丟失。

(2)爲了提高讀的性能,HBase在內存中設置了blockcache,blockcache採用LRU策略將最近使用的數據塊放在內存中。

(3)作爲分佈式存儲系統,爲保證數據不因爲集羣中機器出現故障而導致數據丟失,HBase將實際數據存放在HDFS上,包括storefile與HLOG。HBase與HDFS低耦合,HBase作爲HDFS的客戶端,向HDFS讀寫數據。

 

1、HBase寫過程

(1)客戶端通過客戶端上保存的RS信息緩存或者通過訪問zk得到需要讀寫的region所在的RS信息;

(2)RS接受客戶端寫入請求,先將寫入的操作寫入WAL,然後寫入Memstore,這時HBase向客戶端確認寫入成功;

(3)HBase在一定情況下將Memstore中的數據flush成storefile(可能是Memstore大小達到一定閾值或者region佔用的內存超過一定閾值或者手動flush之類的),storefile以HFile的形式存放在HDFS上;

(4)HBase會按照一定的合併策略對HDFS上的storefile進行合併操作,減少storefile的數量。

2、HBase讀過程

HBase讀數據的過程比較麻煩,原因包括:

(1)HBase採用了LSM-tree的多組件算法作爲數據組織方式,這種算法會導致一個region中有多個storefile;

(2)HBase中採用了非原地更新的方式,將更新操作和刪除操作轉換成插入一條新數據的形式,雖然這樣能夠較快的實現更新與刪除,但是將導致滿足指定rowkey,列族、列名要求的數據有多個,並且可能分佈在不同的storefile中;

(3)HBase中允許設置插入和刪除數據行的timestamp屬性,這樣導致按順序落盤的storefile內數據的timestamp可能不是遞增的。

  下面介紹從HBase中讀取一條指定(rowkey,column family,column)

(1)讀過程與HBase客戶端寫過程第一步一樣,先嚐試獲取需要讀的region所在的RS相關信息;

(2)RS接收讀請求,因爲HBase中支持多版本數據(允許存在rowkey、列族名、列名相同的數據,不同版本的數據通過timestamp進行區分),另外更新與刪除數據都是通過插入一條新數據實現的。所以要準確的讀到數據,需要找到所有可能存儲有該條數據的位置,包括在內存中未flush的memstore,已經flush到HDFS上的storefile,所以需要在1 memstore +N storefile中查找;

(3)在找到的所有數據中通過判斷timestamp值得到最終的數據。

二、Kudu

(1)Kudu中的Tablet是負責表中一塊內容的讀寫工作,Tablet由一個或多個Rowset組成。其中有一個Rowset處於內存中,叫做Memrowset,Memrowset主要負責處理新的數據寫入請求。DiskRowSet是MemRowset達到一定程序刷入磁盤後生成的,實質上是由一個CFile(Base Data)、多個DeltaFile(UNDO records &REDO records)和位於內存的DeltaMemStore組成。Base data、UNDO records、和REDO records都是不可修改的,DeltaMemStore達到一定大小後會將數據刷入磁盤生成新的REDO records。Kudu後臺會有一個類似HBase的compaction線程按照一定的compaction 策略對tablet進行合併處理:

 a、將多個DeltaFile(REDO records)合併成一個大的DeltaFile;

 b、將多個REDO reccords文件與Base data進行合併,並生成新的UNDO records;

 c、將多個DiskRowset之間進行合併,減少DiskRowset的數量。

(2)Kudu將最終的數據存儲在本地磁盤上,爲了保證數據可靠性,Kudu爲一個tablet設置了多個副本(一般爲3或5個)。所以一個tablet會由多個TServer負責維護,其中有個副本稱爲leader tablet,寫入的請求只能通過leader tablet來處理,副本之間通過Raft協議保證其他副本與leader tablet的強一致性。

 

1、Kudu寫過程

Kudu與HBase不同,Kudu將寫入操作分爲兩種,一種是插入一條新數據,一種是對一條已插入數據的更新。

1、Kudu插入一條新數據

(1)客戶端連接Master獲取表的相關信息,包括分區信息,表中所有tablet的信息;

(2)客戶端找到負責處理讀寫請求的tablet所負責維護的TServer。Kudu接受客戶端的請求,檢查請求是否符合要求(表結構);

(3)Kudu在Tablet中的所有rowset(memrowset,diskrowset)中進行查找,看是否存在與待插入數據相同主鍵的數據,如果存在就返回錯誤,否則繼續;

(4)Kudu在MemRowset中寫入一行新數據,在MemRowset數據達到一定大小時,MemRowset將數據落盤,並生成一個diskrowset用於持久化數據,還生成一個memrowset繼續接收新數據的請求。

 2、Kudu對原有數據的更新

(1)客戶端連接Master獲取表的相關信息,包括分區信息,表中所有tablet的信息;

(2)Kudu接受請求,檢查請求是否符合要求;

(3)因爲待更新數據可能位於memrowset中,也可能已經flush到磁盤上,形成diskrowset。因此根據待更新數據所處位置不同,kudu有不同的做法:

當待更新數據位於memrowset時

a、找到待更新數據所在行,然後將更新操作記錄在所在行中一個mutation鏈表中;在memrowset將數據落盤時,Kudu會將更新合併到base data,並生成UNDO records用於查看歷史版本的數據和MVCC,UNDO records實際上也是以DeltaFile的形式存放;

當待更新數據位於DiskRowset中

b、找到待更新數據所在的DiskRowset,每個DiskRowset都會在內存中設置一個DeltaMemStore,將更新操作記錄在DeltaMemStore中,在DeltaMemStore達到一定大小時,flush在磁盤,形成Delta並存在方DeltaFile中;

實際上Kudu提交更新時會使用Raft協議將更新同步到其他replica上去,當然如果在memrowset和diskrowset中都沒有找到這條數據,那麼返回錯誤給客戶端;另外當DiskRowset中的deltafile太多時,Kudu會採用一定的策略對一組deltafile進行合併。

 

2、Kudu讀過程

1、客戶端連接Master獲取表的相關信息,包括分區信息,表中所有tablet的信息;

2、客戶端找到需要讀取的數據的tablet所在的TServer,Kudu接受讀請求,並記錄timestamp信息,如果沒有顯式指定,那麼表示使用當前時間;

3、Kudu找到待讀數據的所有相關信息,當目標數據處於memrowset時,根據讀取操作中包含的timestamp信息將該timestamp前提交的更新操作合併到base data中,這個更新操作記錄在該行數據對應的mutation鏈表中;

4、當讀取的目標數據位於diskrowset中,在所有DeltaFile中找到所有目標數據相關的UNDO record和REDO records,REDO records可能位於多個DeltaFile中,根據讀操作中包含的timestamp信息判斷是否需要將base data進行回滾或者利用REDO records將base data進行合併更新。

三、Kudu與HBase在讀寫上過程中的差異

1、寫過程

(1)HBase寫的時候,不管是新插入一條數據還是更新數據,都當作插入一條新數據來進行;而Kudu將插入新數據與更新操作分別看待。

(2)Kudu表結構中必須設置一個唯一鍵,插入數據的時候必須判斷一些該數據的主鍵是否唯一,所以插入的時候其實有一個讀的過程;而HBase沒有太多限制,待插入數據將直接寫進memstore。

(3)HBase實現數據可靠性是通過將落盤的數據寫入HDFS來實現,而Kudu是通過將數據寫入和更新操作同步在其他副本上實現數據可靠性。

結合以上幾點,可以看出Kudu在寫的性能上相對HBase有一定的劣勢。

2、讀過程

(1)在HBase中,讀取的數據可能有多個版本,所以需要結合多個storefile進行查詢;Kudu數據只可能存在於一個DiskRowset或者MemRowset中,但是因爲可能存在還未合併進原數據的更新,所以Kudu也需要結合多個DeltaFile進行查詢。

(2)HBase寫入或者更新時可以指定timestamp,導致storefile之間timestamp範圍的規律性降低,增加了實際查詢storefile的數量;Kudu不允許人爲指定寫入或者更新時的timestamp值,DeltaFile之間timestamp連續,可以更快的找到需要的DeltaFile。

(3)HBase通過timestamp值可以直接取出數據;而Kudu實現多版本是通過保留UNDO records(已經合併過的操作)和REDO records(未合併過的操作)完成的,在一些情況下Kudu需要將base data結合UNDO records進行回滾或者結合REDO records進行合併然後才能得到真正所需要的數據。

 結合以上三點可以得出,不管是HBase還是Kudu,在讀取一條數據時都需要從多個文件中搜尋相關信息。相對於HBase,Kudu選擇將插入數據和更新操作分開,一條數據只可能存在於一個DiskRowset或者memRowset中,只需要搜尋到一個rowset中存在指定數據就不用繼續往下找了,用戶不能設置更新和插入時的timestamp值,減少了在rowset中DeltaFile的讀取數量。這樣在scan的情況下可以結合列式存儲的優點實現較高的讀性能,特別是在更新數量較少的情況下能夠有效提高scan性能。

另外,本文在描述HBase讀寫過程中沒有考慮讀寫中使用的優化技術如Bloomfilter、timestamp range等。其實Kudu中也有使用類似的優化技術來提高讀寫性能,本文只是簡單的分析,因此就不再詳細討論讀寫過程。如有需要了解HBase的詳細讀寫過程,可以參考範欣欣的    HBase - 數據寫入流程解析等一系列HBase相關文章。

 

其他差異

HBase:使用的java,內存的釋放通過GC來完成,在內存比較緊張時可能引發full GC進而導致服務不穩定;

Kudu:核心模塊用的C++來實現,沒有full gc的風險。

總結

以上在整體結構,數據存儲結構還有讀寫過程等方面上對HBase和Kudu這兩款分佈式存儲系統進行大體上的比較。Kudu通過要求完整的表結構設置,主鍵的設定,以列式存儲作爲數據在磁盤上的組織方式,更新和數據分開等技巧,使得Kudu能夠實現像HBase一樣實現數據的隨機讀寫之外,在HBase不太擅長的批量數據掃描(scan)具有較好的性能。而批量讀數據正是olap型應用所關注的重點,正如Kudu官網主頁上描述的,Kudu實現的是既可以實現數據的快速插入與實時更新,也可以實現數據的快速分析。Kudu的定位不是取代HBase,而是以降低寫的性能爲代價,提高了批量讀的性能,使其能夠實現快速在線分析。

 

使用注意點(踩坑記錄)

1、Kudu創建表時,PK字段一定要寫在表結構的最前面。

2、Hash分區只能在創建表時修改,而Range分區可以在使用過程中動態改變。

3、Range分區在動態改變時,通過python api新增一個Range分區

4、一次性將大量數據讀入Kudu,會報Server timeout錯誤,解決方案2個(可以同時使用):

(1)增加memory_limit_hard_bytes配置的值

(2)將大量數據分批寫入Kudu表

5、Kudu的Python api需要注意版本選擇,目前部門用的cdh5.13,kudu1.4,但是python api用的1.4(沒有匹配的1.5版本,安裝python api時要注意)

6、通過impala使用kudu表,既可以通過impala直接創建kudu表(store as kudu),也可以先單獨創建kudu表,再通過通過impala做外部表映射(create external table)。

7、通過cdh的clouder manager重啓kudu服務後,

通過命令:kudu cluster ksck <master_addresses> 查看kudu各個服務和節點狀態時,開始一段時間各個kudu表會不可用,需要等待一段時間纔會正常(重啓之後,kudu內部需要自動做各種處理工作),這時不要慌,耐心等待即可。

8、通過python的os.system提交命令imapal sql時,注意字段名稱是否含有特殊字段,若有則需要做轉義,否則impala-shell運行時會根據特殊字段切分字段名稱,導致報錯。

9、讀取Kudu表時,需要根據分區字段讀取,儘可能少加載數據,切記一次性讀取全量表(數據表很大時,讀取性能會有很大問題)。

10、通過python api寫入數據時 ,需要控制flush數據量,否則會內存問題,建議每間隔N條記錄(根據實際情況選擇)刷新一次。

11、kudu表的現有限制(未來版本限制或許會移除),舉幾個需要重點注意的栗子:

字段數目不要超過300
PK的類型選擇,不能float和bool等
單個表在單個tablet server上的最大tablets數目爲60,單個tablet server上最大tablet數目爲2000(在設計表分區的時候需要重點考慮) 

如何入門和實戰

循着一下主題去探索。當探索完這些主題的時候,相信你已經掌握了Kudu。

Kudu:一個融合低延遲寫入和高性能分析的存儲系統

https://www.jianshu.com/p/a6c0fdec3d7b

分佈式存儲系統Kudu與HBase的簡要分析與對比

https://zhuanlan.zhihu.com/p/44517915

KUDU 介紹以及簡單的入門操作

https://blog.csdn.net/weixin_43228814/article/details/88907534

KUDU 介紹

https://www.jianshu.com/p/93c602b637a4

kudu使用方法

https://blog.csdn.net/cdxxx5708/article/details/79074489

kudu學習資料總結 https://my.oschina.net/u/269325/blog/817106

1 ,    kudu 是什麼 ,爲什麼要用kudu

2     kudu 的基本架構,概念和術語

3     kudu 的表的schema文件改如何設計

4     Kudu的java操作代碼,

5     利用impala來操作kudu

6     kudu和spark的結合

 

Kudu在使用過程中的各種限制

https://www.jianshu.com/p/3de0f2dcd6ca

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章