10Hive性能优化

10Hive性能优化

  • 1Hive性能问题排查的方式
  • 1.1Hive底层原理:explain执行计划详解
    • 1.1.1 explain理论
    • 1.1.2 实践
  • 2Hive性能调优的方式
    • 2.1. SQL语句优化
      • 1. union all
      • 2. distinct
    • 2.2. 数据格式优化
    • 2.3. 小文件过多优化
    • 2.3.1解决hive小文件过多问题
      • 小文件产生的原因
      • 小文件过多产生的影响
      • 怎么解决小文件过多
        • 1. 使用 hive 自带的 concatenate 命令,自动合并小文件
        • 2. 调整参数减少Map数量
        • 3. 减少Reduce的数量
        • 4. 使用hadoop的archive将小文件归档
        • 如果是新集群,没有历史遗留问题的话,建议hive使用 orc 文件格式,以及启用 lzo 压缩。这样小文件过多可以使用hive自带命令 concatenate 快速合并。
    • 2.4. 并行执行优化
    • 2.5. JVM优化
    • 2.6. 推测执行优化

Hive作为大数据平台举足轻重的框架,以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。
但是如果我们只局限于会使用Hive,而不考虑性能问题,就难搭建出一个完美的数仓,所以Hive性能调优是我们大数据从业者必须掌握的技能。
本节将给大家讲解Hive性能调优的一些方法及技巧。

1Hive性能问题排查的方式

当我们发现一条SQL语句执行时间过长或者不合理时,我们就要考虑对SQL进行优化,优化首先得进行问题排查,那么我们可以通过哪些方式进行排查呢。

经常使用关系型数据库的同学可能知道关系型数据库的优化的诀窍-看执行计划。
如Oracle数据库,它有多种类型的执行计划,通过多种执行计划的配合使用,可以看到根据统计信息推演的执行计划,即Oracle推断出来的未真正运行的执行计划;
还可以看到实际执行任务的执行计划;
能够观察到从数据读取到最终呈现的主要过程和中间的量化数据。
可以说,在Oracle开发领域,掌握合适的环节,选用不同的执行计划,SQL调优就不是一件难事。

Hive中也有执行计划,但是Hive的执行计划都是预测的,这点不像Oracle和SQL Server有真实的计划,可以看到每个阶段的处理数据、消耗的资源和处理的时间等量化数据。Hive提供的执行计划没有这些数据,这意味着虽然Hive的使用者知道整个SQL的执行逻辑,但是各阶段耗用的资源状况和整个SQL的执行瓶颈在哪里是不清楚的。
想要知道HiveSQL所有阶段的运行信息,可以查看YARN提供的日志。查看日志的链接,可以在每个作业执行后,在控制台打印的信息中找到。如下图所示:
在这里插入图片描述
Hive提供的执行计划目前可以查看的信息有以下几种:
1.查看执行计划的基本信息,即explain;
2.查看执行计划的扩展信息,即explain extended;
3.查看SQL数据输入依赖的信息,即explain dependency;
4.查看SQL操作相关权限的信息,即explain authorization;
5.查看SQL的向量化描述信息,即explain vectorization。

在查询语句的SQL前面加上关键字explain是查看执行计划的基本方法。 用explain打开的执行计划包含以下两部分:
-作业的依赖关系图,即STAGE DEPENDENCIES;
-每个作业的详细信息,即STAGE PLANS。

总结:Hive对SQL语句性能问题排查的方式:
1.使用explain查看执行计划;
2.查看YARN提供的日志。

1.1Hive底层原理:explain执行计划详解

不懂hive中的explain,说明hive还没入门,学会explain,能够给我们工作中使用hive带来极大的便利!

1.1.1 explain理论

本节将介绍 explain 的用法及参数介绍

HIVE提供了EXPLAIN命令来展示一个查询的执行计划,这个执行计划对于我们了解底层原理,hive 调优,排查数据倾斜等很有帮助
使用语法如下:

EXPLAIN [EXTENDED|CBO|AST|DEPENDENCY|AUTHORIZATION|LOCKS|VECTORIZATION|ANALYZE] query

explain 后面可以跟以下可选参数,注意:这几个可选参数不是 hive 每个版本都支持的

1EXTENDED:加上 extended 可以输出有关计划的额外信息。这通常是物理信息,例如文件名。这些额外信息对我们用处不大

2CBO:输出由Calcite优化器生成的计划。CBO 从 hive 4.0.0 版本开始支持

3AST:输出查询的抽象语法树。AST 在hive 2.1.0 版本删除了,存在bug,转储AST可能会导致OOM错误,将在4.0.0版本修复

4DEPENDENCY:dependency在EXPLAIN语句中使用会产生有关计划中输入的额外信息。它显示了输入的各种属性

5AUTHORIZATION:显示所有的实体需要被授权执行(如果存在)的查询和授权失败

6LOCKS:这对于了解系统将获得哪些锁以运行指定的查询很有用。LOCKS 从 hive 3.2.0 开始支持

7VECTORIZATION:将详细信息添加到EXPLAIN输出中,以显示为什么未对Map和Reduce进行矢量化。从 Hive 2.3.0 开始支持

8ANALYZE:用实际的行数注释计划。从 Hive 2.2.0 开始支持

在 hive cli 中输入以下命令(hive 2.3.7):

explain select sum(id) from test1;

得到结果(请逐行看完,即使看不懂也要每行都看):

STAGE DEPENDENCIES:Stage-1 is a root stageStage-0 depends on stages: Stage-1STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: test1Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: idStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEGroup By Operatoraggregations: sum(id)mode: hashoutputColumnNames: _col0Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorsort order:Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEvalue expressions: _col0 (type: bigint)Reduce Operator Tree:Group By Operatoraggregations: sum(VALUE._col0)mode: mergepartialoutputColumnNames: _col0Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

看完以上内容有什么感受,是不是感觉都看不懂,不要着急,下面将会详细讲解每个参数,相信你学完下面的内容之后再看 explain 的查询结果将游刃有余。
一个HIVE查询被转换为一个由一个或多个stage组成的序列(有向无环图DAG)。这些stage可以是MapReduce stage,也可以是负责元数据存储的stage,也可以是负责文件系统的操作(比如移动和重命名)的stage。

我们将上述结果拆分看,先从最外层开始,包含两个大的部分:

  1. stage dependencies: 各个stage之间的依赖性

  2. stage plan: 各个stage的执行计划

先看第一部分 stage dependencies ,包含两个 stage,Stage-1 是根stage,说明这是开始的stage,Stage-0 依赖 Stage-1,Stage-1执行完成后执行Stage-0。

再看第二部分 stage plan,里面有一个 Map Reduce,一个MR的执行计划分为两个部分:

  1. Map Operator Tree: MAP端的执行计划树

  2. Reduce Operator Tree: Reduce端的执行计划树

这两个执行计划树里面包含这条sql语句的 operator:

  1. map端第一个操作肯定是加载表,所以就是 TableScan 表扫描操作,常见的属性:

alias: 表名称Statistics: 表统计信息,包含表中数据条数,数据大小等
  1. Select Operator: 选取操作,常见的属性 :
expressions:需要的字段名称及字段类型outputColumnNames:输出的列名称Statistics:表统计信息,包含表中数据条数,数据大小等
  1. Group By Operator:分组聚合操作,常见的属性:
aggregations:显示聚合函数信息mode:聚合模式,值有 hash:随机聚合,就是hash partition;partial:局部聚合;final:最终聚合keys:分组的字段,如果没有分组,则没有此字段outputColumnNames:聚合之后输出列名Statistics: 表统计信息,包含分组聚合之后的数据条数,数据大小等
  1. Reduce Output Operator:输出到reduce操作,常见属性:
sort order:值为空 不排序;值为 + 正序排序,值为 - 倒序排序;值为 +-  排序的列为两列,第一列为正序,第二列为倒序

5.Filter Operator:过滤操作,常见的属性:

predicate:过滤条件,如sql语句中的where id>=1,则此处显示(id >= 1)
  1. Map Join Operator:join 操作,常见的属性:
condition map:join方式 ,如Inner Join 0 to 1 Left Outer Join0 to 2keys: join 的条件字段outputColumnNames: join 完成之后输出的字段Statistics: join 完成之后生成的数据条数,大小等
  1. File Output Operator:文件输出操作,常见的属性
compressed:是否压缩table:表的信息,包含输入输出文件格式化方式,序列化方式等
  1. Fetch Operator 客户端获取数据操作,常见的属性:
limit,值为 -1 表示不限制条数,其他值为限制的条数

好,学到这里再翻到上面 explain 的查询结果,是不是感觉基本都能看懂了。

1.1.2 实践

1. join 语句会过滤 null 的值吗?
现在,我们在hive cli 输入以下查询计划语句

select a.id,b.user_name from test1 a join test2 b on a.id=b.id;

问:上面这条 join 语句会过滤 id 为 null 的值吗

执行下面语句:

explain select a.id,b.user_name from test1 a join test2 b on a.id=b.id;

我们来看结果 (为了适应页面展示,仅截取了部分输出信息):

TableScanalias: aStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: id is not null (type: boolean)Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: _col0Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 _col0 (type: int)1 _col0 (type: int)...

从上述结果可以看到 predicate: id is not null 这样一行,说明 join 时会自动过滤掉关联字段为 null 值的情况,但 left join 或 full join 是不会自动过滤的,大家可以自行尝试下。
2. group by 分组语句会进行排序吗?
看下面这条sql

select id,max(user_name) from test1 group by id;

问:group by 分组语句会进行排序吗

直接来看 explain 之后结果 (为了适应页面展示,仅截取了部分输出信息)

 TableScanalias: test1Statistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int), user_name (type: string)outputColumnNames: id, user_nameStatistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONEGroup By Operatoraggregations: max(user_name)keys: id (type: int)mode: hashoutputColumnNames: _col0, _col1Statistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: _col0 (type: int)sort order: +Map-reduce partition columns: _col0 (type: int)Statistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONEvalue expressions: _col1 (type: string)...

我们看 Group By Operator,里面有 keys: id (type: int) 说明按照 id 进行分组的,再往下看还有 sort order: + ,说明是按照 id 字段进行正序排序的。
3. 哪条sql执行效率高呢?

2Hive性能调优的方式

为什么都说性能优化这项工作是比较难的,因为一项技术的优化,必然是一项综合性的工作,它是多门技术的结合。我们如果只局限于一种技术,那么肯定做不好优化的。
下面将从多个完全不同的角度来介绍Hive优化的多样性,我们先来一起感受下。
观察两条sql语句

SELECTa.id,b.user_name
FROMtest1 a
JOIN test2 b ON a.id = b.id
WHEREa.id > 2;SELECTa.id,b.user_name
FROM(SELECT * FROM test1 WHERE id > 2) a
JOIN test2 b ON a.id = b.id;

这两条sql语句输出的结果是一样的,但是哪条sql执行效率高呢
有人说第一条sql执行效率高,因为第二条sql有子查询,子查询会影响性能
有人说第二条sql执行效率高,因为先过滤之后,在进行join时的条数减少了,所以执行效率就高了

到底哪条sql效率高呢,我们直接在sql语句前面加上 explain,看下执行计划不就知道了嘛

在第一条sql语句前加上 explain,得到如下结果

hive (default)> explain select a.id,b.user_name from test1 a join test2 b on a.id=b.id where a.id >2;
OK
Explain
STAGE DEPENDENCIES:Stage-4 is a root stageStage-3 depends on stages: Stage-4Stage-0 depends on stages: Stage-3STAGE PLANS:Stage: Stage-4Map Reduce Local WorkAlias -> Map Local Tables:$hdt$_0:aFetch Operatorlimit: -1Alias -> Map Local Operator Tree:$hdt$_0:aTableScanalias: aStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id > 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: _col0Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 _col0 (type: int)1 _col0 (type: int)Stage: Stage-3Map ReduceMap Operator Tree:TableScanalias: bStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id > 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int), user_name (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEMap Join Operatorcondition map:Inner Join 0 to 1keys:0 _col0 (type: int)1 _col0 (type: int)outputColumnNames: _col0, _col2Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), _col2 (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeLocal Work:Map Reduce Local WorkStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

在第二条sql语句前加上 explain,得到如下结果

hive (default)> explain select a.id,b.user_name from(select * from  test1 where id>2 ) a join test2 b on a.id=b.id;
OK
Explain
STAGE DEPENDENCIES:Stage-4 is a root stageStage-3 depends on stages: Stage-4Stage-0 depends on stages: Stage-3STAGE PLANS:Stage: Stage-4Map Reduce Local WorkAlias -> Map Local Tables:$hdt$_0:test1Fetch Operatorlimit: -1Alias -> Map Local Operator Tree:$hdt$_0:test1TableScanalias: test1Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id > 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: _col0Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 _col0 (type: int)1 _col0 (type: int)Stage: Stage-3Map ReduceMap Operator Tree:TableScanalias: bStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id > 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int), user_name (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEMap Join Operatorcondition map:Inner Join 0 to 1keys:0 _col0 (type: int)1 _col0 (type: int)outputColumnNames: _col0, _col2Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), _col2 (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeLocal Work:Map Reduce Local WorkStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

大家有什么发现,除了表别名不一样,其他的执行计划完全一样,都是先进行 where 条件过滤,在进行 join 条件关联。说明 hive 底层会自动帮我们进行优化,所以这两条sql语句执行效率是一样的。
最后
以上仅列举了3个我们生产中既熟悉又有点迷糊的例子,explain 还有很多其他的用途,如查看stage的依赖情况、排查数据倾斜、hive 调优等,小伙伴们可以自行尝试。

2.1. SQL语句优化

SQL语句优化涉及到的内容太多,因篇幅有限,不能一一介绍到,所以就拿几个典型举例,让大家学到这种思想,以后遇到类似调优问题可以往这几个方面多思考下。

1. union all

insert into table stu partition(tp) 
select s_age,max(s_birth) stat,'max' tp 
from stu_ori
group by s_ageunion allinsert into table stu partition(tp) 
select s_age,min(s_birth) stat,'min' tp 
from stu_ori
group by s_age;

我们简单分析上面的SQl语句,就是将每个年龄的最大和最小的生日获取出来放到同一张表中,union all 前后的两个语句都是对同一张表按照s_age进行分组,然后分别取最大值和最小值。对同一张表相同的字段进行两次分组,这造成了极大浪费,我们能不能改造下呢,当然是可以的,为大家介绍一个语法: from … insert into … ,这个语法将from前置,作用就是使用一张表,可以进行多次插入操作:

–开启动态分区

set hive.exec.dynamic.partition=true; 
set hive.exec.dynamic.partition.mode=nonstrict; 
from stu_ori insert into table stu partition(tp) 
select s_age,max(s_birth) stat,'max' tp 
group by s_ageinsert into table stu partition(tp) 
select s_age,min(s_birth) stat,'min' tp 
group by s_age;

上面的SQL就可以对stu_ori表的s_age字段分组一次而进行两次不同的插入操作。
这个例子告诉我们一定要多了解SQL语句,如果我们不知道这种语法,一定不会想到这种方式的。

2. distinct

先看一个SQL,去重计数:

select count(1) 
from( select s_age from stu group by s_age 
) b;

这是简单统计年龄的枚举值个数,为什么不用distinct?

select count(distinct s_age) 
from stu;

有人说因为在数据量特别大的情况下使用第一种方式能够有效避免Reduce端的数据倾斜,但是事实如此吗?
我们先不管数据量特别大这个问题,就当前的业务和环境下使用distinct一定会比上面那种子查询的方式效率高。原因有以下几点:
1.上面进行去重的字段是年龄字段,要知道年龄的枚举值是非常有限的,就算计算1岁到100岁之间的年龄,s_age的最大枚举值才是100,如果转化成MapReduce来解释的话,在Map阶段,每个Map会对s_age去重。由于s_age枚举值有限,因而每个Map得到的s_age也有限,最终得到reduce的数据量也就是map数量*s_age枚举值的个数。
2.distinct的命令会在内存中构建一个hashtable,查找去重的时间复杂度是O(1);group by在不同版本间变动比较大,有的版本会用构建hashtable的形式去重,有的版本会通过排序的方式, 排序最优时间复杂度无法到O(1)。另外,第一种方式(group by)去重会转化为两个任务,会消耗更多的磁盘网络I/O资源。
3.最新的Hive 3.0中新增了 count(distinct ) 优化,通过配置 hive.optimize.countdistinct,即使真的出现数据倾斜也可以自动优化,自动改变SQL执行的逻辑。
4.第二种方式(distinct)比第一种方式(group by)代码简洁,表达的意思简单明了,如果没有特殊的问题,代码简洁就是优!
这个例子告诉我们,有时候我们不要过度优化,调优讲究适时调优,过早进行调优有可能做的是无用功甚至产生负效应,在调优上投入的工作成本和回报不成正比。调优需要遵循一定的原则。

2.2. 数据格式优化

Hive提供了多种数据存储组织格式,不同格式对程序的运行效率也会有极大的影响。
Hive提供的格式有TEXT、SequenceFile、RCFile、ORC和Parquet等。
SequenceFile是一个二进制key/value对结构的平面文件,在早期的Hadoop平台上被广泛用于MapReduce输出/输出格式,以及作为数据存储格式。
Parquet是一种列式数据存储格式,可以兼容多种计算引擎,如MapRedcue和Spark等,对多层嵌套的数据结构提供了良好的性能支持,是目前Hive生产环境中数据存储的主流选择之一。
ORC优化是对RCFile的一种优化,它提供了一种高效的方式来存储Hive数据,同时也能够提高Hive的读取、写入和处理数据的性能,能够兼容多种计算引擎。事实上,在实际的生产环境中,ORC已经成为了Hive在数据存储上的主流选择之一。
我们使用同样数据及SQL语句,只是数据存储格式不同,得到如下执行时长:
在这里插入图片描述
注:CPU时间:表示运行程序所占用服务器CPU资源的时间。
用户等待耗时:记录的是用户从提交作业到返回结果期间用户等待的所有时间。
查询TextFile类型的数据表耗时33分钟, 查询ORC类型的表耗时1分52秒,时间得以极大缩短,可见不同的数据存储格式也能给HiveSQL性能带来极大的影响。

2.3. 小文件过多优化

小文件如果过多,对 hive 来说,在进行查询时,每个小文件都会当成一个块,启动一个Map任务来完成,而一个Map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的Map数量是受限的。
所以我们有必要对小文件过多进行优化,关于小文件过多的解决的办法如下:

2.3.1解决hive小文件过多问题

小文件产生的原因

hive 中的小文件肯定是向 hive 表中导入数据时产生,所以先看下向 hive 中导入数据的几种方式

1.直接向表中插入数据

insert into table A values (1,'zhangsan',88),(2,'lisi',61);

这种方式每次插入时都会产生一个文件,多次插入少量数据就会出现多个小文件,但是这种方式生产环境很少使用,可以说基本没有使用的

2.通过load方式加载数据

load data local inpath '/export/score.csv' overwrite into table A  -- 导入文件load data local inpath '/export/score' overwrite into table A   -- 导入文件夹

使用 load 方式可以导入文件或文件夹,当导入一个文件时,hive表就有一个文件,当导入文件夹时,hive表的文件数量为文件夹下所有文件的数量

3.通过查询方式加载数据

insert overwrite table A  select s_id,c_name,s_score from B;

这种方式是生产环境中常用的,也是最容易产生小文件的方式

insert 导入数据时会启动 MR 任务,MR中 reduce 有多少个就输出多少个文件

所以, 文件数量=ReduceTask数量*分区数

也有很多简单任务没有reduce,只有map阶段,则

文件数量=MapTask数量*分区数

每执行一次 insert 时hive中至少产生一个文件,因为 insert 导入时至少会有一个MapTask。
像有的业务需要每10分钟就要把数据同步到 hive 中,这样产生的文件就会很多。

小文件过多产生的影响

首先对底层存储HDFS来说,HDFS本身就不适合存储大量小文件,小文件过多会导致namenode元数据特别大, 占用太多内存,严重影响HDFS的性能

对 hive 来说,在进行查询时,每个小文件都会当成一个块,启动一个Map任务来完成,而一个Map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的Map数量是受限的。

怎么解决小文件过多

1. 使用 hive 自带的 concatenate 命令,自动合并小文件

使用方法:

#对于非分区表
alter table A concatenate;#对于分区表
alter table B partition(day=20201224) concatenate;

举例:

#向 A 表中插入数据
hive (default)> insert into table A values (1,'aa',67),(2,'bb',87);
hive (default)> insert into table A values (3,'cc',67),(4,'dd',87);
hive (default)> insert into table A values (5,'ee',67),(6,'ff',87);#执行以上三条语句,则A表下就会有三个小文件,在hive命令行执行如下语句
#查看A表下文件数量
hive (default)> dfs -ls /user/hive/warehouse/A;
Found 3 items
-rwxr-xr-x   3 root supergroup        378 2020-12-24 14:46 /user/hive/warehouse/A/000000_0
-rwxr-xr-x   3 root supergroup        378 2020-12-24 14:47 /user/hive/warehouse/A/000000_0_copy_1
-rwxr-xr-x   3 root supergroup        378 2020-12-24 14:48 /user/hive/warehouse/A/000000_0_copy_2#可以看到有三个小文件,然后使用 concatenate 进行合并
hive (default)> alter table A concatenate;#再次查看A表下文件数量
hive (default)> dfs -ls /user/hive/warehouse/A;
Found 1 items
-rwxr-xr-x   3 root supergroup        778 2020-12-24 14:59 /user/hive/warehouse/A/000000_0#已合并成一个文件

注意:
1、concatenate 命令只支持 RCFILE 和 ORC 文件类型。
2、使用concatenate命令合并小文件时不能指定合并后的文件数量,但可以多次执行该命令。
3、当多次使用concatenate后文件数量不在变化,这个跟参数 mapreduce.input.fileinputformat.split.minsize=256mb 的设置有关,可设定每个文件的最小size。

2. 调整参数减少Map数量

设置map输入合并小文件的相关参数:

#执行Map前进行小文件合并
#CombineHiveInputFormat底层是 Hadoop的 CombineFileInputFormat 方法
#此方法是在mapper中将多个文件合成一个split作为输入
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 默认#每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;   -- 256M#一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;  -- 100M#一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;  -- 100M

设置map输出和reduce输出进行合并的相关参数:

#设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true;#设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true;#设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000;   -- 256M#当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge
set hive.merge.smallfiles.avgsize=16000000;   -- 16M 

启用压缩

# hive的查询结果输出是否进行压缩
set hive.exec.compress.output=true;# MapReduce Job的结果输出是否使用压缩
set mapreduce.output.fileoutputformat.compress=true;
3. 减少Reduce的数量
#reduce 的个数决定了输出的文件的个数,所以可以调整reduce的个数控制hive表的文件数量,
#hive中的分区函数 distribute by 正好是控制MR中partition分区的,
#然后通过设置reduce的数量,结合分区函数让数据均衡的进入每个reduce即可。#设置reduce的数量有两种方式,第一种是直接设置reduce个数
set mapreduce.job.reduces=10;#第二种是设置每个reduce的大小,Hive会根据数据总大小猜测确定一个reduce个数
set hive.exec.reducers.bytes.per.reducer=5120000000; -- 默认是1G,设置为5G#执行以下语句,将数据均衡的分配到reduce中
set mapreduce.job.reduces=10;
insert overwrite table A partition(dt)
select * from B
distribute by rand();解释:如设置reduce数量为10,则使用 rand(), 随机生成一个数 x % 10 ,
这样数据就会随机进入 reduce 中,防止出现有的文件过大或过小
4. 使用hadoop的archive将小文件归档

Hadoop Archive简称HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问

#用来控制归档是否可用
set hive.archive.enabled=true;
#通知Hive在创建归档时是否可以设置父目录
set hive.archive.har.parentdir.settable=true;
#控制需要归档文件的大小
set har.partfile.size=1099511627776;#使用以下命令进行归档
ALTER TABLE A ARCHIVE PARTITION(dt='2020-12-24', hr='12');#对已归档的分区恢复为原文件
ALTER TABLE A UNARCHIVE PARTITION(dt='2020-12-24', hr='12');

注意:
归档的分区可以查看不能 insert overwrite,必须先 unarchive

如果是新集群,没有历史遗留问题的话,建议hive使用 orc 文件格式,以及启用 lzo 压缩。这样小文件过多可以使用hive自带命令 concatenate 快速合并。

2.4. 并行执行优化

Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。如果有更多的阶段可以并行执行,那么job可能就越快完成。
通过设置参数hive.exec.parallel值为true,就可以开启并发执行。在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。

set hive.exec.parallel=true; //打开任务并行执行
set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。

当然得是在系统资源比较空闲的时候才有优势,否则没资源,并行也起不来。

2.5. JVM优化

JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。
Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间,具体多少需要根据具体业务场景测试得出。

<property><name>mapreduce.job.jvm.numtasks</name><value>10</value><description>How many tasks to run per jvm. If set to -1, there isno limit. </description>
</property>

我们也可以在hive中设置

set  mapred.job.reuse.jvm.num.tasks=10; //这个设置来设置我们的jvm重用

这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。

2.6. 推测执行优化

在分布式集群环境下,因为程序Bug(包括Hadoop本身的bug),负载不均衡或者资源分布不均等原因,会造成同一个作业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其他任务(比如一个作业的某个任务进度只有50%,而其他所有任务已经运行完毕),则这些任务会拖慢作业的整体执行进度。为了避免这种情况发生,Hadoop采用了推测执行(Speculative Execution)机制,它根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。
设置开启推测执行参数:Hadoop的mapred-site.xml文件中进行配置:

<property><name>mapreduce.map.speculative</name><value>true</value><description>If true, then multiple instances of some map tasks may be executed in parallel.</description>
</property><property><name>mapreduce.reduce.speculative</name><value>true</value><description>If true, then multiple instances of some reduce tasks may be executed in parallel.</description>
</property>

hive本身也提供了配置项来控制reduce-side的推测执行:

set hive.mapred.reduce.tasks.speculative.execution=true

关于调优这些推测执行变量,还很难给一个具体的建议。如果用户对于运行时的偏差非常敏感的话,那么可以将这些功能关闭掉。如果用户因为输入数据量很大而需要执行长时间的map或者Reduce task的话,那么启动推测执行造成的浪费是非常巨大大。

最后
代码优化原则:
-理透需求原则,这是优化的根本;
-把握数据全链路原则,这是优化的脉络;
-坚持代码的简洁原则,这让优化更加简单;
-没有瓶颈时谈论优化,这是自寻烦恼。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/892589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安全规约、脱敏规范、敏感逻辑的保护方案、防止 SQL 注入

文章目录 I 强制性安全规约平台资源的防重放机制URL 外部重定向传入的目标地址必须执行白名单过滤。表单、AJAX 提交必须执行 CSRF 安全验证。禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据。用户请求参数必须做有效性验证防止 SQL 注入用户敏感数据用户权限控制校验…

【数学】概率论与数理统计(五)

文章目录 [toc] 二维随机向量及其分布随机向量离散型随机向量的概率分布律性质示例问题解答 连续型随机向量的概率密度函数随机向量的分布函数性质连续型随机向量均匀分布 边缘分布边缘概率分布律边缘概率密度函数二维正态分布示例问题解答 边缘分布函数 二维随机向量及其分布 …

3.Qt Quick-QML地图引擎之v4.3版本(新增动态轨迹线/海图/天地图街道/天地图卫星)

在上个版本Qt Quick-QML地图引擎之v4版本(新增多模型切换/3D模型欧拉角模拟)_qt加载3d地图-CSDN博客更新了3D模拟功能&#xff0c;在4.3版本增加动态轨迹线、三个地图(海图/天地图街道/天地图卫星)。 4.3版本已经支持qt6 cmake版本&#xff0c;而4.3版本以下支持qt5版本&#x…

数据结构:DisjointSet

Disjoint Sets意思是一系列没有重复元素的集合。一种常见的实现叫做&#xff0c;Disjoint-set Forest可以以接近常数的时间复杂度查询元素所属集合&#xff0c;用来确定两个元素是否同属一个集合等&#xff0c;是效率最高的常见数据结构之一。 Wiki链接&#xff1a;https://en…

vmware-ubuntu22.04配置虚拟机win10,重新上网成功

打开问题显示 Hardware配置 Options配置 最后的Advanced&#xff0c;第一次用了BIOS&#xff0c;然后启动中有更新&#xff0c;然后关闭&#xff0c;再用UEFI启动

【2024年华为OD机试】(B卷,100分)- 数组去重和排序(Java JS PythonC/C++)

一、问题描述 题目描述 给定一个乱序的数组&#xff0c;删除所有的重复元素&#xff0c;使得每个元素只出现一次&#xff0c;并且按照出现的次数从高到低进行排序&#xff0c;相同出现次数按照第一次出现顺序进行先后排序。 输入描述 一个数组 输出描述 去重排序后的数组…

《零基础Go语言算法实战》【题目 2-10】接口的实现

《零基础Go语言算法实战》 【题目 2-10】接口的实现 请指出下面代码中存在的问题。 type Programmer struct { Name string } func (p *Programmer) String() string { return fmt.Sprintf("print: %v", p) } func main() { p : &Programmer{} p.String()…

C++ vtordisp的应用场景

文章目录 问题代码1. 基本概念回顾2. 应用场景虚继承与虚函数并存的类层次结构 3. 编译器相关考虑 问题代码 #include <iostream> using namespace std;class base { public:base() {}virtual void show() { cout << "base:: show"<<endl; } priv…

Git:merge合并、冲突解决、强行回退的终极解决方案

首先还是得避免冲突的发生&#xff0c;无法避免时再去解决冲突&#xff0c;避免冲突方法&#xff1a; 时常做pull、fatch操作&#xff0c;不要让自己本地仓库落后太多版本&#xff1b;在分支操作&#xff0c;如切换分支、合并分支、拉取分支前&#xff0c;及时清理Change&#…

2025网络架构

一、园区网络概述。 园区网络典型层次和区域&#xff1a; 核心层&#xff1a;是园区网骨干&#xff0c;是园区数据交换的核心&#xff0c;联接园区网的各个组成部分&#xff0c;如数据中心、管理中心、园区出口等。汇聚层&#xff1a;处于园区网的中间层次&#xff0c;完成数据…

Vue.config.productionTip = false 不起作用的问题及解决

文章目录 一、问题描述二、解决方法 一、问题描述 当我们在代码页面上引入Vue.js(开发版本)时&#xff0c;运行代码会出现以下提示&#xff0c;这句话的意思是&#xff1a;您正在开发模式下运行Vue&#xff0c;在进行生产部署时&#xff0c;请确保打开生产模式 You are runni…

【经管数据】ZF数字采购采购明细数据(2015.3-2024.3)

一、数据来源&#xff1a; 原始数据来源为ZF采购网。数据涵盖了自2015年3月至2024年3月的ZF数字采购合同明细&#xff0c;反映了数字化转型在政府采购中的应用情况。 二、参考文献&#xff1a; [1] 申志轩, 祝树金, 文茜, 等. ZF数字采购与企业数字化转型[J]. 数量经济技术经济…

啥!GitHub Copilot也免费使用了

文章目录 前言免费版直接修复代码多文件上下文Agent模式总结 前言 最近&#xff0c;GitHub 给开发者们带来了一个好消息&#xff1a;他们的 AI 编程助手 GitHub Copilot 现在可以免费使用了&#xff01;以前&#xff0c;每个月要花 10 美元才能享受的服务&#xff0c;现在对所…

013:深度学习之神经网络

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 深度学习是机器学习中重要的一个学科分支&#xff0c;它的特点就在于需要构建多层且“深度”的神经网络。 人们在探索人工智能初期&#xff0c;就曾设想构建一个用数学方式…

【NLP】语言模型的发展历程 (1)

语言模型的发展历程系列博客主要包含以下文章&#xff1a; 【NLP】语言模型的发展历程 (1)【NLP】大语言模型的发展历程 (2) 本篇博客是该系列的第一篇&#xff0c;主要讲讲 语言模型&#xff08;LM&#xff0c;Language Model&#xff09; 的发展历程。 文章目录 一、统计语…

JNI使用类签名及字段签名获取字段值

1.获取逻辑: 2.获取逻辑实现代码: extern "C" JNIEXPORT void JNICALL Java_com_example_jnibasetypedemo_MainActivity_getAnimalsNameFromJNI(JNIEnv *env, jobject thiz,jobjectArray animals) {jobject animalObj;int len env->GetArrayLength(animals);//获…

Vue 封装公告滚动

文章目录 需求分析1. 创建公告组件Notice.vue2. 注册全局组件3. 使用 需求 系统中需要有一个公告展示&#xff0c;且这个公告位于页面上方&#xff0c;每个页面都要看到 分析 1. 创建公告组件Notice.vue 第一种 在你的项目的合适组件目录下&#xff08;比如components目录&a…

Win10微调大语言模型ChatGLM2-6B

在《Win10本地部署大语言模型ChatGLM2-6B-CSDN博客》基础上进行&#xff0c;官方文档在这里&#xff0c;参考了这篇文章 首先确保ChatGLM2-6B下的有ptuning AdvertiseGen下载地址1&#xff0c;地址2&#xff0c;文件中数据留几行 模型文件下载地址 &#xff08;注意&#xff1…

HTTP-响应协议

HTTP的响应过程&#xff1f; 浏览器请求数据--》web服务器过程&#xff1a;请求过程 web服务器将响应数据-》到浏览器&#xff1a;响应过程 响应数据有哪些内容&#xff1f; 1.和请求数据类似。 2. 响应体中存储着web服务器返回给浏览器的响应数据。并且注意响应头和响应体之间…

爬虫基础之爬取歌曲宝歌曲批量下载

声明&#xff1a;本案列仅供学习交流使用 任何用于非法用途均与本作者无关 需求分析: 网站:邓紫棋-mp3在线免费下载-歌曲宝-找歌就用歌曲宝-MP3音乐高品质在线免费下载 (gequbao.com) 爬取 歌曲名 歌曲 实现歌手名称下载所有歌曲 本案列所使用的模块 requests (发送…