Hive介绍
Hive是基于Hadoop的一个数据仓库工具,它提供了数据提取、转化、加载(ETL)的功能,并能够将结构化的数据文件映射为一张数据库表,以支持SQL查询功能。Hive能够将SQL语句自动的转化为MapReduce任务来执行,不需要开发人员认为重构map与reduce方法满足自己的运算逻辑,使得大数据处理变得更加简单和高效,而涉及海量数据的计算的SQL往往需要大量的运行时间,这让我们不得不注重hive运行的调优。
Hive常见调优
资源调优
对于不同的集群的硬件配置,自然需要不同的配置才能达到hive最佳状态,资源没给够时,hive也可能跑的慢,资源调优主要是调整yarn与mapreduce配置文件
Yarn
需要调整的 Yarn 参数均与CPU、内存等资源有关
yarn.nodemanager.resource.memory-mb | 一个 NodeManager 节点分配给 Container 使用的内存。该参数的配 置,取决于 NodeManager 所在节点的总内存容量和该节点运行的其他服务的数量。 |
yarn.nodemanagerresource.cpu-vcores | 一个 NodeManager 节点分配给 Container 使用的 CPU 核数。该参数的配置,同样取决于 NodeManager 所在节点的总 CPU 核数和该节点运行的其他服务。 |
yarn.scheduler.maximum-allocation-mb | 单个 Container 能够使用的最大内存 |
yarn.scheduler.minimum-allocation-mb | 单个 container 能够使用的最小内存 |
MapReduce
MapReduce 资源配置主要包括 Map Task 的内存和 CPU 核数,以及 Reduce Task 的内存和CPU核数
mapreduce.map.memory.mb | 单Map Task申请的 container 容器内存大小,其默认值为 1024,该值不能超出 yarn.scheduler.maximum-allocation-mb yarn.scheduler.minimum-allocation-mb 规定的范围 |
mapreduce.map.cpu.vcores | 单个 Map Task 申请的 container 容器 cpu 核数,其默认值为 1。 |
mapreduce.reduce.memory.mb | 单个 Reduce Task 申请的 container 容器内存大小其默认值为1024,同上该值有范围 |
mapreduce.reduce.cpu.vcores | 单个 Reduce Task 申请的 container 容器 cpu 核数,其默认值为 1。 |
sql语句
older by | 全局排序 表示 全局排序 相当于MapReduce 阶段 只有一个reduce |
sort by | 分区内排序 |
cluster by | 等价于 distribute by 【】 sort by【】 |
对于hiveSQL的编写,有一些通识需要注意:
- 由于older by的作用域是全局,不建议使用。(一定要用older by 要跟 limit 限制查询条数),建议使用sort by并且保证每个reducer内局部有序。为了控制map端数据分配到reducer的key,往往还要配合distribute by一同使用
- distinct会将列中所有的数据保存到内存中 ,极有可能发生内存溢出。采用sum() group by的方式来替换count(distinct) 完成计算。
- 注意小表在
JOIN
操作中的位置,通常小表应该放在JOIN
的左边,这有助于减少数据传输的开销。 - 只选择需要使用到的字段,避免使用
SELECT *
,这样可以减少不必要的数据读取和传输。
hive文件压缩
- 选择适当的文件格式(如ORC、Parquet等)可以减少I/O操作的开销。
- 使用压缩算法(如Snappy、LZO等)可以减少磁盘空间的使用并提高性能。
Tez引擎
Tez: 是基于Hadoop Yarn之上的DAG(有向无环图,Directed Acyclic Graph)计算框架。它把Map/Reduce过程拆分成若干个子过程,同时可以把多个Map/Reduce任务组合成一个较大的DAG任务,减少了Map/Reduce之间的文件存储。同时合理组合其子过程,也可以减少任务的运行时间
手动开启
hive.execution.engine = tez;通过上述设置,执行的每个HIVE查询都将利用Tez,
执行计划调优
分组聚合 mapside
但在某些情况下,可以通过优化将部分聚合操作在Map阶段完成,即所谓的Map-side聚合。Map-side聚合能够减少数据传输量,降低Reduce阶段的负载,从而提高查询性能。
由于Map-side聚合需要在Map任务中缓存中间结果,可以看作用内存空间换取计算时间,需要注意内存管理。确保为每个Map任务分配足够的内存,以避免内存溢出错误。
join算法
Common Join
Common Join是Hive 中最稳定的 join算法其通过一个MapReduce Job 完成一个 join 操作。Map 端负责读取 join 操作所需表的数据,并按照关联字段进行分区,通过 Shuffle,将其发送到Reduce 端,相同 key 的数据在 Reduce 端完成最终的Join 操作。
Map Join
Map Join 算法可以通过两个只有 map 阶段的Job 完成一个 join 操作。其适用场景为 大表 join 小表。若某 join 操作满足要求, 则第一个 Job 会读取小表数据, 将其制作为hash table,并上传至 Hadoop 本质上是上传至HDFS。第二个 Job 会先分布式缓存中读取小表数据,并缓存在 Map Task 的内存中,然后扫描大表数据,这样在map 端即可完成关联操作。
触发方式:
- 语句增加hint提示
- hive优化器自动触发,系统在不知道task情况,有一套自动流程,可以就触发map join,不可以就common join。
Bucket Map Join
Bucket Map Join 是对 Map Join 算法的改进,其打破了 Map Join 只适用于大表 join小表的限制,可用于大表 join 大表的场景。 Bucket Map Join 的核心思想是:若能保证参与 join 的表均为分桶表 且关联字段为分桶字段,且其中一张表的分桶数量是另外一张表分桶数量的整数倍,就能保证参与 join的两张表的分桶之间具有明确的关联关系,所以就可以在两表的分桶间进行 Map Join 操作了。这样一来,第二个 Job 的 Map 端就无需再缓存小表的全表数据了,而只需缓存其所需的分桶即可。
不支持自动转换,需手动配置。
Sort Merge Bucket Map Join
Sort Merge Bucket Map Join (简称 SMB Map Join)基于 Bucket Map Join。SMB Map Join 要求,参与 join 的表均为分桶表,且需保证分桶内的数据是有序的,且分桶字段、 排序字段和关联字段为相同字段,且其中一张表的分桶数量是另外一张表分桶数量的整数 倍。 SMB Map Join同Bucket Join 一样,同样是利用两表各分桶之间的关联关系,在分桶 之间进行 join操作,不同的是,分桶之间的 join 操作的实现原理。Bucket Map Join,两 个分桶之间的 join 实现原理为Hash Join 算法:而SMB Map Join,两个分桶之间的 join 实现原理为 Sort Merge Join 算法(已排好序) Hash Join 和 Sort Merge Join 均为关系型数据库中常见的 Join 实现算法。Hash Toin 的原理相对简单,就是对参与 join 的一张表构建 hash table,然后扫描另外一张表 然后进行逐行匹配。Sort Merge Join 需要在两张按照关联字段排好序的表中进行。
相对于bucket map 对内存要求更低,甚至不需要将桶载入内存。
手动配置
数据倾斜
数据倾斜问题,通常是指参与计算的数据分布不均,即某个 key 或者某些 key 的数据
量远超其他 key,导致在 shuffle 阶段,大量相同 key 的数据被发往同一个 Reduce,进而导
致该Reduce 所需的时间远超其他 Reduce,成为整个任务的瓶颈。也就是说在MapReduce任务过程中,可能绝大部分任务早早完成,剩下一两个reduce任务难以结束,而这就是数据倾斜导致的。
Hive 中的数据倾斜常出现在分组聚合和 join 操作的场景中。
分组聚合导致数据倾斜如何解决
1 map-side聚合
开启 Map-Side 聚合后,数据会现在 Map 端完成部分聚合工作。这样一来即便原始数
据是倾斜的,经过 Map 端的初步聚合后,发往 Reduce 的数据也就不再倾斜了。最佳状态
下,Map-端聚合能完全屏蔽数据倾斜问题。
详细见上文 执行计划调优-分组聚合 mapside
2 Skew-GroupBy 优化
Skew-GroupBy 的原理是启动两个MR 任务,第一个M 按照随机数分区,将数据分散发
送到 Reduce,在第一个MapReduce任务中,数据被随机分配到不同的Map任务进行处理。这些Map任务将数据转换为键值对,并根据随机数进行分组。随机数的作用是使得相同键的值可能被分配到不同的Map任务中。通过这种方式,原本可能全部进入同一个Reduce任务的倾斜key的数据被分散到了多个Map任务中,从而避免了单个Reduce任务处理大量数据的情况。完成部分聚合,第二个 MR 按照分组字段分区,完成最终聚合。
# 启用skew groupby优化
set hive.groupby.skewindata = true; # (默认关闭)
join导致数据倾斜如何解决
1 map join(大表-小表)
使用 map join 算法,join 操作仅在 map 端就能完成,没有 shuffle 操作,没有 reduce
阶段,自然不会产生 reduce 端的数据倾斜。该方案适用于大表 join 小表时发生数据倾斜的
场景。(前文join算法详细提及)。
2 skew join(大表-大表 一对多)一般第一张表key值少方便map join
单独为倾斜大的key值启动map join进行计算,其余key值进行正常的common join。一般不会遇到同一个字段在两表中都倾斜。
3 SQL语句调整(打散倾斜key值)
- 一般来讲倾斜的key都很少,我们可以将它们抽样出来,对应的行单独存入临时表中,然后打上一个较小的随机数前缀(比如0~9),最后再进行聚合。 (null值可直接替换为随机数)
-
select
*
from(
select --打散操作
concat(id,'_',cast(rand()*10 as int)) id,
value
from A
)ta
join(
select --扩容操作 满足成功join
concat(id,'_',0) id,
value
from B
union all
select
concat(id,'_',1) id,
value
from B)tb - .........
- on ta.id=tb.id;