1. 程式人生 > >列式儲存資料庫-kudu

列式儲存資料庫-kudu

一、kudu概念
Apache Kudu是由Cloudera開源的儲存引擎,可以同時提供低延遲的隨機讀寫和高效的資料分析能力。Kudu支援水平擴充套件,使用Raft協議進行一致性保證,並且與Cloudera Impala和Apache Spark等當前流行的大資料查詢和分析工具結合緊密。
這是一個為塊資料的快分析而生的儲存架構

二、kudu架構
Master:
master節點負責整個叢集的元資料管理和服務協調。它承擔著以下功能:
作為catalog manager,master節點管理著叢集中所有table和tablet的schema及一些其他的元資料。
作為cluster coordinator,master節點追蹤著所有server節點是否存活,並且當server節點掛掉後協調資料的重新分佈。
作為tablet directory,master跟蹤每個tablet的位置。
Catalog Manager:
master將內部catalog的資訊寫入tablet中,並將catalog寫入記憶體中。catalog table儲存了所有table的schema的版本以及table的狀態(建立、執行、刪除等)。
Cluster Coordination:叢集協調
kudu叢集中的每個table server 都需要配置master的主機名列表。叢集啟動table server第一次彙報時彙報自身所有資訊,之後彙報增量資訊。
master只是叢集狀態的觀察者。對於tablet server中tablet的副本位置、Raft配置和schema版本等資訊的控制和修改由tablet server自身完成。master只需要下發命令,tablet server執行成功後會自動上報處理的結果。
Table Directory:
master儲存了元資料,client不會每次都去master獲取table位置,而是會在本地儲存一份元資料,只有當元資料資訊發生改變時,client收到相應的通知才回去master拉取最新的元資料來更新本地儲存。
Tablet 儲存:
完全基於自身實現,不借助於其他儲存系統。實現目標:
1、快速的列掃描
2、低延遲的隨機讀寫
3、一致性的效能
Rowset:
kudu中,table被分為更小的單元rowset。rowset分Memrowset、diskRowset。一個table僅有一個Memrowset。後臺執行緒會定期將memrowsetflush到磁碟。
flush同步進行:在flush的同時client也可以進行讀寫操作
Memrowset:
memrowset可以被併發訪問,是一個實現了鎖優化的B-tree
注意:
1、不支援直接刪除資料。只是插入了一條標誌刪除的資料
2、不支援原地更新
3、將tree的leaf連結起來,就像B+-tree。這一步關鍵的操作可以明顯地提升scan操作的效能。
4、沒有實現字典樹(trie樹),而是隻用了單個tree,因為Kudu並不適用於極高的隨機讀寫的場景
memrowset再記憶體中是行式儲存
Diskrowset:base data 、delta data
每32M形成一個diskrowset,列式儲存,通過B-tree索引。主鍵索引存入一個列中,並提供布隆過濾器來進行高效查詢
沒32M形成一個diskrowset保證每個disrowset不會太大。每次合併的時候不會造成太大效能影響。不會出現像hbase中major compaction的情況
Compaction:
kudu會定期執行compaction操作,合併basa data和delta data,對標記了刪除的資料進行刪除,同時合併一些diskrowset
分割槽:
當用戶建立一個table時,可以同時指定table的的partition schema,partition schema會將primary key對映為partition key。一個partition schema包括0到多個hash-partitioning規則和一個range-partitioning規則。通過靈活地組合各種partition規則,使用者可以創造適用於自己業務場景的分割槽方式。

三、安裝
官方文件:http://cwiki.apachecn.org/pages/viewpage.action?pageId=10813613#id-%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97-%E5%AE%89%E8%A3%85ApacheKudu
cdh安裝:https://blog.csdn.net/mergerly/article/details/75127392

開源的rpm安裝服務啟動失敗可能遇到的問題:
1、ntp服務沒啟動
解決:systemctl start NTP
服務啟動後,需要5-10鍾來完成同步。判斷是否已經完成同步可以使用命令:ntpstat,如果輸出為:
synchronised to NTP server (120.25.108.11) at stratum 3
time correct to within 114 ms
polling server every 1024 s
表示同步成功,在此執行kudu啟動命令。
2、許可權問題:
kudu的啟動預設會使用一個叫kudu的使用者。啟動之前更改目錄所屬使用者、所屬組
通過cdh安裝一般不會遇到問題

建表:
kudu沒有互動式介面,使用impala-shell 或 建立客戶端來操作
impala-shell:
hash分割槽:
CREATE TABLE my_first_table1
(
id BIGINT,
name STRING,
PRIMARY KEY(id)
)PARTITION BY HASH (id) PARTITIONS 16 STORED AS KUDU TBLPROPERTIES ( 'kudu.table_name' = 'my_first_table', 'kudu.master_addresses' = 'dsf:7051');

預設按主鍵hash分割槽
STORED AS KUDU 是kudo表的標識
kudu.table_name:Impala將在Kudu中建立(或對映到)的表的名稱
kudu.master_addresses:Impala應與之交流的Kudu master地址列表
不想每次都指定master地址可以對impala進行配置:
在cdh裡面 impala->配置->impala Daemon ->Impala Daemon 命令列引數高階配置程式碼段(安全閥)加上配置:
--kudu_master_hosts = kudu master
配置後重啟就ok了

range分割槽:
CREATE TABLE `first_kudu_test` ( `id` int, `name` STRING ,primary key(id,name))partition by range (id) (partition VALUES <10,partition 10<=VALUES<100) stored AS kudu TBLPROPERTIES ( 'kudu.table_name' = 'my_second_table', 'kudu.master_addresses' = 'dsf:7051');

外部表:
通過api客戶端建立的kudu表需要在impala中建立外部對映表才能訪問
CREATE EXTERNAL TABLE my_mapping_table STOREDAS KUDU TBLPROPERTIES ( 'kudu.table_name' = 'my_kudu_table' );


四、kudu整合其他引擎、框架
kudu目前C++、Java、Python的客戶端API,但是對Python的支援不是很完善,目前處於試驗階段。

查詢引擎——impala
kudu與impala緊密結合,可以使用impala的sql語法來操作kudu資料庫,2.8版本及更高版本、cdh5.10的impala2.7
已知問題和限制:
1、在使用 Impala 中的外部表時,必須為具有大寫字母或非 ASCII 字元的名稱的 Kudu 表分配備用名稱。
2、包含大寫或非ascii字元的列名稱的Kudu表不能用作Impala中的外部表。 可以在Kudu中重新命名列以解決此問題。
3、建立 Kudu 表時,CREATE TABLE 語句必須在主鍵順序中包含其他列之間的主鍵列。
4、包含 UNIXTIME_MICROS 型別列的kudu表不能用作 Impala 中的外部表。
5、Impala 不能使用 TIMESTAMP , DECIMAL , VARCHAR 或巢狀型別的列建立 Kudu 表。
6、Impala 無法更新主鍵列中的值。
7、NULL,NOT NULL,!= 和 LIKE 謂詞不會被推送到 Kudu ,而是會被 Impala 掃描節點評估。這可能會降低相對於其他型別謂詞的效能。
8、通過 Impala 的更新,插入和刪除是非事務性的。如果查詢部分失敗,其部分效果將不會回滾。
9、單個查詢的最大並行度僅限於表中的 tablets 數量。為了獲得良好的分析效能,每個主機可以使用10個或者更多tablets。

計算框架——spark
kudu自1.6版本後不再支援spark1,所以要使用spark1需選擇kudu 1.5及之前版本,kudu 1.6及以後版本需使用spark2。
kudu為spark帶來的便利:
1、實時資料的快速分析
2、謂詞下推,快速查詢---過濾條件可以下推到kudu執行,提高掃描效率
3、基於主鍵索引的快速查詢
4、支援update、delete
spark為kudu帶來的便利:
更簡單的資料操作方式

已知問題和限制:
1、當註冊為臨時表時,必須為名稱包含大寫或非ascii字元的Kudu表分配備用名稱。
2、包含大寫或非ascii字元的列名的Kudu表不能與SparkSQL一起使用。 可以在Kudu中重新命名列以解決此問題。
3、<>和OR謂詞不會被推送到Kudu,而是由Spark任務評估。 只有具有後綴萬用字元的LIKE謂詞被推送到Kudu,這意味著LIKE“FOO%”被下推但LIKE“FOO%BAR”不會。
4、Kudu不支援Spark SQL支援的每種型別。 例如,不支援date和複雜型別。
5、Kudu表只能在SparkSQL中註冊為臨時表。 使用HiveContext可能無法查詢Kudu表。
6、在spark中刪除kudu的資料的時候可以將你需要刪除的資料用一個dataframe組裝,呼叫kuducontext的deleterows來進行刪除,但是有一點要注意,你的dataframe中只能包含主鍵資訊,程式碼如下:
val conf = new SparkConf()
conf.setAppName("Test")
conf.setMaster("local[*]")
val sc = new SparkContext(conf)
val kuduContext = new KuduContext("dsf:7051",sc)
val sQLContext = new SQLContext(sc)
val kuduTable = "KuDuTest"
val kuduOptions: Map[String, String] = Map(
"kudu.table" -> kuduTable,
"kudu.master" -> "dsf:7051")
//讀取表資料,註冊臨時表
val reader: DataFrame = sQLContext.read.options(kuduOptions).kudu
reader.registerTempTable(kuduTable)
//將需要刪除的資料組裝,Name是主鍵,主鍵有多個的時候都要加上
val frame: DataFrame = sQLContext.sql(s"select Name from $kuduTable where AGE=13")
//呼叫api刪除
kuduContext.deleteRows(frame,kuduTable)

五、目前已知的問題和限制
1、主鍵
(1)、建立表後,主鍵不可更改,需刪表後重新建立表指定新的主鍵
(2)、構成主鍵得列必須先列在模式中
(3)、使用該UPDATE功能無法修改行的主鍵。要修改行的主鍵,必須刪除該行並使用修改後的鍵重新插入。這種修改是非原子的。
(4)、帶有DOUBLE,FLOAT或BOOL型別的列不允許作為主鍵定義的一部分。此外,作為主鍵定義一部分的所有列必須是NOT NULL。
(5)、不支援自動生成的主鍵
(6)、在Kudu完成內部複合鍵編碼之後,構成複合主鍵的單元限制為總共16KB。
2、列
(1)、不支援char、varchar、date、array等複雜型別
(2)、通過更改表格無法更改現有列的型別和可為空性
(3)、表最多可以有300列
3、表
(1)、表必須具有奇數個副本,最多為7個
(2)、複製因子無法更改
4、單元格
再編碼或壓縮之前,單元格不能大於64k
5、其他使用限制
(1)、kudu主要用於分析,一行最好不要有多於千位元組的資料,否則可能會出現問題
(2)、不支援二級索引,不支援多行事務,不支援關聯功能,如外來鍵
(3)、列和表名等識別符號僅限於有效的UTF-8字串。此外,最大長度為256個字元。
(4)、刪除列不會立即回收空間,再執行compaction之後才會回收
(5)、無法手動執行壓縮,刪除表立即回收空間
6、分割槽
(1)、表必須使用簡單或複合主鍵預分割成tablets,不支援自動拆分,建表後可以刪除或增加範圍分割槽
(2)、表中現有的資料無法自動分割槽。使用新分割槽建表後插入舊錶的內容
(3)、tablets丟失超過半數的副本數需要手動干預才能恢復
7、叢集管理
(1)、不支援機架意識
(2)、不支援多資料中心
(3)、不支援滾動重啟
8、伺服器管理
(1)、生產部署應為tablet servers配置至少4GB記憶體,理想情況下應大於10GB
(2)、不能容忍磁碟故障,一旦檢測到磁碟故障tablet servers就會崩潰
(3)、tablet 無法更改埠地址
9、其他問題
(1)、kudu沒有內建的恢復和備份功能
(2)、授權僅適用於系統範圍的粗粒度級別。表級,列級和行級授權功能不可用。
六、kudu與hbase
底層與架構設計:
HBase:使用的java,記憶體的釋放通過GC來完成,在記憶體比較緊張時可能引發full GC進而導致服務不穩定;
Kudu:核心模組用的C++來實現,沒有full gc的風險;
Kudu所有叢集的配置資訊均儲存在本地磁碟中,hbase的叢集配置資訊是儲存在zookeeper中;
Hbase將資料持久化這部分的功能交給了Hadoop中的HDFS,最終組織的資料儲存在HDFS上。Kudu自己將儲存模組整合在自己的結構中,內部的資料儲存模組通過Raft協議來保證leader Tablet和replica Tablet內資料的強一致性,和資料的高可靠性。
Hbase是列族式儲存,kudu是完全的列式儲存
寫效能:
HBase寫的時候,不管是新插入一條資料還是更新資料,都當作插入一條新資料來進行;而Kudu將插入新資料與更新操作分別看待;
Kudu表結構中必須設定一個唯一鍵,插入資料的時候必須判斷一些該資料的主鍵是否唯一,所以插入的時候其實有一個讀的過程;而HBase沒有太多限制,待插入資料將直接寫進memstore;
HBase實現資料可靠性是通過將落盤的資料寫入HDFS來實現,而Kudu是通過將資料寫入和更新操作同步在其他副本上實現資料可靠性;
結合以上幾點,可以看出Kudu在寫的效能上相對HBase有一定的劣勢;
讀效能:
(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效能。

七、什麼時候使用kudu——適用場景
大規模資料複雜的實時分析,例如大資料量的join。
資料有更新
查詢準實時
Kudu 最適合的場景包含這兩個特點:
同時有順序和隨機讀寫的場景
對資料更新的時效性要求比較高
這樣的場景有:
和時間序列相關的資料分析:對市場/銷售資料的實時分析;反欺詐;網路監控等
線上報表和資料倉庫應用:如ODS(Operational Data Store)
結合kudu與遺留系統資料

更多詳情可以參考官方文件。