Spark避坑指南----UnsafeRow对象的持久化

举报
hzjturbo 发表于 2020/08/18 21:23:39 2020/08/18
【摘要】 Spark推出Tungsten计划用于提升Spark的性能与资源使用,其中为了消除JVM对象模型和GC代价,提供了UnsafeRow对象类型。它由jvm提供的sun.misc.Unsafe实现,内部存储的是二进制,继承自InternalRow,是SparkSQL中的中间算子的处理和输出数据类型。正是由于UnsafeRow的特殊性,我们发现在某些情况下可能会无法正确序列/持久化该类型,产生数据...

Spark推出Tungsten计划用于提升Spark的性能与资源使用,其中为了消除JVM对象模型和GC代价,提供了UnsafeRow对象类型。它由jvm提供的sun.misc.Unsafe实现,内部存储的是二进制,继承自InternalRow,是SparkSQL中的中间算子的处理和输出数据类型。

正是由于UnsafeRow的特殊性,我们发现在某些情况下可能会无法正确序列/持久化该类型,产生数据读取不一致的情况,下面我们通过几个例子说明:

例子1:默认的RDD.saveAsObjectFile无法正确处理UnsafeRow类型

首先我们准备一些用于测试的数据表:

image.png

我们希望获取到查询`select * from emp, dept where emp.emp_dept_id = dept.dept_id`的结果,该查询对两张表进行了Join操作,后续我们希望将其RDD的数据保存,再重新读取保存的数据。

image.png

为了得到RDD的结果,我们构造一个LogicalRDD的Plan,该Plan会直接Scan RDD的数据。再通过Dataset.ofrows来得到Plan的结果

image.png

得到的正确结果如下:

同样的,我们调用rdd.saveAsObjectFile将RDD[InternalRow]持久化,再利用spark.sparkContext.objectFile读取。

image.png

得到的结果发生了问题,它在总行数不变的情况下,数据被多次复制了,数据读取不一致:

我们查看saveAsObjectFile方法,发现序列化的方式是Java的默认序列化方式,该方法无法正确序列化UnsafeRow对象。

image.png


例子2:RDD的checkpoint方法

Spark提供了checkpoint的方法帮助开发者做中间结果的持久化,开发者可以利用checkpoint将计算查询中复杂的中间结果进行缓存,减少重复计算。

其中,localCheckpoint是将结果存在executor的本地磁盘中,checkpoint是将结果存在hdfs中,checkpoint相比localCheckpoint能获得容错机制,但是性能会相对较差。

在本例中,我们仍采用之前的数据和查询,首先验证一下localCheckpoint():

image.png


得到的结果也是错误的:

由于checkpoint是惰性的,并且在实际的调用过程中会将原来的计算重新执行一遍,所以一般推荐在checkpoint之前进行cache操作,这样到了真正执行时,checkpoint会直接读取cache的数据,而不用触发二次计算:

image.png

结果和localCheckpoint一样,是错误的数据。



通过以上的例子我们发现在对UnsafeRow的类型持久化时,java的序列化方法不能起到正确的作用。UnsafeRow支持的序列化方式为Externalizable和KryoSerializable,我们再对例子2进行验证,需要做两处修改:

1) 在创建sparkSession的时候设置“spark.serializer” 为 “org.apache.spark.serializer.KryoSerializer”

image.png

2)在persist的时候选择带SER的StorageLevel

image.png

得到的结果如下:

和实际的结果是一致的。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。