Hive教程(09)- 彻底解决小文件的问题

简介: Hive教程(09)- 彻底解决小文件的问题

01 引言

在前面的教程,已经初步入门hive了,有兴趣的同学可以参阅:

本文主要讲解在Hive下如何解决小文件的问题。

02 小文件概述

2.1 小文件的缘由

我们都知道HDFS的场景适合一次写入,多次读出的场景,也就是为了“”,“”的时候慢点也是可以的。

就偏偏在再“”的时候,我们发现随着时间的推移,hdfs的文件会越来越多,特别是hdfs增量插入的时候,每次增量可能就几条数据,但是这几条数据占用一个文件,如下图:

2.1 小文件的危害

这个缺点会引发很大的问题,先贴上一张hdfs的架构图:

因为Namenode负责hdfs文件系统索引目录和文件结构进行管理的,假如存在大量的小文件,会造成如下问题:

  • 增加Namenode的存储和计算压力:因为Namenode不像Datanode那样多个节点共同工作(datanode有多个副本);
  • 占用Namenode内存资源:当Client读取或者写入大量小文件则有可能给Namenode造成很大压力,如果Namenode内存使用完了,这个集群将不能再存储文件了,最终影响整个集群稳定性。

可以知道,随着小文件的增加,客户需要从Namenode获取元信息,再从Datanode读取对应数据的时间也会变长。

03 小文件解决方案

解决小文件的问题,首选方案就是 “hive合并小文件”。

可以根据如下思路去解决:

  • 方式一:对已有的数据进行定时或实时的小文件合并
  • 方式二:在生成小文件前,进行相关的配置合并来预防
  • 方式三:使用HAR归档文件

3.1 方式一:处理已有的小文件

3.1.1 distribute by 命令

处理已有的小文件可以实时或定时操作,定时操作可在访问低峰期操作,如凌晨2点。

使用hive操作命令:

insert overwrite table 目标表 [partition(hour=...)] select * from 目标表 
distribute by cast( rand() * 具体最后落地生成多少个文件数 as int);

这里描述一下以上的几个关键字:

  • insert overwrite:会重写数据,先进行删除后插入(不用担心如果overwrite失败,数据没了,这里面是有事务保障的);
  • distribute by:它的作用是控制在map端如何拆分数据给reduce端的,distribute by后面列是控制落地文件数,默认是采用hash算法;
  • ran()函数:控制最终生成多少个文件。

举例:控制dt分区目录下生成100个文件,且文件大小基本一致,那么hsql如下:

insert overwrite table test partition(dt)
select * 
from test
distribute by cast(rand()*100 as int);

3.1.2 concatenate 命令

如果是orc格式存储的表,还可以使用如下命令进行小文件的合并:

alter table test [partition(...)] concatenate

注意:这种方法仅仅适用于orc格式存储的表。

3.1.3 定时方案

定时方案执行distribute by 命令的方案有两种:

  • Linux crontab 控制
  • Java代码控制
3.1.3.1 Linux crontab 控制

cron命令如下(每晚凌晨0点执行):

0 0 * * * $home/bin/command.s

主要的疑难点在于执行脚本(command.sh)的编写。

因为连接hive需要用到了hive安装包里面自带的beeline,需要输入账号密码,等待连接成功后才能进行相关的HSQL操作,而且如果要合并所有分区的小文件,需要遍历所有的表的所有分区,然后依次执行合并小文件的hsql,过程不易控制且账号密码等信息暴露了。

3.1.3.2 Java代码控制(推荐)

如果使用java代码控制,可控粒度比较细,可以通过jdbc的方式去控制。

它的缺点是需要在主工程里引入hive-jdbc的依赖,增加包的体积,如果是分布式的环境,配置的hive连接地址可能不同,用户的访问权限可能需要设置(如hadoop里面的core-site.xml文件)。

3.2 方式二:预防小文件

有些公司用的版本不同,低版本可能有些配置不一样,最好检查一下上面这些配置是否设置,然后根据自己的实际集群情况进行设置

通过调节hive参数的方式预防,配置与注释如下(在hive-site.xml配置也可以):

## 每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;  
## 一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
## 一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)  
set mapred.min.split.size.per.rack=100000000;
## 执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 
## 设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
## 设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
## 设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
## 当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000

3.3 方式三:使用HAR归档文件

运用于每日定时脚本,对于已经产生小文件的hive表可以使用har归档,而且hive提供了原生支持:

set  hive.archive.enabled=  true ;
set  hive.archive.har.parentdir.settable=  true ;
set  har.partfile.size=256000000;
ALTER TABLE  ad_dev.wlb_tmp_smallfile_20210118 ARCHIVE PARTITION(pt='2022-03-01');

04 文末

本文主要讲解在Hive下解决小文件的方案,谢谢大家的阅读,本文完!

目录
相关文章
|
8月前
|
SQL Java 数据库连接
Hive教程(08)- JDBC操作Hive
Hive教程(08)- JDBC操作Hive
377 0
|
8月前
|
SQL 分布式计算 Java
Hive教程(07)- Hive自定义用户名密码验证(已开源)
Hive教程(07)- Hive自定义用户名密码验证(已开源)
214 0
|
8月前
|
SQL 分布式计算 Shell
Hive教程(05)- Hive命令汇总(上)
Hive教程(05)- Hive命令汇总(上)
152 0
|
2月前
|
SQL 存储 算法
【Hive】Hive 小文件过多怎么解决?
【4月更文挑战第16天】【Hive】Hive 小文件过多怎么解决?
|
2月前
|
SQL 存储 分布式计算
Hive【基础知识 02-2】【Hive CLI 命令行工具使用】【详细举例-包含测试脚本文件】
【4月更文挑战第7天】Hive【基础知识 02-2】【Hive CLI 命令行工具使用】【详细举例-包含测试脚本文件】
37 0
|
11月前
|
SQL 存储 分布式计算
Hive学习---6、文件格式和压缩
Hive学习---6、文件格式和压缩
Hive学习---6、文件格式和压缩
|
8月前
|
SQL 分布式计算 HIVE
Hive教程(05)- Hive命令汇总(下)
Hive教程(05)- Hive命令汇总(下)
50 0
Hive教程(05)- Hive命令汇总(下)
|
8月前
|
SQL 存储 API
Flink教程(25)- Flink高级特性(FlinkSQL整合Hive)
Flink教程(25)- Flink高级特性(FlinkSQL整合Hive)
520 0
|
8月前
|
SQL 存储 Java
Hive教程(06)- Hive SerDe序列化与反序列化
Hive教程(06)- Hive SerDe序列化与反序列化
141 0
|
8月前
|
SQL 存储 Java
Hive教程(04)- Hive数据类型
Hive教程(04)- Hive数据类型
127 0