列式存储数据库-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与遗留系统数据

更多详情可以参考官方文档。

猜你喜欢

转载自www.cnblogs.com/lsbigdata/p/10264620.html
今日推荐