zoukankan      html  css  js  c++  java
  • 合并hive/hdfs小文件

    磁盘:

    heads/sectors/cylinders,分别就是磁头/扇区/柱面,每个扇区512byte(现在新的硬盘每个扇区有4K)

    文件系统:

    文件系统不是一个扇区一个扇区的来读数据,太慢了,所以有了block(块)的概念,它是一个块一个块的读取的,block才是文件存取的最小单位。

    文件系统中1个块是由连续的8个扇区组成。

    HDFS:

    默认文件大小64M(或者是128M)

    hive小文件问题解决

    问题描述

    HDFS的文件元信息,包括位置、大小、分块信息等,都是保存在NameNode的内存中的。每个对象大约占用150个字节,因此一千万个文件及分块就会占用约3G的内存空间,一旦接近这个量级,NameNode的性能就会开始下降了。

    Hive小文件产生的原因
     
    前面已经提到,汇总后的数据量通常比源数据要少得多。而为了提升运算速度,我们会增加Reducer的数量,Hive本身也会做类似优化——Reducer数量等于源数据的量除以hive.exec.reducers.bytes.per.reducer所配置的量(默认1G)。Reducer数量的增加也即意味着结果文件的增加,从而产生小文件的问题。
    解决小文件的问题可以从两个方向入手:
    1. 输入合并。即在Map前合并小文件
    2. 输出合并。即在输出结果的时候合并小文件
     
    配置Map输入合并
     
    set hive.merge.mapfiles = true ##在 map only 的任务结束时合并小文件
    
    set hive.merge.mapredfiles = false ## true 时在 MapReduce 的任务结束时合并小文件
    
    set hive.merge.size.per.task = 256*1000*1000 ##合并文件的大小
    
    set mapred.max.split.size=256000000; ##每个 Map 最大分割大小
    
    set mapred.min.split.size.per.node=1; ##一个节点上 split 的最少值
    
    set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; ##执行 Map 前进行小文件合并
     
    配置Hive结果合并
     
    SET hive.exec.dynamic.partition.mode=nonstrict;
    SET hive.exec.max.dynamic.partitions=10000000; 
    SET hive.exec.max.dynamic.partitions.pernode=100000; 
    SET hive.merge.tezfiles=true; 
    -- 动态分区
    insert overwrite table xxx  PARTITION (dt)
    select *
    from xxx
    where dt>='2017-02-01' and dt<'2017-04-01';
    -- 静态分区
    nsert overwrite table xxx  PARTITION (dt='2017-02-01')
    select 
    a1,a2,a3
    from xxx
    where dt='2017-02-01';
     
    我们可以通过一些配置项来使Hive在执行结束后对结果文件进行合并:
     
    hive.merge.mapfiles 在map-only job后合并文件,默认true
    hive.merge.mapredfiles 在map-reduce job后合并文件,默认false
    hive.merge.size.per.task 合并后每个文件的大小,默认256000000
    hive.merge.smallfiles.avgsize 平均文件大小,是决定是否执行合并操作的阈值,默认16000000
     
    Hive在对结果文件进行合并时会执行一个额外的map-only脚本,mapper的数量是文件总大小除以size.per.task参数所得的值,触发合并的条件是:
    根据查询类型不同,相应的mapfiles/mapredfiles参数需要打开;
    结果文件的平均大小需要大于avgsize参数的值。
    示例:
     
    -- map-red job,5个reducer,产生5个60K的文件。
    create table dw_stage.zj_small as
    select paid, count (*)
    from dw_db.dw_soj_imp_dtl
    where log_dt = '2014-04-14'
    group by paid;
    -- 执行额外的map-only job,一个mapper,产生一个300K的文件。
    set hive.merge.mapredfiles= true;
    create table dw_stage.zj_small as
    select paid, count (*)
    from dw_db.dw_soj_imp_dtl
    where log_dt = '2014-04-14'
    group by paid;
    -- map-only job,45个mapper,产生45个25M左右的文件。
    create table dw_stage.zj_small as
    select *
    from dw_db.dw_soj_imp_dtl
    where log_dt = '2014-04-14' ;
    -- 执行额外的map-only job,4个mapper,产生4个250M左右的文件。
    set hive.merge.smallfiles.avgsize=100000000;
    create table dw_stage.zj_small as
    select *
    from dw_db.dw_soj_imp_dtl
    where log_dt = '2014-04-14';
     
    压缩文件的处理
    对于输出结果为压缩文件形式存储的情况,要解决小文件问题,如果在Map输入前合并,对输出的文件存储格式并没有限制。但是如果使用输出合并,则必须配合SequenceFile来存储,否则无法进行合并,以下是示例:
     
    set mapred.output.compression. type=BLOCK;
    set hive.exec.compress.output= true;
    set mapred.output.compression.codec=org.apache.hadoop.io.compress.LzoCodec;
    set hive.merge.smallfiles.avgsize=100000000;
    drop table if exists dw_stage.zj_small;
    create table dw_stage.zj_small
    STORED AS SEQUENCEFILE
    as select *
    from dw_db.dw_soj_imp_dtl
    where log_dt = '2014-04-14' ;
     
    使用HAR归档文件
     
    Hadoop的归档文件格式也是解决小文件问题的方式之一。而且Hive提供了原生支持:
     
    set hive.archive.enabled= true;
    set hive.archive.har.parentdir.settable= true;
    set har.partfile.size=1099511627776;
    ALTER TABLE srcpart ARCHIVE PARTITION(ds= '2008-04-08', hr= '12' );
    ALTER TABLE srcpart UNARCHIVE PARTITION(ds= '2008-04-08', hr= '12' );
     

    Hadoop Archive是一种特殊的归档格式,Hadoop Archive映射到文件系统目录,一个HAR以扩展名.har结尾,一个HAR目录包含元数据(以_index和_masterindex的形式)和data(part- *)文件。 _index文件包含文件名称,这些文件时归档的一部分,并且包含这些文件在归档中的位置。

    hadoop archive -archiveName name -p <parent> <src>* <dest>

    -archiveName用来指定你想创建的归档名称,parent用来指定需要归档文件的相对路径的父参数(支持正则表达式)。需要注意的是归档是一个map/reduce。如下使用例子:

    hadoop archive -archiveName zoo.har -p /foo/bar a/b/c e/f/g /outputdir

    在以上例子中/foo/bar是a/b/c, e/f/g的父目录。如果你想直接对一个目录进行归档,可以直接使用如下命令:

    hadoop archive -archiveName zoo.har -p /foo/bar /outputdir

    档案(archive)属于文件系统层,使用不同的URI,在档案中可以使用所有的fs shell命令,需要注意的是档案是不可变的,不能够被删除,重命名和创建。HAR的URI格式如下所示:

    har://scheme-hostname:port/archivepath/fileinarchive

  • 相关阅读:
    .Net Core DI依赖注入:一个接口注入多个实现类(转载)
    单表千万行数据库 LIKE 搜索优化手记(链接)
    Do the JSON keys have to be surrounded by quotes?(转载)
    梳理情绪解决问题
    MYSQL主从数据库同步备份配置的方法
    VMware ESXI 6.5 安装及配置
    linux centos7 完整邮件服务器搭建及调用_2018_lcf
    利用Tampermonkey(油猴)+ IDM 实现百度云盘大文件下载(IDM安装教程)
    Java中使用feign遇到的坑
    微服务为什么要有服务发现与注册?
  • 原文地址:https://www.cnblogs.com/linn/p/10221108.html
Copyright © 2011-2022 走看看