Cloudera Impala 常见问题
下面是 Clouder Impala 产品常见问题的目录。
继续阅读:
Trying Impala
如何实验 Cloudera Impala?
想要试试 Impala 的核心特性和功能,最简便的实验 Impala 的方法就是下载 Cloudera QuickStart VM 并通过 Cloudera Manager 启动 Impala 服务,然后在终端窗口使用 impala-shell,或者在Hue web 接口中使用 Impala Query UI。
想要在集群中测试 Impala 的性能并实验管理特性,你需要超越 QuickStart VM 和它的虚拟化的单节点环境。理想情况下,下载 Cloudera Manager 软件来设置集群,然后通过 Cloudera Manager 安装 Impala。
Cloudera 是否提供演示 Impala 的 VM 环境?
Cloudera 提供演示 VM 环境 QuickStart VM,包含 VMWare, VirtualBox, KVM 三种格式。更多信息,参见 the Cloudera QuickStart VM。启动 QuickStart VM 后,其中许多服务默认是关闭的;在自动出现的 Cloudera Manager UI 中,启用 Impala 和其他你想要实验的组件
在哪里可以了解到更多的 Impala 的信息?
这里有更多 Impala 产品的信息:
- O'Reilly e-book: Cloudera Impala: Bringing the SQL and Hadoop Worlds Together
- Blog: Cloudera Impala: Real-Time Queries in Apache Hadoop, For Real
- Webinar: Introduction to Impala
- Product website page: Cloudera Enterprise RTQ
在 Cloudera Announcements 论坛查看最新的 Impala 公告。
在哪里提问和提交 Impala 的反馈?
- 请加入 Impala discussion forum 和 Impala mailing list 来提问与反馈
- 使用 Impala Jira project 来记录 bug 报告和功能需求
在哪里可以下载样例数据进行测试?
你可以在 this Github repository 获得生成数据文件并设置 TPC-DS 类型基准测试环境的脚本。除了可以用于性能试验外,这些表也适用于测试 Impala SQL 的许多方面:他们包含了各种数据类型、数据分布、分区、以及适合连接查询的关系数据。
Impala System Requirements
运行 Impala 有什么软硬件方面的需求?
关于 Impala 的需求,参见 Cloudera Impala Requirements。需要注意的是,对于给定版本的 Impala,通常有一个最小支持的 Clouder Manager 版本。
需要多少内存?
尽管 Impala 不是内存数据库,当处理大的表和大的结果集时,你应当期待为 impalad 守护进程分配大量的物理内存(you should expect to dedicate a substantial portion of physical memory for the impalad daemon)。推荐 Impala 节点具有至少 128 GB 内存。Impala 操作所需的内存依赖于几个因素:
- 表的文件格式。相同的数据,采用不同的文件格式,数据文件个数也不同。为了分析数据,根据每个文件所采用的压缩和编码格式的不同,可能需要不同数据量的临时内存来进行解压(The compression and encoding for each file format might require a different amount of temporary memory to decompress the data for analysis)
- 是否为 SELECT 或 INSERT 操作。例如,查询 Parquet 表时需要相对较少的内存,因为 Impala 以 8MB /块来进行读取和解压缩数据。而向 Parquet 表插入数据则是内存密集型操作,因为每一个数据文件(最大大小为 1GB)的数据被放在内存中,直到编码、压缩并写入硬盘
- 表是否为分区表,并且针对分区表的查询是否可以从分区修剪(partition pruning)中受益
- 最终的结果集是否使用 ORDER BY 子句来排序。请记住,Impala 要求所有包含的 ORDER BY 子句的查询同时包含 LIMIT 子句,或者在语句中直接包含,或者隐式的通过 DEFAULT_ORDER_BY_LIMIT 查询选项设置来实现。每一个 Impala 节点扫描并过滤总数据的一部分,并且对他们自己那部分数据应用 LIMIT。中间结果集 (包含最大 LIMIT 行记录)都发送回协调节点,在上面执行最终的排序并对最终结果集应用 LIMIT 子句。例如,假如你执行查询:
并且你的集群有 50 个节点,然后这 50 个节点每个节点将传递最多 1000 行记录给协调节点。协调节点需要足够的内存进行排序(LIMIT *集群节点数) ,尽管这时最终的结果集最多返回 1000 行。select * from giant_table order by some_column limit 1000;
- 结果集的大小。当中间结果集在节点之间传输时,传输数据的数量依赖于查询返回列的数量。例如,在结果集中只返回实际所需列的查询比总是使用 SELECT * 的查询消耗更少的内存
- 连接查询工作如何拆分的机制
如何 Impala 节点在处理中间结果集时超出了预留给 Impala 内存的限制,目前 Impala 不支持"溢出的硬盘(spill to disk)"。假如这对你的情况来说是个问题(例如连接两个非常大的表时),更多内存是有益的。
参见 Hardware Requirements 了解更详细的信息以及 Impala 硬件方面的先决条件。
Cloudera 推荐哪种处理器?
Impala 使用 SSE4.2 指令。对应 Intel 的 Nehalem+ 芯片和 AMD 的 Bulldozer+ 芯片。Impala 可以在较老的机器上正常运行,但无法达到最佳性能。
Supported and Unsupported Functionality In Impala
Impala 支持下列功能:
- SQL 和 HiveQL 命令的一个大的子集,包括 SELECT 、 INSERT 、joins。更多信息,参见 Impala SQL Language Reference.
- 使用 Cloudera Manager 管理 Impala。请使用 Cloudera Manager 4.6 及以上版本,你可以部署和管理你的 Impala 服务。在集群中使用 Impala ,使用 Cloudera Manager 是最佳入门方式。 更多信息,参见 Cloudera Manager Installation Guide 中使用 Cloudera Manager 安装 Impala 的主题
- 使用 Hue 进行查询
- 通过 INSERT 语句向表中追加和插入数据。参见 How Impala Works with Hadoop File Formats 了解关于哪种文件格式的哪些操作可以支持的详细信息
- ODBC: Impala 是认证支持 MicroStrategy 和 Tableau的,但是有一些限制。更多信息,参见 Configuring Impala to Work with ODBC.
- 在单个查询中同时查询 HDFS 和 HBase 中的数据。参见 Using Impala to Query HBase Tables 了解详细信息
- 并发客户端请求。每一个 Impala 守护进程可以处理多并发客户端请求。对性能的影响依赖于你特定的硬件和负载
- Kerberos 认证。更多信息参见 Impala Security.
- 分区。在 Impala SQL 中,你可以使用 CREATE TABLE 语句创建分区表,使用 ALTER TABLE 语句添加、删除分区。Impala 同样会从之前 Hive 中的分区表。参见 Partitioning 了解详细信息
Impala 不支持下列功能:
- 流数据查询(Querying streaming data)
- 删除个别行。你可以通过覆盖整个表或分区、或删除表来批量删除数据
- 索引(暂不支持)。像在 Using LZO-Compressed Text Files 中描述的那样,LZO 压缩文本文件可以在 Impala 之外进行索引
- 文本字段的全文检索。这时候请使用 Cloudera Search 产品
- 自定义 Hive 序列化/反序列化(Serializer/Deserializer) 类(SerDes)。Impala 支持一组通用的本地文件格式,在 CDH 中有对应的内置的 SerDes。参见 How Impala Works with Hadoop File Formats 了解详细信息
- 运行中查询的故障转移。假如运行查询的任意主机失败,目前来说 Impala 是取消所运行的查询。当一个或多个主机下线,Impala 会重新路由之后的查询并只使用可用的主机,当主机重新上线时 Impala 可以检测到,并重新使用它们。因为查询可以通过任意 Impala 节点提交,所以不会出现单点故障。将来我们会为 Impala 添加额外的工作分配功能,这样即使出现主机失败也会完成整个查询
- Impala 守护进程之间的加密数据传输
- 窗口函数(Window functions)
- Hive 索引
- 非 Hadoop 数据源,如关系数据库
关于更详细的不支持的 HiveQL 特性列表,参见 SQL Differences Between Impala and Hive。
Impala 是否支持通用 JDBC?
Impala 支持 HiveServer2 JDBC 驱动。
是否支持 Avro?
是的,支持 Avro。Impala 可以查询 Avro 表。但目前你必须在 Hive 中创建表并加载数据。参见 Using the Avro File Format with Impala Tables 了解详细信息。
What's next for Cloudera Impala?
How do I?
如何避免用户看到 SQL 查询的内容?
关于如何设置 Impala 日志对未授权的用户不可读的介绍,参见 Securing Impala Data and Log Files.
关于web 接口对 Impala 日志文件和其他内部服务器信息的密码保护(For instructions on password-protecting the web interface to the Impala log files and other internal server information),参见 Securing the Impala Web User Interface。
如何知道集群中有多少 Impala 节点?
Impala statestore 会跟踪当前有多少 impalad 节点可用。你可以通过 statestore 的 web 接口看到这些信息。例如,在 http://statestore_host:25010/metrics 你可以看到类似下面的行:
statestore.live-backends:3
statestore.live-backends.list:[host1:22000,host1:26000,host2:22000]
其中 impalad 节点的个数是列出的对象中使用 22000 端口的对象的个数,这里是 2 个(通常这个数值比 statestore.live-backends 报告的数值少一)。假如一个 impalad 不可用,经过停机后恢复正常,那本页报告的信息会对应的修改。
Impala Performance
查询结果是一可用就返回还是等查询完成后一次全部返回?
Impala 尽可能的一有结果就输出来。特定的 SQL 操作(聚合函数或排序操作) 需要所有的结果都准备好才可以返回。
为什么我的查询运行缓慢?
一个查询运行的慢可能有许多原因。使用下面的列表,诊断已有查询性能问题,在写新的查询时避免出现这些问题,配置新的节点,创建新的表,或者加载数据。
- 在查询完成之后,在 impala-shell 中立即执行 PROFILE 命令。对于指定的节点,其中 BytesRead、BytesReadLocal、BytesReadShortCircuit 的值应当一致。例如:
假如 BytesReadLocal 低于 BytesRead,你集群中的一些配置可能错了, 例如 impalad 守护进程没有在全部数据节点上都运行。假如 BytesReadShortCircuit 低于 BytesRead,这一节点上可能没有启用 short-circuit 读;参见 Post-Installation Configuration for Impala 了解相关信息- BytesRead: 180.33 MB - BytesReadLocal: 180.33 MB - BytesReadShortCircuit: 180.33 MB
- 假如表刚刚创建,或者是在 INVALIDATE METADATA 语句之后或者 impalad 守护进程刚刚重启之后第一次访问这个表,当表元数据被加载和缓存时,可能有一些延迟。请检查再次执行查询时候放缓是否消失。在进行性能对比时,考虑先对每一个表执行一个 DESCRIBE table_name 语句,以确保所有的计时都只记录了实际的查询时间而不是包含加载表元数据的一次性等待
- 表数据使用的是未压缩的文本格式?请使用 DESCRIBE FORMATTED table_name 语句检查。文本文件表使用下面的语句标识:
尽管对于不包含 STORED AS 子句的 CREATE TABLE 语句,默认使用未压缩的文本文件格式,但它是占用硬盘空间最大的格式,所以也是查询最慢的格式。对于查询性能很关键的数据,特别是频繁查询的表,请考虑开始或转换成紧凑的二进制文件格式,如Parquet 、Avro、RCFile、SequenceFile。详细信息,参见 How Impala Works with Hadoop File FormatsInputFormat: org.apache.hadoop.mapred.TextInputFormat
- 假如你的表有非常多的列,但是查询仅涉及其中少量的列,请考虑使用 Parquet 文件格式。它的数据文件被组织成面向列(column-oriented)的布局, 可以让检索、过滤和汇总特定列的值的 I/O 需求量最小化。参见 Using the Parquet File Format with Impala Tables 了解详细信息
- 假如你的查询涉及到很多连接,这些表是正确的顺序吗,以便返回最多行的表或子查询放在最左侧(If your query involves any joins, are the tables in the query ordered so that the tables or subqueries are ordered with the ones returning the largest number of rows on the left)? 这一顺序允许 Impala 优化节点之间如何分布工作,以及中间结果集如何从一个节点向另外一个节点路由。例如,其他部分都相同,下面连接顺序的查询是高效的查询:
参见 Performance Considerations for Join Queries 了解连接查询的性能提示select some_col from huge_table join big_table join medium_table join small_table where huge_table.id = big_table.id and big_table.id = medium_table.id and medium_table.id = small_table.id;
- 同样对于连接查询,在你的连接子句中使用的表、列是否都有统计信息?列统计信息让 Impala 更好的选择如何为连接查询的各个部分分配工作。参见 How Impala Uses Statistics for Query Optimization 了解采集统计信息的详细信息
- 你的表是否由大量的小数据文件组成?Impala 对大数据文件更高效(Impala works most efficiently with data files in the multi-megabyte range);Parquet 是一种专为数据仓库类的查询优化的文件格式,采用 1GB 的文件和 1GB 块大小。在 impala-shell 中使用 DESCRIBE FORMATTED table_name 语句来查看表的数据位置,并使用 hadoop fs -ls 或 hdfs dfs -ls Unix 命令查看文件以及大小。假如你有成千上万个小数据文件,这就是你应当合并成更少的大数据文件的信号。使用 INSERT ... SELECT 语句复制数据到新表,这一过程包含重组到新数据文件的部分。宁可构建大的数据文件并通过 LOAD DATA 或 CREATE EXTERNAL TABLE 语句采用批量的方式导入,也不用采用 INSERT ... VALUES 语句的方式;每一个 INSERT ... VALUES 语句创建一个单独的极小的数据文件。假如你在同一个目录下有成千上万的数据文件,但每一个有几兆大(but each one is megabytes in size,), 考虑使用分区表,以便每一个分区包含较少量的文件。请参阅下面更多的分区说明
- 假如你的数据易于根据时间或地理位置分组,那么你根据对应的列如年、月、和/或日分区了吗?基于特定列的分区表允许查询查询根据这些列过滤,避免读取无关年份、无关邮编等等的数据(不要分区成太细的粒度;分区构建成每个分区下都有足够的数据,以便从 multi-megabyte HDFS block size 中受益)。参见 Partitioning 了解详细信息
为什么我的 SELECT 查询会失败?
当一个 SELECT 语句失败了,原因通常是以下类别之一:
- 因为性能、容量、或网络问题影响了特定的节点导致的超时
- 连接查询的过多内存数用,这一查询的结果会自动取消
- 处理查询中特定的 WHERE 子句时,影响到每一节点上本地代码如何生成的底层问题。例如,特定节点上可能会生成它的处理器不支持的机器指令。假如日志中的错误信息猜测是无效指令(illegal instruction),考虑临时关闭生成本地代码,并重试这个查询
- 异常的输入数据,例如包含一个巨大的长行的文本数据文件(a text data file with an enormously long line),或者使用了没有在 CREATE TABLE 语句中 FIELDS TERMINATED BY 子句中设置的分隔符(or with a delimiter that does not match the character specified in the FIELDS TERMINATED BY clause of the CREATE TABLEstatement)
为什么我的 INSERT 查询会失败?
当 INSERT 语句失败时,通常是因为超出 Hadoop 组件的一些限制,特别是 HDFS。
- 由于可能会在 HDFS 并发打开许多文件和关联的进程,插入到分区表的操作是一个费力(strenuous)操作。Impala 1.1.1 包含了一些改进,以更有效的分发工作,这样每个分区使用一个节点写入值,而不是没一个节点一个单独的数据文件
- INSERT 语句中 SELECT 部分的特定表达式会产生复杂的执行计划,并导致低效的 INSERT 操作。请尽量使源表和目标表中列的数据类型匹配,例如,如果必要,在源表上执行 ALTER TABLE ... REPLACE COLUMNS 语句。请尽量避免在 SELECT 位置使用 CASE 表达式,因为相比保持列不变或通过内置函数转换列,CASE 会导致结果更难预测
- 请做好准备提升你的 HDFS 配置设置中的一些限制,可以临时的在 INSERT 执行时,如果你频繁运行这些 INSERT 语句作为 ETL 管道的一部分,也可以永久修改
- 依赖于目标表的文件格式,INSERT 语句的资源使用可能会变化。插入到 Parquet 表是内存密集型操作,因为每一个分区的数据会缓存到内存里,直到它达到 1G,这时候数据文件才写入到硬盘。当执行 INSERT 语句时候,如果查询中源表的统计信息可用,Impala 可以更高效的分布工作。参见 How Impala Uses Statistics for Query Optimization 了解如何采集统计信息
当部署到集群中更多主机上时, Impala 性能会提升吗?就像 Hadoop 性能那样?
是的。Impala 性能随主机数而扩展(Impala scales with the number of hosts)。在集群中所有数据节点上安装 Impala 很重要,否则的话,一些节点必须进行远程读取以获得本地读取无法获得的数据。对于 Impala 性能来说,数据本地化(Data locality) 是一个重要的架构方面(architectural aspect)。参见 this Impala performance blog post 了解背景信息。请注意这些博客使用 Impala 1.1.1 进行的基准测试;在 Impala 1.2.x 系列中,已经添加了更多性能特性。
减少 HDFS 块大小会实现更快的查询结果吗?
不会。Impala 不会对 HDFS 或 HBase 数据集做任何修改。
默认的 Parquet 块大小已经相当的大(1GB),并且在创建 Parquet 文件时使用 PARQUET_FILE_SIZE 查询选项可以控制块大小。
Impala 使用缓存吗?
Impala 不会缓存数据,但它缓存一些表和文件的元数据。尽管因为数据集被缓存到 OS 的缓冲区中,接下来的重复查询可能运行的更快,Impala 不会明确的控制这些。
Impala Use Cases
什么情况下适合使用 Impala 而不适合 Hive 和 MapReduce?
Impala 非常适合在大的数据集上,为交互式探索分析执行 SQL。Hive 和 MapReduce 则适合长时间运行的、批处理的任务,例如 ETL。
Impala 是否需要 MapReduce ?如果 MapReduce 停了,Impala 是否能正常工作?
Impala 根本用不到 MapReduce。
Impala 是否可以用于复杂事件处理?
例如,在工业环境中,许多客户端可能产生大量的数据。Impala 是否可用与分析这些数据,发现环境中显著的变化?
复杂事件处理(Complex Event Processing,CEP) 通常使用专门的流处理系统处理。Impala 不是流处理系统,它其实更像关系数据库。
Is Impala intended to handle real time queries in low-latency applications or is it for ad hoc queries for the purpose of data exploration?
即席查询(Ad-hoc)是 Impala 的主要使用情况。我们估计它会在许多需要低延迟的环境中使用。Impala 是否适合某个特定的情况依赖于此时的负载、数据大小和查询次数。参见 Impala Benefits 了解使用 Impala 可以获得的主要益处。
Questions about Impala And Hive
Impala 与 Hive 和 Pig 有什么异同?
Impala 与 Hive 和 Pig 不同,因为它使用自己的守护进程,跨集群分布式进行查询。因为 Impala 不依赖于 MapReduce,它避免了 MapReduce 作业的启动开销,让 Impala 能实时返回结果。
我是否可以改变或添加新功能(functionality)?
Impala 1.2 开始支持 UDFs。你可以使用 C++ 写你自己的函数,或者重用已有的基于 Java 的 Hive UDFs。支持的 UDF 包括标量函数和用户定义聚合函数(UDAs)。目前不支持用户定义表函数(UDTFs)。
Impala 目前不支持扩展序列号-反序列化(serialization-deserialization)框架(SerDes),因此为 Impala 添加扩展功能不像 Hive 或 Pig 那么简单。
Impala 中的所有查询都可以在 Hive 中执行吗?
是的。尽管在一些查询如何处理方面有细微的差别,但是 Impala 查询也可以在 Hive 中完成。Impala SQL 是 HiveQL 的子集,有一些功能限制如变换(transforms)。关于具体的 Impala SQL 方言,参见 SQL Statements。关于 Impala 内置函数,参见 Built-in Functions。关于不支持的 HiveQL 特性,参见 SQL Differences Between Impala and Hive。
我可以用 Impala 查询已经在 Hive 和 HBase 加载的数据吗?
允许 Impala 查询 Hive 管理的表,不管它是存放在 HDFS 还是 HBase中,都不需要额外的步骤。请确保已经正确的配置 Impala 访问 Hive metastore,并且你准备好了。请记住,默认的 impalad 使用 impala 用户运行,所以你可能需要调整一些文件的权限,这取决于你目前权限多么严格。
参见 Using Impala to Query HBase Tables 了解查询 HBase 中数据的详细信息。
Impala 是否需要 Hive?
Hive metastore 服务是必需的。Impala 与 Hive 共享同一个 metastore 数据库,透明的允许 Impala 和 Hive 访问相同的表。
Hive 本身是可选的,并且不需要跟 Impala 安装在同一个节点上。相比目前 Impala 支持的写(插入)操作(的文件格式),Impala 支持更多类型的读取(查询)操作;对于使用的特定的文件格式,你应当使用 Hive 向表里插入数据。参见 How Impala Works with Hadoop File Formats 了解详细信息。
Impala Availability
Impala 可以用于生产环境吗?
Impala 已经完成了它的测试版本发布周期,1.0 GA 版本已经为生产环境做好准备。而 1.1.x 系列包括了授权这一新增的安全特性,这是许多组织使用产品的重要需求。一些 Cloudera 客户已经为大的负载使用 Impala。
Impala 1.2.0 版本目前是测试版,因为它使用了许多仅在 CDH 5.0 测试版中可用的特性。随后的与 CDH 4 协同的 1.2.1 和 1.2.2,适用于生产环境 (相比 1.2.1,更推荐 1.2.2,因为 1.2.2 包含了许多针对连接查询的性能优化)。
如何为 Impala 配置 Hadoop 高可用性 (HA)?
你可以设置代理服务器,转发 Impala 服务器来回的请求,以实现负载均衡和高可用性。参见 Using Impala through a Proxy for High Availability 了解详细信息。
你可以为 Hive metastore 启用 HDFS HA。参见 CDH4 High Availability Guide 了解详细信息。
Impala 出现错误时都发生了什么?
Impala 中不会出现单点故障。所有的 Impala 守护进程全都可以处理所接受的查询。假如一台机器出现故障,在这台机器上有查询片段(fragments)在上面运行的查询都会失败。因为查询被期望快速返回的,当查询失败时你可以重新运行失败的查询(Because queries are expected to return quickly, you can just rerun the query if there is a failure)。参见 Impala Concepts and Architecture 了解 Impala 架构的详细信息。
完整回答:Impala 必须能够连接到 Hive metastore。Impala 积极缓存元数据,这样 metastore 主机的负载很小。Impala 依赖于 HDFS NameNode,并且在 CDH 4中你可以为 HDFS 配置 HA。Impala 同样有一个集中的软件状态(soft-state)服务,称作 statestore 和 catalog 服务,仅仅在一台主机上运行。假如 statestore 主机下线,Impala 会继续执行查询,但不会获得状态更新。例如,如果在 statestore 主机下线期间向集群添加了一台主机,运行在其他主机上的已有的 impalad 实例将不会发现这台新的主机。一当 statestore 进程重启后,所有它提供的信息会根据所有运行的 Impala 守护进程自动重建。
Impala 表中最多允许多少行?
没有限制。一些用户已经使用 Impala 查询包含上万亿记录的表。
Impala 和 MapReduce 作业可以在相同集群中运行而不会资源冲突吗?
是的。参见 Controlling Resource Usage 了解如何使用 Linux cgroup 机制控制 Impala 使用的资源,以及 Using YARN Resource Management with Impala (CDH 5 Only) 了解如何使用 Impala 和 YARN 资源管理框架。Impala 被设计为运行在 DataNode 主机上的。任何资源冲突都依赖于集群的配置和负载。
关于详细的如何配置集群在 Impala 查询和 MapReduce 作业之间共享资源的例子,参见 Setting up a Multi-tenant Cluster for Impala and MapReduce
Impala Internals
Impala 应当在哪些主机上运行?
为了更佳的性能,Cloudera 强烈推荐在每一台数据节点(DataNode)上都运行 impalad 守护进程。尽管这一拓扑结构不是硬性要求,假如有任意主机,上面包含了数据块副本但是没有 Impala 守护进程运行,那么涉及到这些数据的查询的效率将非常低下(if there are data blocks with no Impala daemons running on any of the hosts containing replicas of those blocks, queries involving that data could be very inefficient)。这时候,这些数据必须通过"远程读取"从一台主机传输到另外一台主机以进行处理,这是 Impala 应尽量避免的情况。参见 Impala Concepts and Architecture 了解关于 Impala 架构的详细信息。Impala 会尽可能的调度查询分片,以便能在存放对应数据的主机上执行查询(Impala schedules query fragments on all hosts holding data relevant to the query, if possible)。
Impala 中连接如何执行?
默认的,Impala 使用基于成本的方法,根据表的总大小和行数,自动确定最高效的表连接顺序(这是从 Impala 1.2.2 才开始具有的新特性)。使用 COMPUTE STATS 语句采集的每一个表的统计信息是高效连接的关键。Impala 连接查询在两种连接技术之间进行选择,分别是 "广播连接(broadcast joins)" 和 "分割连接(partitioned joins)"。参见 Joins 了解语法详情,参见 Performance Considerations for Join Queries 了解性能注意事项。
Impala 如何处理大表的连接查询?
Impala 采用多种策略,允许不同大小的表和结果集进行连接。当一个大表与一个小表连接时,小表中的所有数据会传输到每一节点上以进行中间处理。当连接两个大表时,其中一个表的数据被拆分成多块,每一个节点只处理其中选中的块。参见 Joins 了解连接处理的详细信息,Performance Considerations for Join Queries 了解性能注意事项,Hints 了解如何微调连接策略。
Impala 的聚合策略是什么?
Impala 目前仅支持内存中的哈希聚合(hash aggregation)。
Impala 元数据如何管理?
Impala 使用两部分的元数据:Hive metastore 中的目录信息和 NameNode 中的文件元数据。目前,当 impalad 需要元数据以产生查询的执行计划时才加载并缓存元数据(this metadata is lazily populated and cached when an impaladneeds it to plan a query)
当在 Hive 中加载新数据之后,使用 REFRESH 语句更新这个表的元数据。INVALIDATE METADATA Statement 语句刷新所有的元数据,以便 Impala 识别到 Hive 中创建的新表或其他 DDL 、DML 的修改。
在 Impala 1.2 及以上版本中,有一个单独的 catalogd 守护进程向所有节点广播 Impala 中 DDL 或 DML 语句导致的元数据变化,减少或避免了使用 REFRESH 和 INVALIDATE METADATA 语句的需求。
并发查询时 NameNode 负载如何?
Impala 产生的负载与 MapReduce 产生的非常类似。Impala 在规划阶段连接 NameNode 以获得文件元数据(仅在接收到查询的主机上执行)。每一个 impalad 将读取文件作为查询正常处理的一部分(Every impalad will read files as part of normal processing of the query)。
为何 Impala 能实现性能提升(How does Impala achieve its performance improvements)?
这是 Impala 与其他 Hadoop 组件和相关技术在性能方面不同的主要原因(These are the main factors in the performance of Impala versus that of other Hadoop components and related technologies)。
Impala 避免使用 MapReduce。尽管 MapReduce 是一种伟大的通用并行处理模型,具有许多优点,但是它不是专为执行 SQL 设计的。Impala 在这些方面避免了 MapReduce 的低效:
- Impala 不会把中间结果存放到硬盘上。SQL 查询通常映射成多个包含所有中间结果集都写入到硬盘上的 MapReduce 作业(SQL queries often map to multiple MapReduce jobs with all intermediate data sets written to disk)
- Impala 避免了 MapReduce 启动时间的耗费。对于交互式查询,MapReduce 启动时间变得非常醒目。Impala 以服务方式运行,实际上没有启动时间
- Impala 可以更自然的分散查询计划,而不是不得不纳入 map 和 reduce 作业管道中。这使得 Impala 可以并行处理查询的多个步骤,并避免不必要的负载如排序和混洗(This enables Impala to parallelize multiple stages of a query and avoid overheads such as sort and shuffle when unnecessary)
Impala 通过利用最新机器和技术(modern hardware and technologies),采用了一种更高效的执行引擎(Impala uses a more efficient execution engine by taking advantage of modern hardware and technologies):
- Impala 生成运行时代码。Impala 使用 LLVM 为要执行的查询生成汇编码(assembly code)。个别查询不需要为运行在可以支持各种查询的系统而支付代价(Individual queries do not have to pay the overhead of running on a system that needs to be able to execute arbitrary queries)
- Impala 尽可能采用最新的硬件指令。Impala 使用最新的 SSE (SSE4.2) 指令集,某些情况下可以提供巨大的加速效果
- Impala 采用更好的 I/O 调度。Impala 了解块在硬盘上的位置,并可以调度块处理的顺序,以便保证所有硬盘都繁忙
- Impala 专为性能设计。Impala 采取以性能为导向的设计原则,为此花费了大量的时间,例如紧密内部循环、内联函数调用、最小分支、更好的缓存使用、以及最小内存使用等(A lot of time has been spent in designing Impala with sound performance-oriented fundamentals, such as tight inner loops, inlined function calls, minimal branching, better use of cache, and minimal memory usage)
当数据集超出可用内存时会发生什么?
目前来说,假如在某一节点上处理中间结果集所需的内存超出了这一节点上 Impala 可用的内存,查询会被取消。你可以调整每一节点上 Impala 的可用内存,也可以对你最大的查询微调连接策略来减少内存需求。我们计划在将来支持外部连接和排序。
但请记住,使用内存的大小并不是跟输入数据集的大小直接相关。对于聚合来说,使用的内存跟分组后的行数有关。对于连接来说,使用的内存与除了最大的表之外其他所有表的大小相关,并且 Impala 可以采用在每个节点之间拆分大的连接表而不是把整个表都传输到每个节点的连接策略。
哪些是内存密集型操作?
假如查询失败,错误信息是 "memory limit exceeded",你可能怀疑有内存泄露(memory leak)。其实问题可能是因为查询构造的方式导致 Impala 分配超出你预期的内存,从而在某些节点上超出 Impala 分配的内存限制(The problem could actually be a query that is structured in a way that causes Impala to allocate more memory than you expect, exceeded the memory allocated for Impala on a particular node)。一些特别内存密集型的查询和表结构如下:
- 使用动态分区的 INSERT 语句,插入到包含许多分区的表中(特别是使用 Parquet 格式的表,这些表中每一个分区的数据都保存到内存中,直到它达到 1 GB 并被写入到硬盘里)。考虑把这样的操作分散成几个不同的 INSERT 语句,例如一次只加载一年的数据而不是一次加载所有年份的数据
- 在唯一或高基数(high-cardinality)列上的 GROUP BY 操作。Impala 为 GROUP BY 查询中每一个不同的值分配一些处理结构(handler structures)。成千上万不同的 GROUP BY 值可能超出内存限制
- 查询涉及到非常宽、包含上千个列的表,特别是包含许多 STRING 列的表。因为 Impala 允许 STRING 值最大不超过 32 KB,这些查询的中间结果集可能需要大量的内存分配
何时 Impala 分配(hold on to)或释放(return)内存?
Impala 使用 tcmalloc 分配内存,一款专为高并发优化的内存分频器。一当 Impala 分配了内存,它保留这些内存用于将来的查询。因此,空闲时显示 Impala 有很高的内存使用是很正常的。假如 Impala 检测到它将超过内存限制(通过 -mem_limit 启动选项或 MEM_LIMIT 查询选项定义),它将释放当前查询不需要的所有内存。
当通过 JDBC 或 ODBC 接口执行查询,请确保在之后调用对应的关闭方法。否则,查询关联的一些内存不会释放。
SQL
是否支持 UPDATE 语句?
Impala 目前不支持 UPDATE 语句,它通常用于修改单行数据、一小组数据、或特定的列。通常 Impala 查询使用的基于 HDFS 的文件针对一次超过许多M的批量操作(bulk operations)进行了优化,这使得传统的 UPDATE 操作低效或不切实际。
你可以使用下面的技术来达到与熟悉的 UPDATE 语句相同的目标,并为之后的查询保持高效的文件布局:
- 使用你已经更新后并存放在其他位置的数据替换掉表或分区的全部内容,或者使用 INSERT OVERWRITE, LOAD DATA, 或者使用手工 HDFS 文件操作之后对这个表执行 REFRESH 语句。可选的,你可以在 INSERT 语句中使用内置函数和表达式来转换复制的数据,就像你通常在 UPDATE 语句中所做的那样,例如转换一个混合大小写的字符串为全部大写或全部小写
- 为了更新单行数据,请使用 HBase 表,并使用与原来行相同的 key 执行 INSERT ... VALUES 语句。因为 HBase 通过只返回特定键值的最新的行来处理重复的键,新插入的行有效的隐藏了之前的
Impala 可以执行用户定义函数(UDFs)吗?
Impala 1.2 及以上版本支持 UDFs 和 UDAs。你可以使用 C++ 编写本地 Impala UDFs 和 UDAs,或者重用之前用 Java 编写的 Hive 中的 UDFs (但不支持 UDAs) 。参见 User-Defined Functions 了解详细信息。
为什么我必须使用 REFRESH 和 INVALIDATE METADATA,它们做了什么?
在 Impala 1.2 或更高版本中,大大减少了使用 REFRESH 和 INVALIDATE METADATA 语句的情况:
- 新的 impala 目录服务,即 catalogd 守护进程,向所有 Impala 节点广播 Impala DDL 语句的结果。因此,假如你在一个 Impala 节点执行了 CREATE TABLE 语句,再通过其他节点执行查询时,不再需要执行 INVALIDATE METADATA
- 目录服务只识别到通过 Impala 导致的变更,因此如果你通过 Hive,或者通过在 HDFS 中操作文件加载数据,仍然必须使用 REFRESH 语句,并且如果你在 Hive 中创建、修改表、添加或删除分区、或执行其他 DDL 操作后,必须执行 INVALIDATE METADATA 语句
- 因为目录服务向所有节点广播 REFRESH 和 INVALIDATE METADATA 语句的结果,当你仍然需要执行这些语句的时候,你可以只在其中一个节点上运行,而不是在所有节点上运行,并且这些变化会被整个集群自动识别。这使得可以通过任意 Impala 节点执行查询而不是总使用同一个协调器节点,更方便负载均衡
为什么执行 DROP TABLE 之后空间不释放?
当你对内部表而不是外部表执行 DROP TABLE 后,Impala 删除对应的数据文件。默认的,CREATE TABLE 语句创建内部表,文件被 Impala 管理。外部表通过 CREATE EXTERNAL TABLE 语句创建,文件位置在 Impala 控制范围之外。请执行 DESCRIBE FORMATTED 语句检查表是内部表还是外部表。关键字 MANAGED_TABLE 表示是内部表,Impala 可以删除这些数据文件。关键字 EXTERNAL_TABLE 表示这是外部表,当你删除表时,Impala 将保持这些数据文件不变。
即使当你删除一个内部表并且文件已经从原来的位置移除,你可能也不会立刻得到空闲的硬盘空间。默认的,HDFS 中删除的文件放到特定的回收站(trashcan)目录,在那里过一段时间(默认是 6 小时)后被清除。关于回收站机制的背景知识,请参见 http://archive.cloudera.com/cdh4/cdh/4/hadoop/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html。更多关于在回收站清除文件的信息,参见 http://archive.cloudera.com/cdh4/cdh/4/hadoop/hadoop-project-dist/hadoop-common/FileSystemShell.html。
当 Impala 删除文件,并且那些文件被移动到 HDFS 回收站,他们存放在属于 impala 用户的 HDFS 目录中。假如 impala 用户没有 HDFS home 目录,在这里回收站会被创建,基于安全的考虑,这些文件不会被删除和移动。假如你执行了 DROP TABLE 语句,然后发现表的数据文件仍然在原来的位置,请先创建 HDFS 目录 /user/impala,属于 impala 用户,并可写。例如,你可能发现 /user/impala 属于 hdfs 用户,这时你需要切换成 hdfs 用户并执行类似的命令:
hdfs dfs -chown -R impala /user/impala
Partitioned Tables
我怎么把一个大的 CSV 文件加载到分区表里?
为了向分区表里加载数据文件,当数据文件包含类似 year,month, 等等对应着分区键的列时,使用两步处理。首先,使用 LOAD DATA 或 CREATE EXTERNAL TABLE 语句加载数据到未分区的表里。然后使用 INSERT ... SELECT 语句从未分区的表向分区表复制数据。在 INSERT 语句中包含 PARTITION 子句指定分区键列。对每一个分区,这一 INSERT 操作把数据拆分成单独的数据文件。例如,参见 Partitioning 中的例子。关于如何把数据加载到分区 Parquet 表(大批量数据的热门选择)的详细信息,参见 Loading Data into Parquet Tables。
我可以执行 INSERT ... SELECT *加载数据到分区表吗?
当你使用 INSERT ... SELECT * 语法复制数据到分区表时,对应分区键的列必须出现在 SELECT * 所返回列的最后。你可以把分区键定义放在最后来创建表。或者,你可以使用 CREATE VIEW 语句创建一个记录这些列:把分区键列放在最后,然后使用 INSERT ... SELECT * from the view。