介绍
Kudu是基于Hadoop平台的列式存储系统。
Kudu官方文档
Kudu使用场景
- 适用于既有随机访问,也有批量数据扫描的复合场景
- 适用于高计算量的场景
- 充分利用高性能存储设备
- 支持数据更新,避免数据反复迁移
- 支持跨地域的实时数据备份和查询
Kudu的优势
- 支持update和upsert操作
- 结构化数据模型
- 与imapla或spark集成后,可通过sql操作,使用方便
- 一个table由多个tablet组成,对分区查看、扩容和数据高可用支持非常好
Kudu和HBase、Hive对比
- 在字段较多时,HBase保存一行数据存储会膨胀很多倍,在大数据量下,HBase对存储的消耗是难以接受的,而Kudu独特的列编码和列压缩会极大节省存储空间
- 在批量读取和批量写入速度上(宽表,字段90+),Kudu都比HBase要快很多。有博客说HBase的写性能要优于Kudu,但根据我的测试,写入一小时数据,HBase使用bulk load写空表都需要4分钟,而Kudu不超过2分钟(可能集群性能上有差异,但应该不是主要因素)。HBase读HFile的方式读取一小时数据需要10分钟,而Kudu读一天的数据10分钟
- 相比Hive,Kudu支持动态增删列和数据更新,随机读取效率也高(但不如HBase),适合有更新需求,或回溯补全历史数据的情况
- Kudu实质上是HBase和Hive的折中,兼顾了批量读写与随机读写的效率
性能测试
- 天级别读:源数据2.8亿,541.7 G,耗时10min,平均46.6w条/s
- 小时级别写:源数据2000W行,38G,耗时1.4min,平均23w条/s
- 天级别更新列:源数据4.74亿行,10个新列,耗时17min,平均46.5w条/s (其中包括读800G的text格式hive表的时间,真实插入时间更少)
Spark操作Kudu接口
注意事项
- kudu引擎暂不支持sparkSQL中 <、>、or 这些谓词下推,支持like,但仅限于“201907%”这种形式,不支持“201907%02”这种形式
- 使用SparkSQL读取Kudu表时,必须使用between或者in来指定range分区字段的范围,否则会变成全表扫描,效率极低!!!
- 插入数据、更新数据和删除行的df必须包含所有主键,主键不可为空
- 删除kudu分区会同时删除分区内的数据
Spark-Kudu接口
目前官网提供的kuduContext接口极为简单,无法满足需求,因此整合了一个功能更全面的接口。
GitHub地址:
https://github.com/FeichenYe/KuduHandle
以下仅给出创建kudu表、给kudu表增加列、给kudu表加range分区、删除kudu表range分区的例子,全部的api详见git。
创建带编码格式和列压缩的kudu表:
/**
*新建kudu表。这里range分区字段强制为一个字段
* @param kuduTableName 新建kudu表名
* @param rangeKeyColumn range分区字段 (kudu表的range分区字段可以由多个主键字段组成,但这里强制指定唯一range字段)
* @param hashKeyColumns hash分区字段,由多个主键组成,逗号分隔
* @param simpleBaseColumns kudu表非主键字段,逗号分隔
*/
def createTable(kuduTableName: String,
rangeKeyColumn: String,
hashKeyColumns: String,
simpleBaseColumns: String): Unit ={
//TODO:定义列schema
val kuduCols = new util.ArrayList[ColumnSchema]()
val rangeCol = new ColumnSchema.ColumnSchemaBuilder(rangeKeyColumn, Type.STRING).key(true).nullable(false)
.encoding(Encoding.DICT_ENCODING).compressionAlgorithm(CompressionAlgorithm.LZ4)
kuduCols.add(rangeCol.build())
for(colName <-