zoukankan      html  css  js  c++  java
  • Kudu系列-基础

    Apache Kudu 支持Insert/Update/Delete 等写操作(Kudu 随机写效率也很高, 实测对一个窄表做全字段update, 其速度达到了Insert速度的88%, 而vertica的update效率比insert差很多), Kudu 表文件是列式数据格式(和Parquet格式类似), 所以Kudu是一个支持记录修改的分析型系统, Kudu+Impala组合起来就是一个很有竞争力的MPP架构.

    SQL on kudu 不同与SQL on hadoop, Hive 和其他 SQL on hadoop都是read on schema方式, 而 impala on kudu 是 write on scheme(这和普通的DB一样), 这就导致了两个不同点:
    1. impala 插入kudu 表, 将根据记录的分区键写到对应的kudu tablet中, 而SQL on hadoop无法精细控制记录写入到哪个data node中.
    2. 不合法的记录将无法写入到kudu表, 而使用hive 却能写入到hdfs文件中, 比如一个int字段,我们无法将'abc'这样的字符串写入到kudu表; 但使用hive可以写入, 只是读取时该字段被处理为null.
    3. 因为kudu知道一个记存放在哪里(通过主键), 如果我们的Select/delete/update语句能利用上主键(聚集主键), 执行效率比较高. 如果利用不上的话, 效率就差了.

    Apache Kudu 虽然是Cloudera贡献的, 但并没有包含在CDH中, 需要单独安装, 因为 Kudu 其实并不依赖 Hadoop 运行环境, 文件并不是存放在hdfs上. 但如果搭配Impala使用, 就需要Hadoop环境(impala以来Hive).


    ---==============================
    安装 kudu
    ---==============================
    在CDH 5.5.10 VM版本以上(impala 2.7版以上), 使用下面命令安装kudu软件.
    $ sudo yum install kudu # Base Kudu files
    $ sudo yum install kudu-master # Kudu master init.d service script and default configuration
    $ sudo yum install kudu-tserver # Kudu tablet server init.d service script and default configuration
    $ sudo yum install kudu-client0 # Kudu C++ client shared library
    $ sudo yum install kudu-client-devel # Kudu C++ client SDK


    kudu安装包会自动在Linux alternatives 数据库下创建 kudu-conf 入口,
    sudo alternatives --display kudu-conf

    手动启动kudu
    $ sudo service kudu-master start
    $ sudo service kudu-tserver start

    自动启动设置
    $ sudo chkconfig kudu-master on # RHEL / CentOS / SLES
    $ sudo chkconfig kudu-tserver on # RHEL / CentOS / SLES

    ---==============================
    主键
    ---==============================
    主键: 每个表都必须有一个Unique主键, 主键可以是单独字段也可以由多个字段组成, 但主键中的每个字段都应该是non null, 而且不能是boolean和浮点类型字段. 重复的PK的记录将无法Insert到Kudu表中, 而且主键值是不能修改的. Kudu主键是聚集索引, 也就是说每个tablet中的记录将按照主键排序存储, 在scan时候能利用这些排序加快记录查找.
    通过Kudu API更新/删除记录必须提供主键, 通过Impala查询引擎没有这个限制.

    注意:
    1. 在建表DDL语句中, 主键要放到字段清单的前段.
    2. 除了主键, kudu不支持建立其他索引
    3. 主键值不能被update
    4. insert语句中, 主键名是大小写敏感的, 其他语句大小写不敏感. [怀疑是kudu的bug]


    主键的选择原则:
    1. 选择性强的字段(比如id 类) 应该放在PK清单最前面, 这个规则对查询性能影响最大.
    2. PK清单中只加必要的unique字段, 越少越好.
    3. 如果查询针对PK中所有字段都加了条件, 其性能是最优的. 但只要有一个PK字段未加条件, 相当于完全用不上PK索引,性能就很差.
    我专门又写了个文章讨论主键选择策略, http://www.cnblogs.com/harrychinese/p/kdu_pk.html

    ---==============================
    分区
    ---==============================
    分区键: Kudu要求分区键必须属于主键. 如果没有显式指定分区键的时候, 主键就是分区键, 即按照主键Hash分区, 分区数量为1个, 而且只有缺省方式才能建立1 个 partition,  专门用语句指定的话, partition数量必须大于1.
    既然分区键一定属于主键, 所以Kudu表的主键最好除了包含业务主键, 最好再加上也写常用的查询字段, 比如时间字段和userId这样的字段, 这样能更好地设计分区策略.

    分区数如何确定:

    Kudu每个表在tablet server上的切片数量不能大于60个(含replica), 按照20个tablet server算, 一个表最多400个partition, Impala的限制是100K个, Vertica的限制是512个.
    通常增加分区(切片)数, 对于写入是有利的, 但对于读取可能有利有弊(会提升读取的并行度, 但会增加扫描切片的数量).
    总的原则是: 切片数不要大于集群中CPU的总core数, 如果切片数超过CPU core数, 性能反倒会下降.
    具体为:
    1. Fact表, 切片数<=集群中CPU的总core数, 并是机器数量的倍数, 以防止数据倾斜.
    2. Dim表, 切片数应<<集群中CPU的总core数, 保证每个tablet的size至少1GB.


    分区方法:
    Kudu分区方法只能在建表的时候确定, 所以确定分区方法一定要仔细考虑. Kudu支持Hash和Range分区, 而且支持使用Hash+Range作分区.
    1. hash 分区: 写入压力较大的表, 比如发帖表, 按照帖子自增Id作Hash分区, 可以有效地将写压力分摊到各个tablet中. 因为hash的分区键是自增性的, 就不会有 hot 切片(瓶颈). 可见, 纯hash分区比较适合选择性好的分区键.
    2. range 分区: 如果时间字段可以作为主键的一部分, 可以考虑将时间字段作为range分区键, 往往会得到较好的查询效果. 因为Kudu分区数不能超过1000个, 所以通常不适合用日期作分区键, 因为这样仅能存放3年数据, 往往使用月份作为分区键. 纯range分区的表一般不能太大, 否则当前月的分区往往会是hot分区, 影响性能.
    3. hash + range 分区: 对于较大的事实表, 推荐使用 hash+range分区方法, 使用选择性强的字段作为hash键, 使用月份作为range分区键, 这样能避免纯range分区表的缺点.

    ---==============================
    Kudu的一些限制:
    ---==============================

    压缩前的字段长度应该小于64KB.
    集群最多100 个tablet server.
    每个tablet server推荐最多1000个tablet(含replica).
    每个tablet server最多管理4TB的数据(压缩后的数据量, 含replica).
    每个tablet server存储的数据最大为4T.
    每个tablet 最好控制在20GB内, 1000万笔以内.
    每个表在单个tablet server上最多60个partition(含replica). 按照20个tablet server算(replica三份), 一个表最多400个partition; 按照50个tablet server算, 一个表最多1000个partition.
    更多信息: https://kudu.apache.org/docs/known_issues.html



    ---==============================
    SQL on Kudu 工具:
    ---==============================
    impala 操作kudu的文档: https://impala.apache.org/docs/build/html/topics/impala_kudu.html
    impala 或 Spark SQL

    虽说 Kudu 提供了高效的单行插入和更新功能, 但Impala还是侧重数据分析, 并没有对单行Insert/Update进行优化, 所以如果有大量小型DML的操作, 推荐使用Kudu API而不是Impala SQL方式. 当一定要使用Impala SQL时, 最好采用批处理方式, 即一个Insert 语句一次性插入多行数据.  测试Insert 写到Vertica小集群速度近为7000笔/秒, 而Impala(通过Hive JDBC Driver)写到Kudu仅仅70笔/秒, Impala(通过Impala JDBC Driver)写到Kudu仅仅40笔/秒, 


    ---==============================
    Kudu 建表
    ---==============================
    Kudu的数据类型:
    BOOL, INT8, INT16, INT32, BIGINT, INT64, FLOAT, DOUBLE, STRING, BINARY, TIMESTAMP.
    但 DECIMAL,CHAR,VARCHAR,DATE 和 ARRAY 等复杂类型不受支持.

    Impala 的数据类型:
    BIGINT,BOOLEAN,CHAR,DECIMAL,DOUBLE,FLOAT,INT,REAL,SMALLINT,STRING,TIMESTAMP,TINYINT,VARCHAR
    还有Array,Struct,Map等复杂类型

    当我们使用Impala创建Kudu格式的表, 必须使用kudu数据类型建表, 而不能使用impala支持的数据类型.

    kudu 表文件是列式数据格式, 另外kudu允许为每个字段指定不同的压缩的encoding 算法和压缩算法.


    强烈推荐 impalad 服务加上启动参数 -kudu_master_hosts, 这样每个impala定义kudu表的DDL语句中, 就不需要在TBLPROPERTIES中指定kudu.master_addresses属性.
    kudu.table_name 表属性, 可以理解为在kudu中的表名(物理表名), 而建表语句的表名可以理解为impala catalog中的名称(逻辑名称).

    drop table if exists kudu_somedb.kudu_test ;
    CREATE TABLE kudu_somedb.kudu_test
    (

    ActionDate timestamp ENCODING BIT_SHUFFLE COMPRESSION LZ4,
    UID string ENCODING PLAIN_ENCODING COMPRESSION SNAPPY,
    Operation string ENCODING DICT_ENCODING COMPRESSION SNAPPY,
    EUTIME timestamp ENCODING BIT_SHUFFLE COMPRESSION LZ4,-- default now(),
    EID_kudu string ENCODING PLAIN_ENCODING COMPRESSION SNAPPY,-- concat(cast(unix_timestamp() as string),uuid()) ,
    PRIMARY KEY (ActionDate,Uid,Operation)
    )
    PARTITION BY HASH (Uid) PARTITIONS 6 ,
    RANGE (ActionDate) (
    PARTITION '2018-03-16' <= VALUES < '2018-03-17',
    PARTITION '2018-03-17' <= VALUES < '2018-03-18',
    PARTITION '2018-03-18' <= VALUES < '2018-03-19',
    PARTITION '2018-03-19' <= VALUES < '2018-03-20'
    )

    STORED AS KUDU
    TBLPROPERTIES (
    'kudu.table_name' = 'somedb.kudu_test',
    'kudu.master_addresses' = '10.205.6.121:7051,10.205.6.122:7051,10.205.7.134:7051' ,
    'kudu.num_tablet_replicas' = '3'
    );

    下面是增加和删除 range 分区的语法:
    alter table kudu_somedb.kudu_test add  IF NOT EXISTS range partition '2018-03-20' <= VALUES < '2018-03-21' ;
    alter table kudu_somedb.kudu_test drop  IF EXISTS  range partition '2018-03-20' <= VALUES < '2018-03-21' ;

    -- Create select 方式建表语法, 注意这里的primary key()中的字段名必须使用小写字母.
    create table temptable.test
    Primary key(id,name)
    STORED AS KUDU
    TBLPROPERTIES (
    'kudu.table_name' = 'temptable.test',
    'kudu.master_addresses' = '10.205.6.121:7051,10.205.6.122:7051,10.205.7.134:7051',
    'kudu.num_tablet_replicas' = '1'
    )
    as
    select 1 id, 'name' name, 20 ag
    ;

    ---==============================
    善用 if exists 语句
    ---==============================
    很多时候我们需要在程序中创建临时表, 逻辑一般是, 如果临时表存在先drop, 然后新建这个临时表. 因为是在程序中, 所以删除动作不希望报错, 这时候可以在drop table后加上 if exists. 下面用视图说明这个技巧.

    drop view if exists kudu_guba.v1
    ;

    create view if not exists kudu_guba.v1
    as
    select 1 a
    ;

    ---==============================
    蛋疼的大小写规则:
    ---==============================
    1. 使用Impala insert SQL时候, 主键字段名必须是小写; 而update/delete无限制.
    2. 使用 impala 创建kudu表, kudu.table_name名称会保持DDL语句中的大小写, 字段名会自动转成小写字母.
    3. 使用 kudu API 访问表时候, 表名称大小写敏感的(必须按照kudu.table_name名的写法), 字段名也是大小写敏感的(也就是必须使用小写字母).
    4. 采用Create select 方式建表语法, 注意这里的primary key()中的字段名必须使用小写字母.
    5. 普通的DDL建表, primary key()中的字段名大小写都可以.

  • 相关阅读:
    python3操作sqlserver,查询数据统计导出csv
    scrapy入门二(分页抓取文章入库)
    stm32 调试时卡在LDR R0, =SystemInit
    STM32F407 串口通信实验 第26节 个人笔记
    STM32F407 串口通信:分类&常见接口 个人笔记
    STM32F407 IO引脚复用器和映射 个人笔记
    STM32F407 按键输入实验 库函数版 个人笔记
    STM32F407 GPIO 库函数编程套路(led与beep总结) 个人笔记
    STM32F407 跑马灯 寄存器版 个人笔记
    STM32F407 跑马灯 库函数版 个人笔记
  • 原文地址:https://www.cnblogs.com/harrychinese/p/kudu_basics.html
Copyright © 2011-2022 走看看