Hive 企业级调优
1 Fetch 抓取
Fectch 抓取是指对某些情况下的查询不必使用 MapReduce 计算
将 hive.fetch.task.conversion 设置成 more,在全局查找、字段查找、limit查找等都不走 MapReduce
2 本地模式
多数的 Hadoop Job 是需要 Hadoop 提供的完整的可扩展性来处理大数据集的,不过,有时 Hive 的输入数据量是非常小的,在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多,对于大多数这种情况,Hive 可以通过本地模式在单台机器上处理所有的任务,对于小数据集,执行时间可以明显被缩短
将 hive.exec.mode.local.auto 设置成 true,让 Hive 在适当的时候自动启动这个优化
3 表优化
3.1 空 KEY 过滤
有时 JOIN 超时是因为某些 KEY 对应的数据太多,而相同 KEY 对应的数据都会发送到相同的 Reducer 上,从而导致内存不够,此时我们应该仔细分很多情况下,这些 KEY 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。
3.2 空 KEY 转换
有时虽然某个 KEY 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在 JOIN 的结果中,此时我们可以将表中 KEY 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 Reducer 上。
3.3 MapJOIN
如果不指定 MapJOIN 或者不符合 MapJOIN 的条件,那么 Hive 解析器会将 JOIN 转换成 Common JOIN,即:在Reduce阶段完成 JOIN,容易发生数据倾斜,可以用 MapJOIN 把小表加载到内存在 Map 端进行 JOIN,避 Reducer 处理。
### 3.4 Group By
默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了
# 是否在Map端进行聚合
set hive.map.aggr = true
# 在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000
# 有数据倾斜的时候进行负载均衡
set hive.groupby.skewindata = true
当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce中,从而达到负载均衡的目的,第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作
3.5 Count(Distinct)
数据量小的时候无所谓,数据量大的情况下,由于 COUNT DISTINCT 的全聚合操作,即使设定了 Reduce Task 个数,Hive 也只会启动一个Reduce,这就造成一个 Reduce 处理的数据量太大,导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换
### 3.6 笛卡尔积
不使用笛卡尔积
### 3.7 行列过滤
禁止使用 SELECT *
3.8 动态分区调整
对分区表Insert数据时候,数据库自动会根据分区字段的值,将数据插入到相应的分区中,即动态分区
# 开启动态分区功能
hive.exec.dynamic.partition=true
# 设置为非严格模式
hive.exec.dynamic.partition.mode=nonstrict
# 在所有执行MR的节点上,最大一共可以创建多少个动态分区,默认1000
hive.exec.max.dynamic.partitions=1000
# 在每个执行MR的节点上,最大可以创建多少个动态分区,该参数需要根据实际的数据来设定
hive.exec.max.dynamic.partitions.pernode=100
# 整个MR Job中,最大可以创建多少个HDFS文件,默认100000
hive.exec.max.created.files=100000
# 当有空分区生成时,是否抛出异常。一般不需要设置
hive.error.on.empty.partition=false
4 合理设置 MapReduce 数量
4.1 复杂文件增加 Map 数
当 input 的文件都很大,任务逻辑复杂,Map 执行非常慢的时候,可以考虑增加 Map 数,来使得每个 Map 处理的数据量减少,从而提高任务的执行效率
4.2 小文件进行合并
在 Map 执行前合并小文件,减少 Map 数:
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
在 Map-Reduce 的任务结束时合并小文件的设置
# 在 map-only 任务结束时合并小文件
SET hive.merge.mapfiles = true;
# 在Map-Reduce任务结束时合并小文件
SET hive.merge.mapredfiles = true;
# 合并文件的大小,默认256M
SET hive.merge.size.per.task = 268435456;
# 当输出文件的平均大小小于该值时,启动一个独立的Map-Reduce任务进行文件merge
SET hive.merge.smallfiles.avgsize = 16777216;
4.3 合理设置 Reduce 数
# 每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=256000000
# 每个任务最大的Reduce数,默认为1009
hive.exec.reducers.max=1009
# 计算Reduce数的公式
N=min(hive.exec.reducers.max, 数据总量/hive.exec.reducers.bytes.per.reducer)
5 并行执行
Hive 会将一个查询转化成一个或者多个阶段,这样的阶段可以是 MapReduce 阶段、抽样阶段、合并阶段、limit 阶段,或者 Hive 执行过程中可能需要的其他阶段,默认情况下,Hive 一次只会执行一个阶段,不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个 job 的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么 job 可能就越快完成。
通过设置参数 hive.exec.parallel 值为 true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果 job 中并行阶段增多,那么集群利用率就会增加。
6 严格模式
Hive 提供了一个严格模式,可以防止用户执行那些可能意想不到的不好的影响的查询
开启严格模式需要修改 hive.mapred.mode 值为 strict,开启严格模式可以禁止 种类型的查询:
- 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行
- 对于使用了order by语句的查询,要求必须使用limit语句
- 限制笛卡尔积的查询
7 JVM 重用
JVM 重用是 Hadoop 调优参数的内容,其对 Hive 的性能具有非常大的影响,特别是对于很难避免小文件的场景或 task 特别多的场景,这类场景大多数执行时间都很短。
Hadoop 的默认配置通常是使用派生来执行和任务的,这时的启动过程可能会造成相当大的开销,尤其是执行的包含有成百上千任务的情况。
重用可以使得实例在同一个中重新使用多次。
需要在 Hadoop 的 mapred-site.xml 中配置,但是有个缺点是重用次数过大,会产生大量的垃圾
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
8 推测执行
如果用户因为输入数据量很大而需要执行长时间的 Map 或者 Reduce Task 的话,那么启动推测执行造成的浪费是非常巨大大