一、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與遺留系統數據
更多詳情可以參考官方文檔。