Hive数据倾斜
什么是数据倾斜
数据倾斜就是由于数据分布不均匀导致大量数据集中一点,造成数据热点的现象。
主要表现
数据任务进度长时间维持在99%,查看任务监控发现仅有少量reduce子任务未完成,处理时长远大于其他reduce处理的平均时长
可能情况
- group by 不和聚集函数搭配使用的时候
- count(distinct),在数据量大的情况下,容易数据倾斜,因为 count(distinct)是按 group by 字段分组,按 distinct 字段排序
- 小表关联超大表 join
原因
- key 分布不均匀
- 业务数据本身的特性
- 建表考虑不周全
- HQL语句书写问题
Hive任务执行过程
执行流程
- Hive 将 HQL 转换成一组操作符(Operator),比如 GroupByOperator, JoinOperator 等
- 操作符 Operator 是 Hive 的最小处理单元
- 每个操作符代表一个 HDFS 操作或者 MapReduce 作业
- Hive 通过 ExecMapper 和 ExecReducer 执行 MapReduce 程序,执行模式有本地模式和分 布式两种模式
操作符列表
SQL解析器职责
- Parser:将 HQL 语句转换成抽象语法树(AST:Abstract Syntax Tree)
- Semantic Analyzer:将抽象语法树转换成查询块
- Logic Plan Generator:将查询块转换成逻辑查询计划
- Logic Optimizer:重写逻辑查询计划,优化逻辑执行计划
- Physical Plan Gernerator:将逻辑计划转化成物理计划(MapReduce Jobs)
- Physical Optimizer:选择最佳的 Join 策略,优化物理执行计划
join操作实现过程
Map:
1、以 JOIN ON 条件中的列作为 Key,如果有多个列,则 Key 是这些列的组合
2、以 JOIN 之后所关心的列作为 Value,当有多个列时,Value 是这些列的组合。在 Value 中还会包含表的 Tag 信息,用于标明此 Value 对应于哪个表
3、按照 Key 进行排序
Shuffle:
1、根据 Key 的值进行 Hash,并将 Key/Value 对按照 Hash 值推至不同对 Reduce 中
Reduce:
1、 Reducer 根据 Key 值进行 Join 操作,并且通过 Tag 来识别不同的表中的数据
distinct实现
SQL 语句会按照 key预先分组,进行 distinct 操作。
Hive数据压缩
优缺点分析
优势:
- 减少IO及磁盘空间
- 减少带宽及网络传输
缺点:
- 需要额外时间去做压缩/解压缩计算,属于时间换空间策略
压缩分析
首先说明 mapreduce 哪些过程可以设置压缩:需要分析处理的数据在进入 map 前可以压缩,然后解压处理,map 处理完成后的输出可以压缩,这样可以减 少网络 I/O(reduce 通常和 map 不在同一节点上),reduce 拷贝压缩的数据后进 行解压,处理完成后可以压缩存储在 hdfs 上,以减少磁盘占用量。
压缩算法
压缩格式 |
压缩格式所在的类 |
Zlib |
org.apache.hadoop.io.compress.DefaultCodec |
Gzip |
org.apache.hadoop.io.compress.GzipCodec |
Bzip2 |
org.apache.hadoop.io.compress.BZip2Codec |
Lzo |
com.hadoop.compression.lzo.LzoCodec |
Lz4 |
org.apache.hadoop.io.compress.Lz4Codec |
Snappy |
org.apache.hadoop.io.compress.SnappyCodec |
压缩设置
-- 开启 hive 中间传输数据压缩功能 set hive.exec.compress.intermediate=true; -- 开启 mapreduce 中 map 输出压缩功能 set mapreduce.map.output.compress=true; -- 开启 hive 最终输出数据压缩功能 set hive.exec.compress.output=true; -- 开启 mapreduce 最终输出数据压缩 set mapreduce.output.fileoutputformat.compress=true; -- 设置 mapreduce 最终数据输出压缩为块压缩 set mapreduce.output.fileoutputformat.compress.type=BLOCK;
Hive数据存储格式对比
列存储与行存储
行存储
优点:
- 相关的数据是保存在一起,比较符合面向对象的思维,因为一行数据就是一 条记录
- 比较方便进行 INSERT/UPDATE 操作
缺点:
- 如果查询只涉及某几个列,它会把整行数据都读取出来,不能跳过不必要的 列读取。当然数据比较少,一般没啥问题,如果数据量比较大就比较影响性能
- 由于每一行中,列的数据类型不一致,导致不容易获得一个极高的压缩比, 也就是空间利用率不高
- 不是所有的列都适合作为索引
列存储
优点:
- 查询时,只有涉及到的列才会被查询,不会把所有列都查询出来,即可以跳 过不必要的列查询;
- 高效的压缩率,不仅节省储存空间也节省计算内存和 CPU;
- 任何列都可以作为索引;
缺点:
- INSERT/UPDATE 很麻烦或者不方便;
- 不适合扫描小量的数据
Hive常见存储格式
行式存储 TEXTFILE
默认格式,数据不做压缩处理,磁盘开销大,数据解析开销大
列式存储 ORC
Optimized Row Columnar,ORC 文件格式是一种 Hadoop 生态 圈中的列式存储格式,ORC并不是一个单纯的列式格式,仍然是首先根据行组分割整个表,在每一个行组内进行按列存储。
- Index Data:一个轻量级的 index,默认是每隔 1W 行做一个索引。这里做 的索引只是记录某行的各字段在 Row Data 中的 offset。
- Row Data:存的是具体的数据,先取部分行,然后对这些行按列进行存储。 对每个列进行了编码,分成多个 Stream 来存储。
- Stripe Footer:存的是各个 stripe 的元数据信息。
每个文件有一个 File Footer,这里面存的是每个 Stripe 的行数,每个 Column 的数据类型信息等;每个文件的尾部是一个 PostScript,这里面记录了整个文件 的压缩类型以及 FileFooter 的长度信息等。在读取文件时,会 seek 到文件尾部读 PostScript,从里面解析到 File Footer 长度,再读 FileFooter,从里面解析到各个 Stripe 信息,再读各个 Stripe,即从后往前读。
列式存储 PARQUET
由 Twitter 和 Cloudera 合作开 发,2015 年 5 月从 Apache 的孵化器里毕业成为 Apache 顶级项目。
通常情况下,在存储 Parquet 数据的时候会按照 Block 大小设置行组的大小, 由于一般情况下每一个 Mapper 任务处理数据的最小单位是一个 Block,这样可 以把每一个行组由一个 Mapper 任务处理,增大任务执行并行度。
在 Parquet 中,有三种类型的页:数据页、字典页和索引页。数据页用于存储当前 行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包含一个字 典页,索引页用来存储当前行组下该列的索引,目前 Parquet 中还不支持索引页, 但是在后面的版本中增加。