Spark 开发总结

前言

大数据开发过程中把自己积累的关于Spark的使用方法记录下来,便于不断的回顾和总结

spark UI

Spark API Function

Window.partitionBy

window 窗口函数在一组行(frame)上面执行计算,通过aggregate/window 函数给每行返回一个新的值,本质上按某个属性划分partition,在对每个partition进行聚合,使用的场景是计算每个partition中某个属性的平均值,总和,或者转化成集合;

overCategory = Window.partitionBy("depName").orderBy(desc("salary"))
df = empsalary.withColumn("salaries",collect_list("salary").over(overCategory))
.withColumn("average_salary",(avg("salary").over(overCategory)).cast("int"))
.withColumn("total_salary",sum("salary").over(overCategory))
.select("depName","empNo","name","salary","salaries","average_salary","total_salary")
df.show(20,False)

如数据集empsalary
在这里插入图片描述
在这里插入图片描述
输出结果:
在这里插入图片描述
注意:
spark函数中,只有Aggregate Functions 能够和 Window Functions搭配使用,其他类别的函数不能应用于Spark Window中,例如下面的一个例子,使用了函数array_contains,(collection functions的一种),spark会报错
在这里插入图片描述

overCategory = Window.partitionBy("depName")

df = empsalary.withColumn(
"average_salary_in_dep",array_contains(col("hobby"),"game").over(overCategory)).withColumn("total_salary_in_dep",sum("salary").over(overCategory))
df.show()
## pyspark.sql.functions.array_contains(col,value)
## Collection 函数,return True if the array contains the given value.The collection elements and value must be of the same type
df = spark.createDataFrame([(['a', 'b', 'c'],),([],)],['data'])
df.select(array_contains(df.data,'a')).collect()
[Row(array_contains(data,a) = True,Row(array_contains(data,a) = False)]

参考:https://knockdata.github.io/spark-window-function-pyspark/

Spark udf

// 对于array<struct>类型的column 执行 udf(array<struct> => array<struct>) 返回结果仍是array<struct>的情况下,需要声明schema类型
val tmpschema = tmpadEffect.schema("crowd_dimen_group").dataType
val tmpcrowdDimensFilter = udf((crowd_dimen_groups: Seq[Row]) => {
      crowd_dimen_groups.filter(x => x.getAs[String]("frontend_dimension_id") == "306931917")
    }, tmpschema)

Spark 中禁止使用return

太头疼了,只能用if else , 代码不美观,后续有时间找找比较好的编码方式

Spark NullPointException

Spark开发中经常因为NullPointException问题导致整个任务失败不断重试,浪费大量时间;
最有效的解决方法是:
1、先尽量分步骤保存各阶段运行结果;
2、在上一步结果的基础上,不断来定位产生NullPointException的原因;
3、不要心怀侥幸,觉得随便加个判空就能解决问题,避免因判空不生效导致不断重试;
4、根据NullPoint的变量检查对应的DataFrame是否包含空值,然后添加过滤条件;

Spark Shuffle FetchFailedException

shuffle分为shuffle write和shuffle read两部分。
shuffle write的分区数由上一阶段的RDD分区数控制,shuffle read的分区数则是由Spark提供的一些参数控制。

shuffle write可以简单理解为类似于saveAsLocalDiskFile的操作,将计算的中间结果按某种规则临时放到各个executor所在的本地磁盘上。

shuffle read的时候数据的分区数则是由spark提供的一些参数控制。可以想到的是,如果这个参数值设置的很小,同时shuffle read的量很大,那么将会导致一个task需要处理的数据非常大。结果导致JVM crash,从而导致取shuffle数据失败,同时executor也丢失了,看到Failed to connect to host的错误,也就是executor lost的意思。有时候即使不会导致JVM crash也会造成长时间的gc。

解决办法
知道原因后问题就好解决了,主要从shuffle的数据量和处理shuffle数据的分区数两个角度入手。

减少shuffle数据

思考是否可以使用map side join或是broadcast join来规避shuffle的产生。

将不必要的数据在shuffle前进行过滤,比如原始数据有20个字段,只要选取需要的字段进行处理即可,将会减少一定的shuffle数据。

SparkSQL和DataFrame的join,group by等操作

通过spark.sql.shuffle.partitions控制分区数,默认为200,根据shuffle的量以及计算的复杂度提高这个值。

Rdd的join,groupBy,reduceByKey等操作

通过spark.default.parallelism控制shuffle read与reduce处理的分区数,默认为运行任务的core的总数(mesos细粒度模式为8个,local模式为本地的core总数),官方建议为设置成运行任务的core的2-3倍。

提高executor的内存

通过spark.executor.memory适当提高executor的memory值。

是否存在数据倾斜的问题

空值是否已经过滤?异常数据(某个key数据特别大)是否可以单独处理?考虑改变数据分区规则。

spark 数据倾斜

  • 提高shuffle并行度:增大shuffle read task参数值,让每个task处理比原来更少的数据;适应所有场景,简单有效可作为首选方案,缺点是缓解的效果有限;对于group,join shuffle类语句,可以通过设置spark.sql.shuffle.partitions来调整并发;
  • 两阶段聚合:适用于groupbykey分组聚合,reducebykey等shuffle算子,思路:首先通过map给每个key打上n以内的随机数前缀进行局部聚合,并进行reducebykey的局部聚合,然后再次map将key的前缀随机数去掉再次进行全局聚合;可以让整个过程中原本一个task处理的数据分摊到多个task做局部聚合,规避单task数据过量,缺点是仅适用于聚合类的Shuffle操作,无法适用于join类的shuffle操作
  • 广播broadcast: 对RDD或Spark SQL使用join类操作或语句,且join操作的RDD比较小(百兆或1,2G);使用broadcast和map类算子实现join的功能替代原本的join,彻底规避shuffle。对较小RDD直接collect到内存,并创建broadcast变量;并对另外一个RDD执行map类算子,在该算子的函数中,从broadcast变量(collect出的较小RDD)与当前RDD中的每条数据依次比对key,相同的key执行你需要方式的join;
  • 采样倾斜key拆分join:适用于两个表都很大,但大key占比很小;对join导致的倾斜是因为某几个key,可将原本RDD中的倾斜key从原RDD拆分出来得到新RDD,并以加随机前缀的方式打散n份做join,将倾斜key对应的大量数据分摊到更多task上来规避倾斜;不适用于大量倾斜key;
  • 随机前缀加扩容RDD进行join:适用场景:RDD中有大量key导致倾斜
    • 1.首先查看RDD/Hive表中数据分布并找到造成倾斜的RDD/表;
    • 2.对倾斜RDD中的每条数据打上n以内的随机数前缀;
    • 3.对另外一个正常RDD的每条数据扩容n倍,扩容出的每条数据依次打上0到n的前缀;
    • 4.对处理后的两个RDD进行join。与采样倾斜key方案不同在于这里对不倾斜RDD中所有数据进行扩大n倍,而不是找出倾斜key进行扩容, 效果非常显著;缺点是扩容需要大内存
  • 实际中需要结合业务全盘考虑,可先提升Shuffle的并行度,最后针对数据分布选择后面方案中的一种或多种灵活应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值