SparkStreaming将结果输出到单个文件以及小文件的合并

SparkStreaming将结果输出到单个文件以及小文件的合并

sparkStreaming消费kafka数据…

每个duration批次时间数据量不一定多少,
若数据量太少,
首先每个批次处理数据后会有多个分区的小文件,
解决办法1. 是在结果落地前重分区,每个批次只生成一个文件,

那么要是这一个文件数据量也很小,落地到hive还是会影响查询效率

那么解决办法2. 就用在hive定时执行一个insert overwrite table a select * from a;语句,这个时候会覆盖表的数据达到合并小文件的目的

关于insert overwrite table a select * from a;应该会覆盖原先的文件,不过我还是测试了一下。 在我摘的两篇文章最下面贴截图。

以下摘自优快云

地址是:https://blog.youkuaiyun.com/xianpanjia4616/article/details/82888608

sparksql写入hive后小文件太多,影响查询性能的问题
首先我们要知道hive里面文件的数量=executor-coresnum-executorsjob数,所以如果我们batchDuration的设置的比较小的话,每天在一个分区里面就会生成很多的小文件,我们在hive里面查询的时候就会非常的影响性能,下面介绍两种方法优化小文件:

(1),第一种,可以在创建的DataFrame的时候,cache一下,然后对DataFrame进行重新分区,可以把分区设置为1,可以用reparation,当然也可以用coalesce,这两个的区别,可以看我的另外一篇博客,这个时候就会一个job产生一个文件.但是这么做就降低了写入的性能,所以数据量不是特别大的时候,还是可以用的,但是如果数据量很大,就需谨慎使用,

(2),第二种方法是利用sql定时执行一下,insert overwrite table a select * from a;这个时候会覆盖表的数据达到合并小文件的目的,具体的sql下面会有.

下面看一下具体的代码吧:

 val df = spark.createDataFrame(rowRDD, schema).cache()
          df.coalesce(1).createOrReplaceTempView("tempTable")
          val sq = "insert into combine_data partition(day_time='" + day_time + "') select * from tempTable"
          sql(sq)
          println("插入hive成功了")
          df.unpersist(true)
insert overwrite table combine_data partition (day_time='2018-08-01') select data,enter_time from combine_data where day_time = '2018-08-01'; 

以下是摘自简书

地址:https://www.jianshu.com/p/7e2b20ccc78b

原始的结果
今天终于完成了SparkStreaming的阶段性工作,要将结果数据放入到hdfs上保存,使用的是RDD自己原有的函数saveAsTextFiles(“Path”)
在这里插入图片描述
使用函数
结果如下
在这里插入图片描述
结果
可以看出,有瑕疵。我是想将我的数据保存在一个文件中,所以有瑕疵。文件太多,文件夹太多。这样的结果对于后面对数据的再次使用,坏处我就不必多说了吧。

可以看出,多文件夹的原因是因为我是使用的SparkStreaming,所以是每个时间段(Duration)执行一次写入的操作,所以会出现多文件夹,并且名字以时间命名。再看文件夹下的多个文件,这是由我的RDD的分区决定的,而RDD的分区是由我指定数量的线程来决定的,因为我是在本地跑的val sparkConf =new SparkConf().setMaster(Constant.SPARK_MASTER_LOCAL),我这里指定的是4,所以是4个文件。对RDD感兴趣的可以去看一下RDD的分区,讲的很好理解,这里就不再赘述。对spark中RDD通俗易懂的介绍

解决方法
思路描述:首先解决多文件的问题,因为文件数量是由分区决定的,那我们就将他重分区,分区数量为1,然后再向hdfs中写入临时目录,写入后我们再将这个文件追加到最终的文件中,然后再把这个临时文件删除。闲话少说,上干货。
在这里插入图片描述
解决方法
copyMerge(src.getFileSystem(conf), src, dst)方法如下。
在这里插入图片描述
copyMerge(src.getFileSystem(conf), src, dst)

作者:飞叔Brother
链接:https://www.jianshu.com/p/7e2b20ccc78b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

测试overwrite覆盖原文件

insert overwrite table a select * from a;

创建表 指定数据目录

create table testover(
a int
)
location '/out/18';

目下有两个文件
在这里插入图片描述
查询数据在这里插入图片描述

覆盖以合并小文件

insert overwrite table testover
select * from testover;

在这里插入图片描述
查看目录下文件

果然由两个变为了一个

在这里插入图片描述
查询一下 没有错
在这里插入图片描述

### 配置和优化 Spark Streaming 并行度 在 Spark Streaming 中,并行度主要由批处理间隔 (Batch Interval) 和块间隔 (Block Interval) 决定。默认情况下,`blockInterval` 设置为 200 毫秒,而 `batchInterval` 取决于应用程序的具体配置[^5]。 #### 批处理间隔与并行度的关系 当 `batchInterval` 设为 5 秒时,默认分区数量等于 `batchInterval / blockInterval` 即 25 个分区。然而,实际数据量可能不足以填充这些分区,导致某些批次仅有少量甚至单个分区被创建。这种现象会影响作业的整体性能以及资源利用率。 为了更好地控制并行度,可以考虑以下几个方面: - **调整 Block Interval**: 减小 `spark.streaming.blockInterval` 参数值可增加每批次内的 Partition 数目;反之则减少。不过需要注意的是,过短的时间可能导致过多的小任务生成,反而降低效率。 - **设定最小输入分片数**: 使用 `minPartitions` 参数指定读取源时所需的最少分区数目,确保即使数据稀疏也能维持一定水平的并发执行能力。 - **自定义接收器逻辑**: 如果应用依赖于 Receiver 接收外部流式数据,则可以通过实现自定义 Receiver 来更灵活地管理缓冲区大小及写前日志功能(通过开启 `spark.streaming.receiver.writeAheadLog.enable=true`),从而间接影响最终形成的 RDD 分区结构[^2]。 针对提到的数据写入 Iceberg 表过程中产生的大量小文件问题,除了上述措施外还可以采取以下策略来缓解 Hive Metastore 压力: - **合并小文件**: 定期触发 Compaction 操作以合并多个小文件成较大规模的单一文件; - **调节 Shuffle 并行度**: 对于涉及 shuffle 的转换操作,适当增大 `spark.sql.files.maxPartitionBytes` 或者显式调用 repartition() 方法重新划分数据集,避免因过高并行度造成过多输出片段[^4]。 ```scala // 示例代码:显示设置 partition 数量 val df = spark.read.format("iceberg").load("table_path") df.repartition(num_partitions).write.mode("append").format("iceberg").save("output_table_path") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值