zoukankan      html  css  js  c++  java
  • Hive的压缩存储和简单优化

    一、Hive的压缩和存储

    1,MapReduce支持的压缩编码

    压缩格式

    工具

    算法

    文件扩展名

    是否可切分

    对应的编码/解码器

    DEFLATE

    DEFLATE

    .deflate

    org.apache.hadoop.io.compress.DefaultCodec

    Gzip

    gzip

    DEFLATE

    .gz

    org.apache.hadoop.io.compress.GzipCodec

    bzip2

    bzip2

    bzip2

    .bz2

    org.apache.hadoop.io.compress.BZip2Codec

    LZO

    lzop

    LZO

    .lzo

    com.hadoop.compression.lzo.LzopCodec

    Snappy

    Snappy

    .snappy

    org.apache.hadoop.io.compress.SnappyCodec

    2,文件压缩格式:

      TEXTFILE和SEQUENCEFILE的存储格式都是基于行式存储的;

      ORC和PARQUET是基于列式存储的。

    a>TextFile格式:

      默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用,但使用Gzip这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。

    b>Orc格式:

      Hive 0.11版里引入的新的存储格式,数据按行分块 每块按照列存储 ,压缩快 快速列存取,效率比rcfile高,是rcfile的改良版本,相比RC能够更好的压缩,能够更快的查询,但还是不支持模式演进。

    c>parquent格式:

      Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。

    在实际的项目开发当中,hive表的数据存储格式一般选择:orc或parquet。压缩方式一般选择snappy,lzo。

    二、Hive的企业级调优:

    1,Fetch抓取:

      默认开启。Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算(hive-default.xml.template文件中hive.fetch.task.conversion默认是more)例如:SELECT * FROM person;在这种情况下,Hive可以简单地读取person对应的存储目录下的文件,然后输出查询结果到控制台。

    2,本地模式:

      大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。

    set hive.exec.mode.local.auto=true//开启本地mr
    //设置local mr的最大输入数据量,当输入数据量小于这个值时采用local  mr的方式,默认为134217728,即128M
    set hive.exec.mode.local.auto.inputbytes.max=50000000;
    //设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
    set hive.exec.mode.local.auto.input.files.max=10;

    3,表的优化:

    a>大小表的join:

      新版的hive已经对小表JOIN大表和大表JOIN小表进行了优化。小表放在左边和右边已经没有明显区别。

    b>大表join大表:

      空key过滤:空key对应的数据无意义

    select n.* from (select * from nullidtable where id is not null ) n  left join ori o on n.id = o.id;

      空key转换:空key对应的数据还是有意义,需要保留

    #为空key赋予随机值,在进入reduce的时候防止空key太多而造成数据倾斜
    select
    n.* from nullidtable n full join ori o on case when n.id is null then concat('hive', rand()) else n.id end = o.id;

    c>MapJoin(小表join大表)

    #默认开启
    set hive.auto.convert.join = true;
    #大表小表的阈值设置(默认25M以下认为是小表)可以调整
    set hive.mapjoin.smalltable.filesize=25000000;

    d>group by:

      默认情况下,Map阶段同一个key数据分发到同一个reduce,当一个key的数据过大时就会出现数据倾斜。

    #是否在Map端进行聚合,默认为True
    set hive.map.aggr = true
    #在Map端进行聚合操作的条目数目 set hive.groupby.mapaggr.checkinterval = 100000
    #有数据倾斜的时候进行负载均衡(默认是false) set hive.groupby.skewindata = true

      当设置为负载均衡之后,生成的计划会有两个MR的job。第一个MRjob,Map的输出结果可能会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRjob再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。

    e>Count(distinct)去重统计

      数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT的全聚合操作,即使设定了reduce task个数,set mapred.reduce.tasks=100;hive也只会启动一个reducer,这就造成一个Reduce处理的数据量太大,导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换:

    #设置reduce个数为5
    set mapreduce.job.reduces = 5;
    #采用distinct去重
    select count(distinct id) from bigtable;
    #采用group by去重
    select count(id) from (select id from bigtable group by id) a;

      虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。 

    f>笛卡尔积

      尽量避免笛卡尔积,join的时候不加on条件,或者无效的on条件,Hive只能使用1reducer来完成笛卡尔积

    g>行列过滤

      列处理:在select中,只拿需要的列,如果有,尽量使用分区过滤,少用select *。

      行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在where后面,那么就会先全表关联,之后再过滤。

    #先关联再过滤
    select o.id from bigtable b join ori o on o.id = b.id
    #先过滤再关联
    select b.id from bigtable b
    join (select id from ori where id <= 10 ) o on b.id = o.id;

    h>动态分区

    1)开启动态分区功能(默认true,开启)
    set hive.exec.dynamic.partition=true2)设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
    set hive.exec.dynamic.partition.mode=nonstrict
    (3)在所有执行MR的节点上,最大一共可以创建多少个动态分区。默认1000
    set hive.exec.max.dynamic.partitions=10004)在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
    set hive.exec.max.dynamic.partitions.pernode=1005)整个MR Job中,最大可以创建多少个HDFS文件。默认100000
    set hive.exec.max.created.files=1000006)当有空分区生成时,是否抛出异常。一般不需要设置。默认false
    set hive.error.on.empty.partition=false

    i>分区

      分区表实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过WHERE子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。

    j>分桶

     分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分。分区针对的是数据的存储路径;分桶针对的是数据文件。

    #创建分桶表
    create table stu_buck(id int, name string)
    clustered by(id) 
    into 4 buckets
    row format delimited fields terminated by '	';
    #创建中间表
    create table stu(id int, name string) row format delimited fields terminated by ' ';
    #导入数据到中间表
    load data local inpath '/opt/module/datas/student.txt' into table stu;
    #开启分桶
    set hive.enforce.bucketing=true;
    #设置reduce数量为-1
    set mapreduce.job.reduces=-1;
    #向分桶表中导入数据
    insert into table stu_buck select id, name from stu;

    4,合理设置Map的数量和Reduce的数量

    a>复杂文件增加map数量

    增加map的方法为:根据computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,调整maxSize最大值。
    让maxSize最大值低于blocksize就可以增加map的个数。
    set mapreduce.input.fileinputformat.split.maxsize=100;

    b>小文件进行合并

    #设置为CombineHiveInputFormat合并小文件
    set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
    #在map-only任务结束时合并小文件,默认true
    set hive.merge.mapfiles = true;
    #在map-reduce任务结束时合并小文件,默认false
    set hive.merge.mapredfiles = true;
    #合并文件的大小,默认256M
    set hive.merge.size.per.task = 268435456;
    #当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge
    set hive.merge.smallfiles.avgsize = 16777216;

    c>合理设置reduce的个数

       1.调整reduce个数方法一

    1)每个Reduce处理的数据量默认是256MB
    hive.exec.reducers.bytes.per.reducer=2560000002)每个任务最大的reduce数,默认为1009
    hive.exec.reducers.max=10093)计算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任务处理数据量大小要合适;

    5,并行执行

      Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。

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

      在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。

    6,严格模式

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

      1)对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。(就是用户不允许扫描所有分区)

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

      3)限制笛卡尔积的查询。

    7,JVM重用

      JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。

      在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,推测执行

      Hadoop的mapred-site.xml文件中进行配置,默认是true

    <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的推测执行:默认是true

    <property>
        <name>hive.mapred.reduce.tasks.speculative.execution</name>
        <value>true</value>
        <description>Whether speculative execution for reducers should be turned on. </description>
    </property>

      不建议开启的情况:(1)任务间存在严重的负载倾斜;(2)特殊任务,比如任务向数据库中写数据。

    9,压缩

      见第一章

    10,explain执行计划

      利用explain查看sql的执行计划

  • 相关阅读:
    SpringBoot是如何动起来的
    Windows 10 安装 Docker for Windows
    Spring Boot2.0 设置拦截器
    修改博客园的css样式
    Spring-Aop
    Java自学-泛型 集合中的泛型
    Java自学-集合框架 聚合操作
    Java自学-集合框架 Comparator和Comparable
    Java自学-集合框架 hashCode原理
    Java自学-集合框架 HashSet、LinkedHashSet、TreeSet之间的区别
  • 原文地址:https://www.cnblogs.com/bbgs-xc/p/13048185.html
Copyright © 2011-2022 走看看