kudu使用及常见问题小结

问题记录

最近发现kudu日志爆满,info信息全部输出保存在了日志文件里,需要配置日志输出级别:首先登录了kudu监控页面:http://xxxxx:8051 

发现Command-line Flags里的

--minloglevel=0

修改/etc/kudu/conf/master.gflagfile 和 /etc/kudu/conf/tserver.gflagfile 这两个文件,加上--minloglevel=2,重启kudu,

service kudu-master restart

service kudu-tserver restart

问题解决。

 

kudu 使用案例:

主要讲解使用impala进行kudu的操作:

1.假设已经通过Java client等其他方式在kudu中创建了某个表,要想对该表进行操作,需要在impala中创建外部表,将其映射到impala当中,例如:

CREATE EXTERNAL TABLE my_mapping_table

STOREDAS KUDU

TBLPROPERTIES(

'kudu.table_name' = 'my_kudu_table');

 

这种情况极少出现,这边先不展开。

 

2.创建impala外表并从文件中导入数据(注意此表不是kudu表,是用来存放hdfs数据的)

hdfs dfs -mkdir /sfmta

 

zcat sfmtaAVLRawData01012013.csv.gz | tr -d '\r' | hadoop fs -put - /sfmta/data.csv

hadoop fs -ls /sfmta

 

CREATE EXTERNAL TABLE sfmta_raw (

  revision int,

  report_time string,

  vehicle_tag int,

  longitude float,

  latitude float,

  speed float,

  heading float

)

ROW FORMAT DELIMITED

FIELDS TERMINATED BY ','

LOCATION '/sfmta/'

TBLPROPERTIES ('skip.header.line.count'='1');  ---跳过文件首行

 

CREATE TABLE sfmta

PRIMARY KEY (report_time, vehicle_tag)       ---创建表的时候需要指定主键(必须包含主键)

PARTITION BY HASH(report_time) PARTITIONS 8   

STORED AS KUDU

AS SELECT

  UNIX_TIMESTAMP(report_time,  'MM/dd/yyyy HH:mm:ss') AS report_time,   ---string转换成时间戳

  vehicle_tag,

  longitude,

  latitude,

  speed,

  heading

FROM sfmta_raw;

3.kudu使用impala直接创建表

CREATE TABLE my_first_table

(

  id BIGINT,

  name STRING,

  PRIMARY KEY(id)

)

PARTITION BY HASH PARTITIONS 16

STORED AS KUDU;

(不指定hash分区键,默认主键作为hash分区键)

 

CREATE TABLE new_table

PRIMARY KEY (ts, name)

PARTITION BY HASH(name) PARTITIONS 8

STORED AS KUDU

AS SELECT ts, name, value FROM old_table;

 

4.指定 Tablet Partitioning ( Tablet 分区 )

表分为每个由一个或多个 tablet servers 提供的 tablets 。理想情况下,tablets 应该相对平等地拆分表的数据。 Kudu 目前没有自动(或手动)拆分预先存在的 tablets  的机制。在实现此功能之前,必须在创建表时指定分区。在设计表格架构时,考虑使用主键,可以将表拆分成以类似速度增长的分区。使用 Impala 创建表时,可以使用 PARTITION BY 子句指定分区:

CREATE TABLE cust_behavior (

  _id BIGINT PRIMARY KEY,

  salary STRING,

  edu_level INT,

  usergender STRING,

  `group` STRING,

  city STRING,

  postcode STRING,

  last_purchase_price FLOAT,

  last_purchase_date BIGINT,

  category STRING,

  sku STRING,

  rating INT,

  fulfilled_date BIGINT

)

PARTITION BY RANGE (_id)

(

    PARTITION VALUES < 1439560049342,

    PARTITION 1439560049342 <= VALUES < 1439566253755,

    PARTITION 1439566253755 <= VALUES < 1439572458168,

    PARTITION 1439572458168 <= VALUES < 1439578662581,

    PARTITION 1439578662581 <= VALUES < 1439584866994,

    PARTITION 1439584866994 <= VALUES < 1439591071407,

    PARTITION 1439591071407 <= VALUES

)

STORED AS KUDU;

如果有多个主键列,则可以使用元组语法指定分区边界:('va',1),('ab',2)。该表达式必须是有效的 JSON 。

 

5.将数据插入 Kudu

Impala 允许您使用标准 SQL 语句将数据插入 Kudu 。

此示例插入单个行。

INSERT INTO my_first_table VALUES (99, "sarah");

此示例使用单个语句插入三行。

INSERT INTO my_first_table VALUES (1, "john"), (2, "jane"), (3, "jim");

 

Hive入kudu:

insert into table mykudu.my_first_table select * from impala_database.my_first_table

 

 Kudu入hive

insert into table impala_database.my_first_table select * from mykudu.my_first_table

 

6.更新行

UPDATE my_first_table SET name="bob" where id = 3;

7.批量更新

可以使用批量插入中相同的方法 批量更新 。

UPDATE my_first_table SET name="bob" where age > 10;

 

8.删除行

DELETE FROM my_first_table WHERE id < 3;

9.批量删除

您可以使用 “插入批量” 中概述的相同方法 批量删除 。

DELETE FROM my_first_table WHERE id < 3;

 

10.删除表

如果表是使用 Impala 中的内部表创建的,则使用 CREATE TABLE ,标准 DROP TABLE 语法会删除底层的 Kudu 表及其所有数据。如果表被创建为一个外部表,使用 CREATE EXTERNAL TABLE,Impala 和 Kudu 之间的映射被删除,但 Kudu表保持原样,并包含其所有数据。

DROP TABLE my_first_table;

 

11.主键设计

每一个Kudu的表都有且仅有一个主键,主键可以包含多个列,同时要求每一列的值都不能为空(non-nullable),另外bool和浮点数也不能作为主键。创建表的时候主键必须是前几个字段,不能将非主键的字段放在主键字段前,否则会报错。

 

 

 

 12.切片设计(partitioning

作为一个分布式的数据存储引擎,切片是最基本也是最重要的设计之一。对于每个数据库表(table)而言,Kudu会把一个table按照切片规则分成多个partition,一个partition存储在tablet服务之中。每个tablet都有一个一主多从的tablet服务,每条数据属于且仅属于一个tablet,数据和tablet的从属关系规则,由切片规则决定。

 

Range切片

Range的切片方式把数据按照范围进行分类,每个partition会分配一个固定的范围,每个数据只会属于一个切片,不同partition的范围不能有重叠。切片在表的创建阶段配置,后续不可修改,但是可以删除和新增,如果数据找不到所属的切片,会插入失败。

range的切片方式通常与时间有关系,值得注意的是,老的切片可以删掉,同时可以增加新的切片,意味着与时间强相关的数据可以按照这种方式来切片,老的数据可以通过删除切片的方式删除。同时Kudu对此类操作的支持非常高效,完全不用担心删除或者新增切片会影响数据读写。上文有讲到,单片数据过大会影响Kudu的性能,配置为时间相关的Range切片方式,可以很好地控制每片数据的总大小。比如有日志型数据,每秒平均有100条数据写入,配置每天一个切片,则单片数据量规模约为864w。如果配置为hash的切片方式,则单片数据会随着时间推移越来越多大。

切片的设计对Scan性能的影响至关重要,比如对于时间序列类型的数据而言,往往查询的是近期的数据,如果按时间进行切片,则Scan操作可以跳过大部分数据,如果单纯按照默认的hash方式切片,Scan操作则需要扫描全表。

 

ALTER TABLE sales_by_year ADD RANGE PARTITION VALUE = 2017;

 

ALTER TABLE sales_by_year DROP RANGE PARTITION VALUE = 2012;

 

Hash切片

Hash切片把每行数据hash之后分配到对应的tablet。hash切片在设计上相对简单,通常情况下只需要配置计算hash值的列,比如前文所列举的例子,如果你需要查询一个店铺的所有商品,则把shopid作为hash列是比较恰当的选择。相同shopid的hash值是相同的,相同hash值的数据肯定会被分配到同一个partition之中。

需要注意的是hash的切片方式是不可修改的,所以随着数据量的增长,hash的切片方式会造成单片的数据量过大,甚至超过单个tablet服务所能承受的数据量。

hash的切片方式对于随机读写友好,对于写操作而言,hash的切片方式会均匀的把写入压力分担到多个切片之中。对于随机读而言,按照主键进行hash之后Kudu可以提前预知读操作所对应的切片,避免每个切片都查一次。

 

优化一个数据库表的切片规则需要考虑随机读、随机写、扫描三种操作,需根据业务场景的不同侧重来最终决定。

 

随机写压力场景

对于写压力比较大的业务场景,最重要的一点是把写压力均匀分担到不同的tablet之中,这种场景下切片设计通常采用hash partitioning,hash切片拥有良好的随机性。

相比Hbase而言,Kudu的架构可以轻松应对随机写的场景。

 

随机读压力场景

对于随机读压力比较大的业务场景并不是很建议使用Kudu,通常情况下Hbase是一个更好的选择,不过Kudu也拥有不错的随机读性能。Kudu官方的性能测试,在读压力分布符合齐夫定律时,Hbase有读性能优势,随机分布下,Kudu和Hbase的的随机读性能相当。不过通常情况下业务场景的读分布符合齐夫定律,也就是我们常说的28原则,80%的读集中在20%的数据上。

如果用Kudu的业务场景确实随机读压力较大,则通常采用hash partitioning。

 

小范围Scan场景

对于拥有大量小范围Scan的业务场景,比如扫描一个店铺的所有商品,比如找到一个用户看过的所有商品,诸如此类的业务场景最好将同一个Scan所需要的数据放置在同一个tablet里面。比如按店铺id做hash,可以把同一个店铺的所有信息放置在同一个tablet里。按userid做hash,可以把一个用户的所有信息放置在同一个tablet里面。

 

大范围Scan

如果业务场景的Scan所需要扫描的数据量比较大,又想这类Scan跑的快,则需要把这类Scan所需要的数据分布到多个tablets里面,充分利用多机分布式计算能力。假设我们有一个表存储了最近12个月的数据,一个设计方案是按照月来切片,一共12个tablet,但如果大部分BI查询对应的Scan只需要最近1个月的数据,则这种设计便不合理,因为Scan的压力全部集中到了一个tablet之中。

这种情况下一个更好的设计方案是按月切片再按hash切片,具体方案后续再详细分析。

 

多级切片

Kudu支持多层的切片方式,hash和range的切片方式可以结合起来。比如按照月把数据分成多片,每个月的数据再按照hash进行二级切片。

合理的使用多级切片,可以充分利用不同切片方式的优势。

 

切片调优

合理的切片可以让Kudu的Scan操作跳过部分切片,比如上文举例说明的时间序列类型存储。合理的切片还需要避免写入热点,防止大量的写入分配到同一个tablet服务之中。

 

高级分区

hash分区数量*range分区数量不能超过60个(1.7.0版本之后没限制了)

 

可以组合 HASH 和 RANGE 分区来创建更复杂的分区模式。您可以指定零个或多个 HASH 定义,后跟零个或一个 RANGE 定义。每个定义可以包含一个或多个列。

PARTITION BY HASH and RANGE

考虑上面的 简单哈希 示例,如果您经常查询一系列 sku 值,可以通过将哈希分区与范围分区相结合来优化示例。

以下示例仍然创建了16个 tablets ,首先将 id 列分为 4 个存储区,然后根据 sku 字符串的值应用范围划分将每个存储区分为四个数据块。至少四片(最多可达16张)。当您查询相邻范围的 sku 值时,您很有可能只需从四分之一的 tablets 中读取即可完成查询。

注意

默认情况下,使用 PARTITION BY HASH 时,整个主键是散列的。要只对主键进行散列,可以使用像 PARTITION BY HASH(id, sku) 这样的语法来指定它。

CREATE TABLE cust_behavior (

  id BIGINT,

  sku STRING,

  salary STRING,

  edu_level INT,

  usergender STRING,

  `group` STRING,

  city STRING,

  postcode STRING,

  last_purchase_price FLOAT,

  last_purchase_date BIGINT,

  category STRING,

  rating INT,

  fulfilled_date BIGINT,

  PRIMARY KEY (id, sku)

)

PARTITION BY HASH (id) PARTITIONS 4,

RANGE (sku)

(

  PARTITION VALUES < 'g',

  PARTITION 'g' <= VALUES < 'o',

  PARTITION 'o' <= VALUES < 'u',

  PARTITION 'u' <= VALUES

)

STORED AS KUDU;

Multiple PARTITION BY HASH Definitions

再次扩展上述示例,假设查询模式将是不可预测的,但希望确保写入分布在大量 tablets 上,可以通过在主键列上进行散列来实现整个主键的最大分配。

CREATE TABLE cust_behavior (

  id BIGINT,

  sku STRING,

  salary STRING,

  edu_level INT,

  usergender STRING,

  `group` STRING,

  city STRING,

  postcode STRING,

  last_purchase_price FLOAT,

  last_purchase_date BIGINT,

  category STRING,

  rating INT,

  fulfilled_date BIGINT,

  PRIMARY KEY (id, sku)

)

PARTITION BY HASH (id) PARTITIONS 4,

             HASH (sku) PARTITIONS 4

STORED AS KUDU;

该示例创建16个分区。也可以使用 HASH(id,sku) PARTITIONS 16。但是,对于 sku 值的扫描几乎总是会影响所有16个分区,而不是可能限制为 4 。

 

存在问题:

(1) 重复数据不报错(upsert into)

经过测试发现,insert into时若有主键重复,插入的数据不会更新原有数据,并且不会报错,但是会有warning。用upsert into时,主键重复数据会更新原有数据,并且语句执行正常,没有warning。并且两个语句的执行效率类似。

 

(2) 不存在事务

(3)导入数据有问题

暂时如此,未来要管控

(4) 分区要研究

答:kudu建表必须指定分区,且分区数至少为2个。Kudu建表有两种方式的分区方法,分为hash方式建表和range方式建表。

  1. 使用hash方式:

一般情况下,对于全量表,可使用hash方式建表,且由于全量表数据量较小,hash分区数指定为2即可。

例:

drop table mykudu.cust_behavior;

CREATE TABLE mykudu.cust_behavior (

  id BIGINT,

  sku STRING,

  salary STRING,

  edu_level INT,

  PRIMARY KEY (id, sku)

)

PARTITION BY HASH PARTITIONS 2

STORED AS KUDU;

  1. 使用range方式:

对于大数据量的增量表,如估值表,凭证表,大数据平台暂定存储三个月时间的数据,因此一般使用range方式存储数据,range方式可动态的进行分区的创建和删除,可按月来进行数据的存储。后续需要按月进行批量表的动态分区创建及删除。

例:

CREATE TABLE mykudu.sales_by_month (

      month_time INT,

sale_id INT,

amount INT,

  PRIMARY KEY (sale_id, month_time)

)

PARTITION BY RANGE (month_time) (

  PARTITION VALUE = 201811,

  PARTITION VALUE = 201812,

  PARTITION VALUE = 201901

)

STORED AS KUDU;

 

ALTER TABLE mykudu.sales_by_month ADD RANGE PARTITION VALUE = 201902;

ALTER TABLE mykudu.sales_by_month drop RANGE PARTITION VALUE = 201811;

 

(5)部分函数不复用

(6)不存在索引

(7)必须有主键

Kudu使用过程中的多种限制(主键):

a.表创建之后,主键不能修改,必须删除重建表指定新的主键;

b.主键列必须在非主键列之前;

c.主键列的值不能使用update函数进行修改;如果要修改主键的值,只能删除该行重新插入;

d.Double,float和boolean类型的列不能作为主键,此外,主键必须为not null。

e.不支持自动生成主键(如自增列);

f.组合主键所有列在编码后,大小不能大于16k

 

(8)数据存储默认编码格式(utf-8)

 下游同步数据需要注意

(9)主键列存在NULL值,导致插入错误,但执行成功,只返回warning。

 

(10)主要参考Impala函数

(11)字符串是以UTF-8编码

 

参考文献:

(1)Kudu+Impala介绍 | 微店数据科学团队博客

(2)Apache Kudu - Fast Analytics on Fast Data

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值