標籤:

Kudu vs HBase

Kudu vs HBase

來自專欄 網易大數據

本文由網易雲 發布

背景

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

整體結構Hbase的整體結構

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

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

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

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

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

Kudu的整體結構

Kudu的主要組件包括TServer和TMaster。

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

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

主要區別

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

(1)Kudu將HBase中zookeeper的功能放進了TMaster內,Kudu中TMaster的功能比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,這樣的設置可以完成某些特定的操作;

(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將寫入操作分為兩種,一種是插入一條新數據,一種是對一條已插入數據的更新。Kudu插入一條新數據:

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

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

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

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

Kudu對原有數據的更新

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

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

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

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

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

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

2. Kudu讀過程

(1)客戶端連接TMaster獲取表的相關信息,包括分區信息,表中所有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進行合併更新。

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的詳細讀寫過程,

3. 其它差異

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

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

總 結

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

想要了解網易大數據,請戳這裡網易大數據|專業的私有化大數據平台

了解 網易雲

網易雲官網:https://www.163yun.com/

新用戶大禮包:https://www.163yun.com/gift

網易雲社區:https://sq.163yun.com/


推薦閱讀:

TAG:Hadoop | HBase | Kudu |