第4节 hive调优:2、数据倾斜

数据的倾斜:
主要就是合理的控制我们的map个数以及reduce个数

第一个问题:maptask的个数怎么定的???与我们文件的block块相关,默认一个block块就是对应一个maptask
第二个问题:reduceTask的个数怎么定的???是我们自己手动设置的,爱设几个设几个,没人管你

第三个问题:是不是maptask的个数越多越好:不一定:有时候有些小文件,都要启动一个maptask,分配资源的时间超过了数据处理的时间
减少mapTask的个数:设置map端的小文件合并:使用combineHiveInputFormat来实现对我们小文件的合并,减少maptask的个数 或者使用本地模式也可以解决小文件的问题
增加maptask的个数:我们可以多设置几个reduce,然后使用distribte by将我们的数据打散
set mapreduce.job.reduces =10;
create table a_1 as
select * from a
distribute by rand(123);
第四个问题:控制reduceTask的个数:
reduce个数设置方法:
(1)每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=256123456
(2)每个任务最大的reduce数,默认为1009
hive.exec.reducers.max=1009
(3)计算reducer数的公式
N=min(参数2,总输入数据量/参数1)

直接凭感觉设置reduce的个数:
set mapreduce.job.reduces = 15;

查看执行计划:
explain extended select * from course;


并行执行:有时候有些sql之间是不相关的,可以并行的一起执行,那么就可以用并行执行

严格模式: 如果开启hive的严格模式,有以下三个限制
1、分区表需要带上分区字段
2、order by 必须使用limit
3、笛卡尔积不能执行

jvm的重用:我们的container的里面的任务执行完成之后,不要马上释放资源,留着资源给下一个任务执行


推测执行:maptask的推测执行以及reducetask的推测执行:
一般都直接关闭maptask以及reducetask的推测执行
set mapreduce.map.speculative=false;关闭map端的推测执行
set mapreduce.reduce.speculative=false; 关闭reduce端的推测执行

压缩与存储:压缩:snappy 源始数据存储:TextFile
处理之后的数据存储:ORC PARQUET

===================================================

9.3 数据倾斜

9.3.1 Map数

1)通常情况下,作业会通过input的目录产生一个或者多个map任务。

主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M,可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改);

2)举例:

a)  假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数。

b) 假设input目录下有3个文件a,b,c大小分别为10m,20m,150m,那么hadoop会分隔成4个块(10m,20m,128m,22m),从而产生4个map数。即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。

3)是不是map数越多越好?

扫描二维码关注公众号,回复: 6576640 查看本文章

答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。

4)是不是保证每个map处理接近128m的文件块,就高枕无忧了?

答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。

针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;

9.3.2 小文件进行合并

在map执行前合并小文件,减少map数:

1)参数设置(下面的API属于hadoop低版本的API)

set mapred.max.split.size=112345600;

set mapred.min.split.size.per.node=112345600;

set mapred.min.split.size.per.rack=112345600;

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

这个参数表示执行前进行小文件合并,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并。

9.3.3 如何适当的增加map数

当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。

假设有这样一个任务:

Select data_desc,

count(1),

count(distinct id),

sum(case when …),

sum(case when …),

sum(…)

from a group by data_desc

如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。

set mapreduce.job.reduces =10;

create table a_1 as

select * from a

distribute by rand(123);

这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。

每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。

看上去,貌似这两种有些矛盾,一个是要合并小文件,一个是要把大文件拆成小文件,这点正是重点需要关注的地方,根据实际情况,控制map数量需要遵循两个原则:使大数据量利用合适的map数;使单个map任务处理合适的数据量;

9.3.4 reduce数

1)调整reduce个数方法一

(1)每个Reduce处理的数据量默认是256MB

hive.exec.reducers.bytes.per.reducer=256123456

       (2)每个任务最大的reduce数,默认为1009

hive.exec.reducers.max=1009

(3)计算reducer数的公式

N=min(参数2,总输入数据量/参数1)

2)调整reduce个数方法二

在hadoop的mapred-default.xml文件中修改

设置每个job的Reduce个数

set mapreduce.job.reduces = 15;

3)reduce个数并不是越多越好

1)过多的启动和初始化reduce也会消耗时间和资源;

2)另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;

在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;

9.4 使用EXPLAIN(执行计划)

1)基本语法

EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query

2)案例实操

(1)查看下面这条语句的执行计划

hive (default)> explain select * from course;

hive (default)> explain select s_id ,avg(s_score) avgscore from score group by s_id;

(2)查看详细执行计划

hive (default)> explain extended select * from course;

hive (default)> explain extended select s_id ,avg(s_score) avgscore from score group by s_id;

9.5 并行执行

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。

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

9.6 严格模式

Hive提供了一个严格模式,可以防止用户执行那些可能意向不到的不好的影响的查询。

       通过设置属性hive.mapred.mode值为默认是非严格模式nonstrict 。开启严格模式需要修改hive.mapred.mode值为strict,开启严格模式可以禁止3种类型的查询。

<property>

    <name>hive.mapred.mode</name>

    <value>strict</value>

    <description>

      The mode in which the Hive operations are being performed.

      In strict mode, some risky queries are not allowed to run. They include:

        Cartesian Product.

        No partition being picked up for a query.

        Comparing bigints and strings.

        Comparing bigints and doubles.

        Orderby without limit.

    </description>

  </property>

1)对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。

2)对于使用了order by语句的查询,要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。

3)限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN查询的时候不使用ON语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。

9.7 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 is

  no limit.

  </description>

</property>

我们也可以在hive当中通过

  set  mapred.job.reuse.jvm.num.tasks=10;

这个设置来设置我们的jvm重用

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

9.8 推测执行

在分布式集群环境下,因为程序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的推测执行:

  <property>

    <name>hive.mapred.reduce.tasks.speculative.execution</name>

    <value>true</value>

    <description>Whether speculative execution for reducers should be turned on. </description>

  </property>

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

9.9 压缩

参见前面

======================================================================

课程回顾:
1、数据仓库的概念: 了解
数据仓库的分层:分为三层:
第一层:源数据层 :贴源层 ODS层
第二层:数据仓库层:DW层 这一层主要负责sql的数据分析
第三层:应用层:APP层 数据展示层,所有的数据展示都在这一层做
2、hive的基本概念: 了解
hive不存储数据,也不会计算数据
数据的存储:hdfs
数据的计算:MapReduce
hive的元数据:映射关系:hive的表模型与hdfs的数据之间的一个映射关系,默认保持在derby,一般都会改成mysql或者oracle等等
查看mysql的运行状态:
serivce mysqld status
启动mysql的服务进程
service mysqld start
/etc/init.d/mysqld start
停止mysql的服务进程
service mysqld stop

hive的交互方式: 搞定
第一种:shell客户端进行交互 bin/hive
第二种:使用beeline进行连接 必须要启动 hiveserver2的这个服务
服务启动命令 bin/hive --service hiveserver2
第三种:hive -e "select xxx"
hive -f xxx.sql

hive的基本操作
创建数据库
创建数据库表: 搞定
表模型:内部表:管理表 删表的时候删除数据
外部表: 删表的时候不会删除数据 external
分区表: 分文件夹 partitioned by (month string)
分桶表: 分文件 按照某个字段进行数据的打散,分到多个文件里面去 clustered  by into xxx buckets
hive表加载数据:
load data [local] inpath 'xxx' into table xxxx partition(month= 'xxx')
insert overwrite table xxx partition(month='xxx') select xxxx

hive表的数据导出:了解
insert overwrite local directory


hive的查询语法: 搞定
group by 要注意: group by的字段要么出现在select字段后面,要么group by的字段少,要么就不出现

排序:
order by :全局的排序 只能有一个reduce来处理全局的排序,数据量大的话,可能会比较慢
distribte by id + sort by id = cluster by id


hive的shell参数:hive如何设置一些参数 了解
第一种设置方式:hive-site.xml
第二种设置方式 bin/hive -hiveconf xxx=xxx
第三种设置方式:set xxx=xxxx

hive函数: 熟悉自定义流程
hive的自定义函数:
UDF: 一行数据进去,一行数据出来
UDTF: 一行进多行出
UDAF: 多行进一行出 count()
hive的UDF自定义
流程需要熟悉
继承UDF 覆写evaluate 打包丢到lib下 add jar 创建临时函数进行关联

hive的数据压缩:snappy 知道
hive的存储格式: 知道
行式存储:TextFile sequenceFile
列式存储:ORC parquet

存储与压缩相结合
存储格式用orc 压缩方式用snappy


hive的调优: 好好看一看
fetch抓取:尽量避免mr的执行
表的优化:
数据倾斜:控制map的个数以及reduce的个数
explain:查看执行计划
并行执行:多个sql可以一起执行
严格模式:order by必须要带limit 分区表必须要带分区字段 笛卡尔积不能执行
jvm的重用: maptask使用完成的资源不要释放,可以留着给其他的任务继续运行
推测执行:关闭推测执行
压缩与存储:

猜你喜欢

转载自www.cnblogs.com/mediocreWorld/p/11072148.html