在生产中,无论是通过SQL语句或者Scala/Java等代码的方式使用Spark SQL处理数据,在Spark SQL写数据时,往往会遇到生成的小文件过多的问题,而管理这些大量的小文件,是一件非常头疼的事情。

大量的小文件会影响Hadoop集群管理或者Spark在处理数据时的稳定性:

1. Spark SQL写Hive或者直接写入HDFS,过多的小文件会对NameNode内存管理等产生巨大的压力,会影响整个集群的稳定运行

2. 容易导致task数过多,如果超过参数spark.driver.maxResultSize的配置(默认1g),会抛出类似如下的异常,影响任务的处理

Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Total size of serialized results of 478 tasks (2026.0 MB) is bigger than spark.driver.maxResultSize (1024.0 MB)

当然可以通过调大spark.driver.maxResultSize的默认配置来解决问题,但如果不能从源头上解决小文件问题,以后还可能遇到类似的问题。

此外,Spark在处理任务时,一个分区分配一个task进行处理,多个分区并行处理,虽然并行处理能够提高处理效率,但不是意味着task数越多越好。如果数据量不大,过多的task运行反而会影响效率。

下面通过一个例子,Spark SQL写数据时,导致产生分区数"剧增"的典型场景,通过分区数"剧增",以及Spark中task数和分区数的关系等,来倒推小文件过多的可能原因(这里的分区数是指生成的DataSet/RDD的分区数,不是Hive分区表的分区概念):

1. 现象

1) 对表test_tab进行写入操作
2) t1的分区数是100,t2的分区数是200,union all后生成的tmp分区数是300
3) test_tab产生的小文件数基本也在300左右
select * from t1 union all select * from t2 as tmp;insert overwrite table test_tab select * from tmp;

2. 分析

1)执行上述insert操作时的分区并行度,主要受tmp的分区数(对应一个DataSet)影响,

2)tmp的分区数主要受t1、t2以及union all的影响

3)暂且不考虑t1或t2是物理表还是经过其他处理生成的临时表,它们的分区数是确定的,这里主要看经过union all处理后,生成的tmp的分区数和t1、t2的分区数有何关系?

4)Spark SQL语句中的union all对应到DataSet中即为unionAll算子,底层调用union算子

在之前的文章《重要|Spark分区并行度决定机制》中已经对Spark RDD中的union算子对union产生的新的RDD的分区数是如何受被union的多个RDD的影响的,做过详细介绍,这里直接给出结论:

同样的这种机制也可以套用到Spark SQL中的DataSet上,那么就很好解释了tmp的分区数为什么等于t1和t2的分区数的和。

最后,Spark中一个task处理一个分区从而也会影响最终生成的文件数。

当然上述只是以Spark SQL中的一个场景阐述了小文件产生过多的原因之一(分区数过多)。在数仓建设中,产生小文件过多的原因有很多种,比如:

1. 流式处理中,每个批次的处理执行保存操作也会产生很多小文件

2. 为了解决数据更新问题,同一份数据保存了不同的几个状态,也容易导致文件数过多

那么如何解决这种小文件的问题呢?

1. 通过repartition或coalesce算子控制最后的DataSet的分区数

注意repartition和coalesce的区别,具体可以参考文章《重要|Spark分区并行度决定机制》

2. 将Hive风格的Coalesce and Repartition Hint 应用到Spark SQL需要注意这种方式对Spark的版本有要求,建议在Spark2.4.X及以上版本使用,示例:

INSERT ... SELECT /*+ COALESCE(numPartitions) */ ...
INSERT ... SELECT /*+ REPARTITION(numPartitions) */ ...

3. 小文件定期合并

可以定时通过异步的方式针对Hive分区表的每一个分区中的小文件进行合并操作

上述只是给出3种常见的解决办法,并且要结合实际用到的技术和场景去具体处理,比如对于HDFS小文件过多,也可以通过生成HAR 文件或者Sequence File来解决。

推荐文章:

Spark SQL | 目前Spark社区最活跃的组件之一

Spark存储Parquet数据到Hive,对map、array、struct字段类型的处理Spark SQL解析查询parquet格式Hive表获取分区字段和查询条件

关于HDFS应知应会的几个问题Spark RDD详解

Spark和Spring整合处理离线数据Spark流式状态管理


关注微信公众号:大数据学习与分享,获取更对技术干货

Spark SQL 小文件问题处理的更多相关文章

  1. hadoop spark合并小文件

      一.输入文件类型设置为 CombineTextInputFormat hadoop job.setInputFormatClass(CombineTextInputFormat.class) sp ...

  2. Spark SQL如何选择join策略

    前言 众所周知,Catalyst Optimizer是Spark SQL的核心,它主要负责将SQL语句转换成最终的物理执行计划,在一定程度上决定了SQL执行的性能. Catalyst在由Optimiz ...

  3. spark SQL (四)数据源 Data Source----Parquet 文件的读取与加载

    spark SQL Parquet 文件的读取与加载 是由许多其他数据处理系统支持的柱状格式.Spark SQL支持阅读和编写自动保留原始数据模式的Parquet文件.在编写Parquet文件时,出于 ...

  4. Spark SQL之External DataSource外部数据源(二)源代码分析

    上周Spark1.2刚公布,周末在家没事,把这个特性给了解一下,顺便分析下源代码,看一看这个特性是怎样设计及实现的. /** Spark SQL源代码分析系列文章*/ (Ps: External Da ...

  5. spark sql/hive小文件问题

    针对hive on mapreduce 1:我们可以通过一些配置项来使Hive在执行结束后对结果文件进行合并: 参数详细内容可参考官网:https://cwiki.apache.org/conflue ...

  6. Spark:spark df插入hive表后小文件数量多,如何合并?

    在做spark开发过程中,时不时的就有可能遇到租户的hive库目录下的文件个数超出了最大限制问题. 一般情况下通过hive的参数设置: val conf = new SparkConf().setAp ...

  7. 针对小文件的spark wholeTextFiles()

    场景:推送过来的数据文件数量很多,并且每个只有10-30M的大小 spark读取hdfs一般都是用textfile(),但是对于这种情况,如果使用textFile默认产生的分区数将与文件数目一致,产生 ...

  8. 通过Spark SQL关联查询两个HDFS上的文件操作

    order_created.txt   订单编号  订单创建时间 -- :: -- :: -- :: -- :: -- :: order_picked.txt   订单编号  订单提取时间 -- :: ...

  9. Spark使用CombineTextInputFormat缓解小文件过多导致Task数目过多的问题

    目前平台使用Kafka + Flume的方式进行实时数据接入,Kafka中的数据由业务方负责写入,这些数据一部分由Spark Streaming进行流式计算:另一部分数据则经由Flume存储至HDFS ...

随机推荐

  1. PHP核心配置基础解读

    PHP核心配置 原为引用 <代码审计企业级web代码安全架构>尹毅  第一章内容 Register_globals(全局变量开关) 会直接把用户GET.POST等方式提交上来的参数注册成为 ...

  2. 转换文件格式遭遇 FileNotFoundError:[WinError 2]系统找不到指定的文件

    重启试试

  3. 「CSP-S 2019」划分

    description loj 3212 solution 首先容易想到\(n^3\)DP,即令\(f_{i,j}\)表示前\(i\)个数的划分,其中最后一段是从\(j\)开始时的答案 于是有 \[f ...

  4. python计算时间差

    前言 之前写代码都是看打印的初始和结束时间然后自己算间隔时间,感觉总是不方便,这不符合python的优雅简洁,于是去寻找简便之道. 方法 time模块计算时间差 import time s_time ...

  5. 如何解决vue2.0 打包之后 打开index.html出现空白页

    如何解决vue2.0 打包之后 打开index.html出现空白页 1.打包之前修改三个文件       1.1.第一步,找到build文件,在webpack.prod.conf.js 第25行左右 ...

  6. redis数据量大时bgsave线程阻塞redis原因

    rt 转载 Latency generated by fork In order to generate the RDB file in background, or to rewrite the A ...

  7. Linux下使用Docker部署nacos-server(单机模式),丧心病狂的我在半夜给UCloud提交了一份工单

    1. 拉取nacos-server镜像 进入 Docker Hub 查看nacos-server最新版本为 nacos-server:1.4.0 配置阿里云镜像加速 sudo mkdir -p /et ...

  8. 避开一部分安装问题的Burpsuite的安装教程

    Burpsuite的安装教程 前言: 既然网上有很多的Burpsuite的安装教程为什么笔者还要在写这篇文章呢? 笔者发现网上的许多安装教程都存在着许许多多的问题,有时候对于一些安装细节描述不是很深, ...

  9. linux查看内存及磁盘使用情况

    1.查看当前目录 命令:   df -h       (统一每个目录下磁盘的整体情况) 2.查看指定目录 在命令后直接放目录名,比如查看"usr"目录使用情况: 命令:   df ...

  10. 码农飞升记-Java是什么?

    1.Java概述 Java 原名 Oak 是 Sun Microsystems 公司的 James Gosling 及其团队于 1995 年 5 月推出的 Java 程序设计语言 和 Java 平台 ...