解决spark streaming 聚合算子(shuffle)并行度200及缓存buffer不断增大的问题

  • 问题现象:

spark流式计算中做聚合需要使用 group by算子,我在使用过程中遇到一些问题,通过stage图可以看出2个问题:

1. 聚合算子每个批次shuffle write的数据量直线上升,这样会导致算子得效率逐渐降低,甚至会导致oom

2.聚合算子(shuffle)的并行度是200,即使设置spark.sql.shuffle.partitions=10也不生效。200并行度会增加调度压力,并且会把并行度传递到下游(如果不做repartition)。我的业务中会把数据写入iceberg中,发现每个批次都会产生大量的小文件,这对hive metastore产生了巨大压力!

  •  问题定位:

1. 通过现象可以看出,即使聚合算子的如如只有1M,它的输出也有63M,并且不断递增。因此可以推断是算子中有大量的状态数据,导致每个批次数据的计算既有新批次数据,也有大量的状态数据。通过spark structured streaming官方文档可以发现原因,当Output mode使用Complete的时候,聚合函数不会丢弃过去的聚合状态,因此会保留所有数据到输出。

 2. 我们可以看到聚合算子每次的shuffle read的数据量都有几十M,可以推断是spark的自适应框架自动将该算子的并行度设成了200。

  • 问题解决:

1. 很显然,只需要将output mode改成append或update即可,使用哪一个可以根据自身业务要求选择,我使用了append模式。在这期间可能会遇到另一个奇怪的问题,虽然指定了watermark,但是会出现报错:

org.apache.spark.sql.AnalysisException: Append output mode not supported when there are streaming aggregations on streaming DataFrames/DataSets without watermark;;

Dataset<Row> targetDf = df
	.withWatermark("event_ts", "1 minute")
	.groupBy(functions.window(df.col("event_ts"), "1 minutes", "1 minutes", "0 second"), df.col("id"))

 这里是因为withWatermark会产生一个新的流Dataset<Row>,并将watermark加入到这个数据流中,如果聚合算子使用df.col(),则对应的列中是没有watermark的,因此会由上面的报错。改证候的代码如下:

Dataset<Row> targetDf = df
	.withWatermark("event_ts", "1 minute")
	.groupBy(functions.window(functions.col("event_ts"), "1 minutes", "1 minutes", "0 second"), functions.col("id"))

2. 使用Complete后,shuffle read的数据量降低到1M,spark.sql.shuffle.partitions=10开始生效

  • 结果展示

改正后重新运行,可以看到无论是聚合算子的并行度,还是shuffle write的数据量都已经和预期一致!


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值