kudu impala

Impala介绍

Impala是什么
Impala是建立在Hadoop生态圈的交互式SQL解析引擎,Impala的SQL语法与Hive高度兼容,并且提供标准的ODBC和JDBC接口。Impala本身不提供数据的存储服务,其底层数据可来自HDFS、Kudu、Hbase甚至亚马逊S3。

Impapa最早由Cloudera公司开发,于15年12月贡献给Apache基金会,目前其正式名字为Apache Impala(incubating)

Impala本身并不是Hive的完全替代品,对于一些大吞吐量长时间执行的请求,Hive仍然是最稳定最佳的选择,哪怕是SparkSQL,其稳定性也无法跟Hive媲美。

稳定性方面Impala不如Hive,但是在执行效率方面,Impala毫无疑问可以秒杀Hive。Impala采用内存计算模型,对于分布式Shuffle,可以尽可能的利用现代计算机的内存和CPU资源。同时,Impala也有预处理和分析技术,表数据插入之后可以用COMPUTE STATS指令来让Impala对行列数据深度分析。

Impala的优势

和Hive高度相似的SQL语法,无需太多学习成本
超大数据规模SQL解析的能力,高效利用内存与CPU利用,快速返回SQL查询结果。
集成多个底层数据源,HDFS、Kudu、Hbase等数据皆可通过Impala共享,并且无需进行数据同步。
与Hue深度集成,提供可视化的SQL操作以及work flow。
提供标准JDBC和ODBC接口,方便下游业务方无缝接入。
提供最多细化到列的权限管理,满足实际生产环境数据安全要求。
Impala和Hive的SQL兼容性?
Impala高度兼容Hive,不过有部分Hive的SQL特性在Impala中并不支持,其中包括:

Data等类型不支持
XML和Json函数不支持
多个DISTINCT不支持,完成多个DISTINCT需要如下操作
select v1.c1 result1, v2.c1 result2 from (select count(distinct col1) as c1 from t1) v1 cross join (select count(distinct col2) as c1 from t1) v2;

Impala和Hive的兼容不仅仅体现在语法上,在架构上Impala和Hive也保持着相当程度上的兼容性,Impala直接采用Hive的元数据库,对于公司而言,已经在Hive中的表结构无需迁移,Impala可以直接使用。

Kudu+Impala对我们意味着什么

Kudu+Impala为实时数据仓库存储提供了良好的解决方案。这套架构在支持随机读写的同时还能保持良好的Scan性能,同时其对Spark等流式计算框架有官方的客户端支持。这些特性意味着数据可以从Spark实时计算中实时的写入Kudu,上层的Impala提供BI分析SQL查询,对于数据挖掘和算法等需求可以在Spark迭代计算框架上直接操作Kudu底层数据。

kudu应用场景

大规模数据复杂的实时分析,例如大数据量的join。
数据有更新
查询准实时

Kudu以及Impala的不足

Kudu主键的限制

表创建后主键不可更改;
一行对应的主键内容不可以被Update操作修改。要修改一行的主键值,需要删除并新增一行新数据,并且该操作无法保持原子性;
主键的类型不支持DOUBLE、FLOAT、BOOL,并且主键必须是非空的(NOT NULL);
自动生成的主键是不支持的;
每行对应的主键存储单元(CELL)最大为16KB。

Kudu列的限制

MySQL中的部分数据类型,如DECIMAL, CHAR, VARCHAR, DATE, ARRAY等不支持;
数据类型以及是否可为空等列属性不支持修改;
一张表最多有300列。

Kudu表的限制

表的备份数必须为奇数,最大为7;
备份数在设置后不可修改。

Kudu单元(Cells)的限制

单元对应的数据最大为64KB,并且是在压缩前。

Kudu分片的限制

分片只支持手动指定,自动分片不支持;
分片设定不支持修改,修改分片设定需要”建新表-导数据-删老表”操作;
丢掉多数备份的Tablets需要手动修复。

Kudu容量限制

建议tablet servers的最大数量为100
建议masters的最大数量为3;
建议每个tablet server存储的数据最大为4T(此处存疑,为何会有4T这么小的限制?);
每个tablet server存储的tablets数量建议在1000以内;
每个表分片后的tablets存储在单个tablet server的最大数量为60

Kudu其他使用限制

Kudu被设计为分析的用途,每行对应的数据太大可能会碰到一些问题;
主键有索引,不支持二级索引(Secondary indexes);
多行的事务操作不支持;
关系型数据的一些功能,如外键,不支持;
列和表的名字强制为UTF-8编码,并且最大256字节;
删除一列并不会马上释放空间,需要执行Compaction操作,但是Compaction操作不支持手动执行;
删除表的操作会立刻释放空间。

Impala的稳定性

Impala不适合超长时间的SQL请求;
Impala不支持高并发读写操作,即使Kudu是支持的;
Impala和Hive有部分语法不兼容。

FAQ

Impala支持高并发读写吗?

不支持。虽然Impala设计为BI-即席查询平台,但是其单个SQL执行代价较高,不支持低延时、高并发场景。

Impala能代替Hive吗?

不能,Impala设计为内存计算模型,其执行效率高,但是稳定性不如Hive,对于长时间执行的SQL请求,Hive仍然是第一选择。

Impala需要多少内存?

类似于Spark,Impala会把数据尽可能的放入内存之中进行计算,虽然内存不够时,Impala会借助磁盘进行计算,但是毫无疑问,内存的大小决定了Impala的执行效率和稳定性。Impala官方建议内存要至少128G以上,并且把80%内存分配给Impala

Impala有Cache吗?

Impala不会对表数据Cache,Impala仅仅会Cache一些表结构等元数据。虽然在实际情况下,同样的query第二次跑可能会更快,但这不是Impala的Cache,这是Linux系统或者底层存储的Cache。

Impala可以添加自定义函数吗?

可以。Impala1.2版本支持的UDFs,不过Impala的UDF添加要比Hive复杂一些。

Impala为什么会这么快?

Impala为速度而生,其在执行效率细节上做了很多优化。在大的方面,相比Hive,Impala并没有采用MapReduce作为计算模型,MapReduce是个伟大的发明,解决了很多分布式计算问题,但是很遗憾,MapReduce并不是为SQL而设计的。SQL在转换成MapReduce计算原语时,往往需要多层迭代,数据需要较多的落地次数,造成了极大地浪费。

Impala会尽可能的把数据缓存在内存中,这样数据不落地即可完成SQL查询,相比MapReduce每一轮迭代都落地的设计,效率得到极大提升。
Impala的常驻进程避免了MapReduce启动开销,MapReduce任务的启动开销对于即席查询是个灾难。
Impala专为SQL而设计,可以避免每次都把任务分解成Mapper和Reducer,减少了迭代的次数,避免了不必要的Shuffle和Sort。
同时Impala现代化的计算框架,能够更好的利用现代的高性能服务器。

Impala利用LLVM生成动态执行的代码

Impala会尽可能的利用硬件配置,包括SSE4.1指令集去预取数据等等。
Impala会自己控制协调磁盘IO,会精细的控制每个磁盘的吞吐,使得总体吞吐最大化。
在代码效率层面上,Impala采用C语言完成,并且追求语言细节,包括内联函数、内循环展开等提速技术
在程序内存使用上,Impala利用C的天然优势,内存占用比JVM系语言小太多,在代码细节层面上也遵循着极少内存使用原则,这使得可以空余出更多的内存给数据缓存。
Kudu相比Hbase有何优势,为什么?
Kudu在某些特性上和Hbase很相似,难免会放在一起比较。然而Kudu和Hbase有如下两点本质不同。

Kudu的数据模型更像是传统的关系型数据库,Hbase是完全的no-sql设计,一切皆是字节。
Kudu的磁盘存储模型是真正的列式存储,Kudu的存储结构设计和Hbase区别很大。
综合而言,纯粹的OLTP请求比较适合Hbase,OLTP与OLAP结合的请求适合Kudu。
Kudu是纯内存数据库吗?
Kudu不是纯内存数据库,Kudu的数据块分MemRowSet和DiskRowSet,大部分数据存储在磁盘上。

Kudu拥有自己的存储格式还是沿用Parquet的?

Kudu的内存存储采用的是行存储,磁盘存储是列存储,其格式和Parquet很相似,部分不相同的部分是为了支持随机读写请求。

compactions需要手动操作吗?

compactions被设计为Kudu自动后台执行,并且是缓慢分块执行,当前不支持手动操作。

Kudu支持过期自动删除吗?

不支持。Hbase支持该特性。

Kudu有和Hbase一样的局部热点问题吗?

现代的分布式存储设计往往会把数据按主键进行有序存储。这样会造成一些局部的热点访问,比如把时间作为主键的日志实时存储模型中,日志的写入总是在时间排序的最后,这在Hbase中会造成严重的局部热点。Kudu也有同样的问题,但是比Hbase好很多,Kudu支持hash分片,数据的写入会先按照hash找到对应的tablet,再按主键有序的写入。

Kudu在CAP理论中的位置?

和Hbase一样,Kudu是CAP中的CP。只要一个客户端写入数据成功,其他客户端读到的数据都是一致的,如果发生宕机,数据的写入会有一定的延时。

Kudu支持多个索引吗?

不支持,Kudu只支持Primary Key一个索引,但是可以把Primary Key设置为包含多列。自动增加的索引、多索引支持、外键等传统数据库支持的特性Kudu正在设计和开发中。

Kudu对事务的支持如何?

Kudu不支持多行的事务操作,不支持回滚事务,不过Kudu可以保证单行操作的原子性。

字段类型对比

Kudu - 图1

安装client

  1. rpm -i http://archive.cloudera.com/kudu/redhat/6/x86_64/kudu/5/RPMS/x86_64/kudu-client-devel-1.4.0+cdh5.12.2+0-1.cdh5.12.2.p0.8.el6.x86_64.rpm
  2. rpm -i http://archive.cloudera.com/kudu/redhat/6/x86_64/kudu/5/RPMS/x86_64/kudu-client0-1.4.0+cdh5.12.2+0-1.cdh5.12.2.p0.8.el6.x86_64.rpm
  3. yum install gcc
  4. yum install gcc-c++
  5. pip install Cython kudu-python==1.2.0

使用 impala 创建 kudu 表

  • 注意每个表 kudu 分区数量限制,使用 Run Kudu ksck 查看 Replicas ,Tablets 数量

Replicas / kudu服务器数量 要少于 1000,Tablets / kudu服务器数量 要少于 60;

  1. CREATE TABLE IF NOT EXISTS `ylyh__kudu`.`ods__log` (
  2. `v` STRING NOT NULL,
  3. `e` STRING NOT NULL,
  4. `dt` STRING NOT NULL,
  5. `server` STRING NOT NULL,
  6. `id` STRING NOT NULL,
  7. `log_time` STRING,
  8. `log_type` BIGINT,
  9. `log_tag` BIGINT,
  10. `log_user` BIGINT,
  11. `log_name` STRING,
  12. `log_server` BIGINT,
  13. `log_level` BIGINT,
  14. `log_previous` STRING,
  15. `log_now` STRING,
  16. `log_relate` STRING,
  17. `f1` STRING,
  18. `f2` STRING,
  19. `f3` STRING,
  20. `f4` STRING,
  21. `f5` STRING,
  22. `f6` STRING,
  23. `f7` STRING,
  24. `f8` BIGINT,
  25. `log_channel` STRING,
  26. `log_data` BIGINT,
  27. `log_result` BIGINT,
  28. PRIMARY KEY (`v`,`e`,`dt`,`server`,`id`)
  29. )
  30. PARTITION BY
  31. HASH (`v`) PARTITIONS 4,
  32. HASH (`e`) PARTITIONS 7,
  33. HASH (`server`,`id`) PARTITIONS 10
  34. ,
  35. RANGE(dt)(
  36. PARTITION VALUES < '2020-02-23',
  37. PARTITION '2100-01-01' < VALUES
  38. )
  39. STORED AS KUDU
  40. TBLPROPERTIES ('kudu.master_addresses'='kudu_master1:7051,kudu_master2:7051,kudu_master3:7051');

优化表

  1. COMPUTE INCREMENTAL STATS [table]

写入优化

  1. set batch_size=10000;

Kudu TabletServer服务器断电无法启动

1.问题
Kudu TabletServer服务器正常大量写入时,服务器异常重启,会造成TabletServer的metadata的文件数据不完整功能,再次启动TabletServer会报如下错误:

  1. Check failed: _s.ok() Bad status: Corruption: Failed to load FS layout: Could not process records in container /data1/bigdata/kudu/tablet/data/data/b77918da73e342b4940f64c557ea0f61: Data length checksum does not match: Incorrect checksum in file /data1/bigdata/kudu/tablet/data/data/b77918da73e342b4940f64c557ea0f61.metadata at offset 634685: Checksum does not match. Expected: 0. Actual: 1214729159

2.解决办法
根据启动报错日志获取和报错日志文件一致的所有元数据文件,删除元数据文件的最后一行记录,然后启动Kudu TabletServer服务,观察是否还有此类似报错,有再处理,直到服务启动为止

  1. # 创建元数据备份目录
  2. mkdir /data1/backup/data1
  3. # 根据kudu日志进入报错的相应元数据目录
  4. cd /data1/bigdata/kudu/tablet/data/data/
  5. # 备份元数据
  6. cp -arpf ./*.metadata /data1/backup/data1
  7. # 一般和此文件最后一次修改时间相同的目录都会有问题,先获取日志报错文件的最后修改时间
  8. ls -l --full-time b77918da73e342b4940f64c557ea0f61.metadata
  9. 输出信息
  10. -rw------- 1 kudu kudu 7717519360 2019-07-10 13:16:07.662511306 +0800 b77918da73e342b4940f64c557ea0f61.metadata
  11. 1
  12. # 删除所有和b77918da73e342b4940f64c557ea0f61.metadata元数据文件最后一次修改时间相同的文件的最后一行记录
  13. for i in `ls -l --full-time |grep '2019-07-10 13:16:07.662511306 +0800'|grep '.metadata' | awk {'print $9'}`; do sed -i '$d' $i; done

通过CM页面启动Kudu TabletServer服务
通过WebUI检查该Kudu TabletServer表情况,有可能存在表状态为FAILED的情况,副本数为3的表会从其他节点行copy过来

移除服务器

这时如果想要把这些dead状态的tserver去掉,并没有直接的命令,官方给出的方法如下:

  1. Kudu does not currently have an automated way to remove a tablet server from a cluster permanently. Instead, use the following steps:
  2. 1 Ensure the cluster is in good health using ksck. See Checking Cluster Health with ksck.
  3.   首先保证集群是健康的(通过ksck命令)
  4. 2 If the tablet server contains any replicas of tables with replication factor 1, these replicas must be manually moved off the tablet server prior to shutting it down. The kudu tablet change_config move_replica tool can be used for this.
  5.   dead状态的server上的副本进行迁移,如果有replication factor设置为1的数据,必须在下线前手工移动数据;
  6. 3 Shut down the tablet server. After -follower_unavailable_considered_failed_sec, which defaults to 5 minutes, Kudu will begin to re-replicate the tablet servers replicas to other servers. Wait until the process is finished. Progress can be monitored using ksck.
  7.   只要tserver处于下线状态超过5分钟以上会自动进行副本迁移;
  8. 4 Once all the copies are complete, ksck will continue to report the tablet server as unavailable. The cluster will otherwise operate fine without the tablet server. To completely remove it from the cluster so ksck shows the cluster as completely healthy, restart the masters. In the case of a single master, this will cause cluster downtime. With multimaster, restart the masters in sequence to avoid cluster downtime.
  9.   当所有副本都迁移完之后,ksck依然会显示有tserver不可用,如果想完全去掉这些dead状态的server,需要重启master
  10. Do not shut down multiple tablet servers at once. To remove multiple tablet servers from the cluster, follow the above instructions for each tablet server, ensuring that the previous tablet server is removed from the cluster and ksck is healthy before shutting down the next.
  11. 最后,重启master之后在保证集群健康的前提下逐一重启tserver
  • 执行检查命令
  1. sudo -u kudu kudu cluster ksck kudu_master1,kudu_master2,kudu_master3
  1. Tablet 6e7d76ad72994d34849a04f4fc70f61f of table 'impala::ylyh__kudu.ods__log' is unavailable: 2 replica(s) not RUNNING
  2. 9a9ddfc080f74a5090628740b4fa9433: TS unavailable [LEADER]
  3. 97d33c3aa56841e1b9d5d9ba113d3146 (h27:7050): RUNNING
  4. a243f67d9c204385af039500f819e7d3: TS unavailable
  5. All reported replicas are:
  6. A = 9a9ddfc080f74a5090628740b4fa9433
  7. B = 97d33c3aa56841e1b9d5d9ba113d3146
  8. C = a243f67d9c204385af039500f819e7d3
  9. The consensus matrix is:
  10. Config source | Replicas | Current term | Config index | Committed?
  11. ---------------+------------------------+--------------+--------------+------------
  12. master | A* B C | | | Yes
  13. A | [config not available] | | |
  14. B | [config not available] | | |
  15. C | [config not available] | | |

可用的副本可能存在同步延迟会丢失部分数据,这时如果已经确定leader副本不可恢复,则可以强制指定剩下的可用副本为leader,恢复tablet到健康状态;

The remaining replica is not the leader, so the leader replica failed as well. This means the chance of data loss is higher since the remaining replica on tserver-00 may have been lagging.

  1. $ sudo -u kudu kudu remote_replica unsafe_change_config h27:7050 <tablet-id> <tserver-00-uuid>
  2. where <tablet-id> is e822cab6c0584bc0858219d1539a17e6 and <tserver-00-uuid> is the uuid of tserver-00,638a20403e3e4ae3b55d4d07d920e6de.
  3. 事例:
  4. sudo -u kudu kudu remote_replica unsafe_change_config h27:7050 6e7d76ad72994d34849a04f4fc70f61f 97d33c3aa56841e1b9d5d9ba113d3146
  5. <tablet-id>为非健康的tablettserver-00:7150为可用副本所在的tserver,<tserver-00-uuid>为可用副本所在的tserveruuid,这样就可以在可能丢失少量数据的情况下恢复tablet
  6. 如果有问题的tablet非常多,可以参考如下命令:
  7. $ kudu cluster ksck localhost|grep -e '^Tablet '|awk '{print $2}'|xargs -i echo "sudo -u kudu kudu remote_replica unsafe_change_config tserver-00:7150 {} <tserver-00-uuid>"

参考:

优化

kudu表最好不要做任何压缩,保证原始扫描性能发挥最好;假如对查询性能要求比存储要求高的话;大部分企业对实时查询效率要求高,而且存储成本毕竟低;

kudu针对大表要做好分区,最好range和hash一起使用,前提是主键列包含能hash的id,但range分区一定要做好,经验告诉我一般是基于时间;

常用sql

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

kudu的DDL语句: 对字段来说只能添加列、删除列、重命名列名;对字表来说只能删除表、重命名表名。不能修改字段类型,不能对主键进行修改。

  • 删除表
    1. drop table tb_name;

如果在impala中,表是外部表,其实并没有真正的删掉,要彻底删除:

  1. # kudu 查表的语法
  2. kudu table list kudu_master1,kudu_master2,kudu_master3
  3. kudu 删表的语法 kudu table delete master(master的主机名) 表名
  4. kudu table delete kudu_master1,kudu_master2,kudu_master3
  • 增加分区
    ALTER TABLE ${var:DB_WRITE}.temp__analysis__user_kudu ADD IF NOT EXISTS RANGE PARTITION VALUE = ‘${var:DT_add1}’;
  • 删除分区
    ALTER TABLE ${var:DB_WRITE}.temp__analysis__user_kudu DROP IF EXISTS RANGE PARTITION VALUE = ‘${var:DT2}’;
  • 重命名
    ALTER TABLE kudu_PERSON RENAME TO my_new_table;
    使用该ALTER TABLE … RENAME语句重命名表仅重命名Impala映射表,而不管该表是内部还是外部表。这样可以避免可能访问基础的Kudu表的其他应用程序的中断。
    重新命名内部表的基础Kudu表

    1. ALTER TABLE my_internal_table
    2. SET TBLPROPERTIES('kudu.table_name' = 'new_name')
  • 更新值
    ``` UPDATE 表名称 SET 列名称=新值[,列名称=新值] WHERE 列名称 = 某值

UPDATE ylyhdata.edsplayer_kudu SET is_roll_server = false, is_tiny_account = false WHERE v=’cn’ and server=’1’;

  1. - 添加列(不推荐,可能异常, 特别大表)

alter TABLE tb_name add columns(col_name string COMMENT ‘描述’);

  1. - 删除列

ALTER table tb_name drop column col_name;

  1. - 删除行

DELETE FROM tb_name WHERE id = 3;

  1. - Change the Kudu Master Address

ALTER TABLE my_table SET TBLPROPERTIES(‘kudu.master_addresses’ = ‘kudu-new-master.example.com:7051’);

  1. - 将内部管理的表更改为外部

ALTER TABLE my_table SET TBLPROPERTIES(‘EXTERNAL’ = ‘TRUE’);

  1. - 重新映射外部表,指向不同的kudu

ALTER TABLE external_table SET TBLPROPERTIES(‘kudu.table_name’ = ‘hashTable’) ```