为什么你的Spark应用执行的慢并且失败 - 数据倾斜和垃圾回收

本文探讨了Spark程序中常见的性能问题,如数据倾斜和内存管理。数据倾斜发生在数据分布不均匀导致某些分区过大,影响处理效率。解决方法包括广播小表、处理null值和加盐技术。内存管理问题主要与Java垃圾回收相关,可通过优化数据结构、使用序列化和调整内存配置来改善。文章提供了识别和解决这些问题的实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

像很多Spark性能上的挑战一样,这些症状也会出现程序处理数据增加而增加.

什么是数据倾斜

在理想的Spark程序,当运行join操作, join key将要平均分布到不同分区, 非常漂亮的组织不同分区来处理. 真实的业务数据是非常罕见这么整齐的组织. 通常结束的数据不是理想组织那样,Spark集群性能被数据倾斜降级.

数据倾斜不是Spark本身问题,而是数据问题.引起数据倾斜是不均匀分布底层数据.在所有数据分布或是自然查询不均匀的分区有时是不可避免的.

对于join或是聚合操作,spark需要使相同key在一个分区.相同key的记录总是在同一个分区.类似的,其它key会分布到其它分区.如果其中一个分区变得非常大,这样会引起数据倾斜.如果没有特殊处理,会的查询引擎是个问题.

处理数据倾斜

数据倾斜在数据需要移改组非常容易出现,像join和聚合.改组操作被spark完成通过把关联数据放到同一个分区(相关的数据移动的相同key). 因为这样,spark需要在cluster上移动数据.所以数据改组是最消耗性能的操作.

通常会引起数据倾斜的症状:

  • 运行在指定stage和task
  • cpu利用率低
  • 内存溢出错误
    有几种技巧我位可以利用处理spark当中的数据倾斜.

确认和解决数据倾斜

Spark用户通常注意到大部分task都在合理的时间内完成,仅仅有一个任务一起在执行. 十分可能, 这表明是数据倾斜. 这也导致集群利用率低. 在去上运行spark这是个突出的问题. 集群上的资源浪费和昂贵的.

如果数据倾斜在数据源层(如果hive分区为_month key,并且表有非常多条记录在这个分区中),这会引起倾斜处理在读表的stage中. 在这种情况下表重建,用不同的分区key会有帮助. 然而一些情况是行不通的,在企业中表是被其它数据管道在用.

在这样例子中,有几种方式我位可以避免数据倾斜.

广播数据

如果在做join操作时有数据倾斜,一种方式是增加spark.sql.autoBroadcastJoinThreshold值大小,这样小表的数据会被广播. 这要确保driver和执行节点上的内存够用.

数据处理

如果有很多null值在join或是group-by key中,它们将要导致数据倾斜操作. 试着用随机id预处理null值, 并且在程序中处理.

加盐

在SQL join中,join key被改变导致平均重新分配这些数据,这样处理分区不会花非常多的时间. 这个技术被称为加盐.用一个例子可以更好了解.在join或是group-by,spark map key到一个分区是通过在key上的hash code值,再把数据分组到不同分区.

假设有两张表
Data schema
让我们考虑一个例子, 有一个特别的值数据倾斜非常严重,例如. key = 1, 并且想要join两张表,做一个group来得到数量.如:
在这里插入图片描述
在数组分组到stage是通过join操作之后,用这个key所有行都被分到相同的分区中.看上图,所有带有key 1的数据在分区1.类似的,所有为key 2的在分区2. 十分清楚处理分区1的时间大小分区2的时间,并且分区包含更多数据.看下上图 Spark UI关于分组数据stagef运行的时间.
在这里插入图片描述
正如你看到的,一个任务比其它任务运行更长时间.用更多数据会更明显.并且这也会引起程序的不稳定性,在一个分区的内存使用过大.

我们可以加入一些其它东西来使我们的数据集分区的更平均吗?大部分用户使用加盐方式来处理数据倾斜. 加盐技术是增加一个随机数到表中join的key. 在另外的表,需要复制行来匹配随机keys. 这个想法是如果join条件满足key1=key1,它也应该满足key_1=key1_.这个值可以帮助数据集更分区均匀.

例如看我的例子是怎样做的.看20行.使用当做一个随机函数, 炸开数据集. 这不同与除法数,是我想要处理数据倾斜的数.这是一个基础的例子,可以提高包含仅是几个key数据倾斜的.
Image title
现在再看Spark UI. 处理时间更平均了
Image title
注意小数据的性能差异不会有很大不同.有时压缩改组在整个运行中也扮演着角色.对于数据倾斜,数组改组可以被大力压缩由于重复的数据.因此,磁盘IO/网络IO占用会减少.我们需要运行我的程序没有盐和有盐,来最终达到合适自己的结果.

垃圾回收

Spark运行在JVM上.因为Spark可以存放大量数据在内存中, 非常依赖Java内存管理和GC.因此,GC是一个非常大的问题,可以影响Spark应用.

在Spark中执行GC常见状态:

  • 应用运行速度
  • 执行心跳超时
  • GC过载限制导致错误

Spark以内存为中中和处理大量数据的应用使它比其它java应用更容易出问题.多亏非常容易诊断出Spark 遭受GC问题. Spark UI标记执行节点为红钯诮是花了太多时间在GC上.

Spark执行节点花费大量CPU执行垃圾回收. 通过查看Spark UI Executors 页面.spark红色表示花费超过10%的时间是垃圾回收,可以看下图
Apache Spark UI

定位垃圾回收问题

有一些基本的事情,可以尝试定位垃圾回收问题.

数据结构

如果使用RDD开发程序,数据结构少用对象. 例如,用数组来代替list

序列化数据

如果你处理基本数据类型,考虑使用序列化数据结构像Koloboke或fastutil. 这些结构基本类型优化内存使用.

排序数据非堆存储

Spark执行引擎和Spark存储都存在非堆上. 可以使用转换堆存储使用如下命令:

  • -conf spark.memory.offHeap.enabled = true
  • -conf spark.memory.offHeap.size = Xgb

当使用堆存储时需要小心,不会影响堆内存大小,如你不能减少堆内存大小. 所以定义整体内存限制,分配一个小的堆内存.

内嵌 vs 用户自定义函数(UDFs)

如果你使用Spark SQL, 尽可能使用内建函数,而不是udfs. 大多数UDFs可以在不安全的行工作,并且不需要转换为包裹数据类型.这样避免了创建GC,很好的生成代码.

要吝啬创建对象

记住我们可能操作数亿行数据. 如果创建一个临时的对象,每行只用 100 byte大小, 这样会创建1百亿*100 byte的垃圾.

总结

到目前为至,只是专注内存管理,数据倾斜,垃圾回收做为引起spark应用程序变慢或失败.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值