要好好使用 Impala 就得好好梳理一下他得结构以及他存在得一些问题或者需要注意得地方。本系列博客主要想记录一下对 Impala 架构梳理以及使用上的 workaround。
Impala 简介
首先我们来了解一下在 Impala Guide 中 Impala 对自己的定位
Impala is an addition to tools available for querying big data. Impala does not replace the batch processing frameworks built on MapReduce such as Hive. Hive and other frameworks built on MapReduce are best suited for long running batch jobs, such as those involving batch processing of Extract, Transform, and Load (ETL) type jobs.
Impala 认为自己是大数据查询工具的补充,对于长时间的 batch work 还是推荐使用基于 mapreduce 的方式来处理超大量数据。因为那更稳定可靠。
Impala 目前已经从 Apache 孵化项目中毕业,由 Cloudera 公司捐赠后 Impala 由 Cloudera Impala => Apache Impala
Impala 架构部分
Impala 守护进程(Impala Daemon)
Impala 的核心组件一个守护进程,运行在集群的每个数据节点上,它是一个叫 impalad 的进程负责读取和写入数据文件。接受从impala-shell传递过来的命令,Hue、JDBC或ODBC传输过来的查询;并行化查询请求并在整个集群中分配工作;将中间查询结果传输回中央协调器节点。
注意上面我 CDH 上运行的跟 impala 相关的实例,我只在一个计算节点上启动了 impala daemon,所以说我要使用 hue 或者 impala 请求该节点来构建查询和返回结果。
如果有多个 impala daemon ,那么我可以向任意有 impala daemon 节点上提交任务。该实例将作为该查询协调节点。其他节点将部分查询结果返回协调节点,它将构建最终的结果集。
Impala 状态存储进程(Impala StateStore)
被称为 StateStore 的 Impala 组件负责检查集群中的所有数据节点上的 Impala Daemon 的健康状况,并不断的将结果转发给每个 Impala Daemon。它是一个名为 StateStored 的守护进程。而且只需要在集群中某一个主机上运行该进程即可。如果一个 Impala Daemon 失败或者脱机卡斯,那么 StateStored 会复杂同志其他守护进程,来避免后来的查询请求被发送到一些无效的节点。
StateStore 是被设计用来当 daemon 进程刮了之后将消息广播至协调者的,它对 Impala 集群的正常运行没有那么重要,如果这玩意失效了,只要守护进程还在继续运行,那么整个集群的 Impala 工作还是可以继续开展。但是 StateStore 由于会用来维护健康状况等信息,所以当它失效之后集群将会变得没有那么强健。包括 metadata 在内的变动在 StateStore 失效的时候是无法保持一致的。而当我们回复 StateStore 的正常运行之后,它会重新和 Impala daemons 建立连接和监控,然后重新运行广播函数等。同样的,当 StateStore 挂了的时候,我们进行一些对表的 DDL 操作可能会失败,这和上面 metadata 无法被广播更新有一定关系。
负载平衡和高可用性的大多数考虑都适用于 Impala 守护进程。StateStored 和 Catalogd 守护进程对高可用性没有特殊要求,因为这些守护进程的问题不会导致数据丢失。如果这些守护进程由于某个主机的中断而不可用,我们立即停止这台机器上的 Impala 服务并且删除 Impala StateStore 和 Impala Catelog Server,然后在另一个主机上添加这些角色,并重新启动Impala服务即可。
Impala 目录服务进程(Impala Catalog Service)
被称为目录服务的 Impala Catalog Service 组件,维护着从 Impala SQL 语句到集群中的所有 Impala 守护进程需要用到的元数据,它是一个名为 Catalogd 的守护进程,只需要在集群中的某个主机上执行这个进程即可。因为请求是通过 StateStore 进行传递的,所以如果 StateStored 和 catalogd 两个服务在一个机器上会比较不错。
这个进程涉及一系列关于 Impala 的功能:
有 Catalog Service 之后当我们通过 Impala 使用 CREATE TABLE, INSERT, 或者其他对表进行 DDL 操作的时候我们不需要进行 Refresh 和 INVALIDATE METADATA 申明了。而如果这些 DDL 是通过 Hive 或者 直接在 HDFS 中操作数据文件来完成的,那么我们在查询的时候就必须提前执行一下以上命令。
这里我要多说一句,我们经常有这种场景,就是晚上我们会通过 DATAX 或者 Sqoop 对表进行同步或者建立新的分区然后刷入数据,其实 Impala 是无法获取这些新的信息的,所以当我们无论是使用 HUE 还是接口去访问 Impala 的时候都无法查询到这些新的数据,这个时候我们就需要 Refresh 一下新的表,或者直接使用 INVALIDATE METADATA 对元数据进行重建。就可以看到这些新的表和数据了,这里要注意。
无论在 HUE 上执行还是代码里面直接获取 Impala cursor 直接执行相关命令
impala_cursor.execute("refresh {}".format(table))
impala_cursor.execute("INVALIDATE METADATA {}".format(table))
都可以刷新元数据,在一个地方执行之后所有节点都会同步,就能使用 Impala 查找到直接修改文件生成的数据了。
使用 --load_catalog_in_background 选项可以控制 Impala 在何时进行 metadata 的 load。
CDH 里面也有这个选项
默认是 False.
如果设置成 False 这个关于表级别的 metadata 被加载是在第一次对表引用的时候。这意味着第一次跑某些 query 的时候可能要比已经加载过 metadata 的时候要慢一些。从 Impala2.2 开始这个选项就默认是 False 了。
如果我们设置成 True 这个 Catalog Service 会尝试为所有表去加载 metadata,即使这个查询不需要重新加载某个表的 metadata。现在这个选项不建议被设置成 True 因为以下原因。。。
1. 从后台去加载 metadata 可能会干扰指定的 metadata 加载,这种情况可能在启动的时候发生,也可能在失效的时候发生,持续事件取决于元数据数量,并且可能导致随机的长时间运行查询,这些耗时的查询很难被诊断出来是为啥。。。说到底就是可能引起一些奇怪的 bug ,不如需要的话手动自己刷。
2. Impala 开启这个会去加载很多自己用不到的元数据导致数据膨胀。这可能会增加目录大小,从而增加目录服务和守护进程的内存使用量。总之就是不要开。
负载平衡和高可用性的大多数考虑因素都适用于 Impalad。StateStored 和 Catalogd 对高可用性没有特殊的要求,因为这些守护进程的问题不会导致数据丢失。如果这些守护进程由于特定主机的宕机而变得不可用,您可以停止Impala服务,删除Impala状态存储和Impala目录服务器角色,在不同的主机上添加角色,并重新启动Impala服务。
Impala 性能调优
1. 文件格式上,与基于文本的文件格式相比,使用二进制的文件格式将会获得更好的性能。最好能将密集查询的或者很大的表使用二进制格式存储例如使用 Parquet | Avro。Parquet 是最被推荐的数据仓库查询格式(。。。一家开发的可能优化得更好吧)。虽然 Impala 在文本格式上也能顺利执行查询例如 RCFILE SequenceFile 等格式,但是基于行存储的他们并不会的到查询上的优化。并且 Impala 也不支持在类似文件格式上进行 INSERT 操作。
2. 在可行的地方使用 Snappy 压缩,他的解压消耗很小并且可以给我们带来非常多的空间节省。
3. 在 Strings 和 numeric 的类型选择上选择 numeric。主要还是在空间节省上面的优化。
4. 可以分区,但是不要对数据进行过度分区以保证高效的数据处理能力,主要碎片大小。如果一个核心可以处理一个文件的话,可以拆出更多的文件,如将 256M 的块拆成两个使其得到并行处理,最大程度将 cpu 利用起来。其实我觉得这一点都控制得太细了。可能只有很高频的表值得如此进行细粒度的优化。
5. 在我们 Loading data 之后总是使用 compute stats 命令计算表的统计结果。当我们同步表或者 Loading 数据之后 Impala 的 stats 处于懵逼的状态,包括不知道数据有多少行,不知道数据是否被改变。然而 Impala 又广泛的使用了 stats 特性包括表中列统计信息以帮助其计算一些资源密集型的操作比如 join insert into partition 操作。因为信息只在 loading 数据之后可用,所以我们可以在增加分区、加载替换数据之后执行 compute stats 帮助该表建立自己的 stats 用于优化数据查询。
举个栗子:
我们有很多周期性任务,每隔一段事件会将 OLTP 的数据表通过 Sqoop 导上集群。
可以看到我们现在并没有 rows 的信息。
我们来执行一下最典型的 count(*) 操作需要时间。因为有 2.28gb 所以花费了近 10s。然后我们清理一下缓存执行
compute stats analytics_db.hd_new_yanzhi_record
再执行查看 stats 命令可以看到
统计概要已经有该文件的条数,我们再执行 count 操作类似的操作就可以秒出结果。
这只是我举例说明的一个非常小的点,使用 compute stats 还将获得 join 等操作的性能提升,我们都知道 join 的时候表的左右关系也十分影响性能,这有助于帮我们找到小表作为驱动表进行优化。所以当我们 loading 数据之后计算一下 stats 吧。
需要多提一点的是 Cloudera 的官方文档给到这里一点补充,还有一个计算增量 stats 的命令
COMPUTE INCREMENTAL STATS
这两个命令不要混用,如果使用其中一个请一直使用下去,他们的不同其实仅仅在如果你针对一个超级大表直接计算全表 stats 可能需要耗费非常多时间。
但是你使用 incremental stats 可以只计算分区信息。
如果我们要换用 可以先使用
DROP INCREMENTAL STATS
然后再进行正常计算,切记不要混用!
6. 使用 EXPLAIN AND SUMMARY 命令来查看自己的执行计划,和执行之后的 profile 。这个大家自己去探索吧,Impala 给到的执行计划还是比较多信息的,包括会提醒你涉及表是否进行过 stats 的计算,如果没有提醒你去计算以提升执行性能和优化程度。Summary 只能使用在 Impala-shell 中,用于在执行完 DML 操作之后查看运行详情。如果想要更多详情还可以使用 profile 命令获得更详细的信息。
Reference:
https://zhuanlan.zhihu.com/p/77463503 Apache Impala概念和架构
https://impala.apache.org/docs/build/impala-3.2.pdf Apache Impala Guide
https://impala.apache.org/impala-docs.html Apache Impala Doc
https://docs.cloudera.com/documentation/enterprise/5-14-x/topics/impala_compute_stats.html impala_compute_stats
https://zhuanlan.zhihu.com/p/80354571