Spark Core之Spark的序列化

1 RDD 中函数的传递

为什么要进行序列化操作?
因为类的对象是在driver端创建,而对象的方法是在executor上执行,一般情况它们不在同一个节点上,因此需要把driver端的对象序列化到executor端,否则程序会报错。
进行 Spark 进行编程的时候, 初始化工作是在 driver端完成的, 而实际的运行程序是在executor端进行的. 所以就涉及到了进程间的通讯, 数据是需要序列化的。

2 传递函数

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object SerDemo {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[2]").setAppName("SerDemo")
    val sc = new SparkContext(conf)
    val rdd1 = sc.parallelize(Array("hello world","hello atguigu","atguigu","hahah"),2)
      //需求:在RDD中查出来包含query字符串的元素

     //是在driver创建的对象 用来查找包含在hello子字符串的那些字符串组成的rdd
    val searcher = new Searcher("hello")
    val rdd2 = searcher.getMathchedRDD1(rdd1)
    rdd2.collect().foreach(println)
    sc.stop()
  }
}
//query 为需要查找的子字符串
class Searcher(val query:String){
  //判断s中是否包含子字符串query
  def isMatch(s:String):Boolean ={
    s.contains(query)
  }
  //判断出包含query字符串的字符串组成的新的RDD
  def getMathchedRDD1(rdd:RDD[String])= {
    //.filter是在driver调用
    //isMatch方法在executor上执行
    rdd.filter(isMatch)
  }
}

直接运行程序会发现报错: 没有初始化。因为rdd.filter(isMatch) 用到了对象this的方法isMatch, 所以对象this需要序列化,才能把对象从driver发送到executor。
在这里插入图片描述
解决方案

3 序列化的方法

序列化的方法:
(1)java自带的序列化:只需要实现java的一个接口:Serializable
好处:及其简单,不需要做任何额外的工作;java自带,用起来方便。
坏处:序列化后的数据太重
序列化速度慢;序列化之后的size比较大;
(2)hadoop没有使用java的序列化
hadoop自定义序列化机制:…Writeable
注:spark中默认使用java自带的序列化
(3)支持另外一种序列化(第三方序列化方法)
Kyro序列化。

 object SerDemo {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[2]").setAppName("SerDemo")
    val sc = new SparkContext(conf)
    val rdd1 = sc.parallelize(Array("hello world","hello atguigu","atguigu","hahah"),2)
      //需求:在RDD中查出来包含query字符串的元素

     //是在driver创建的对象 用来查找包含在hello子字符串的那些字符串组成的rdd
    val searcher = new Searcher("hello")
    val rdd2 = searcher.getMathchedRDD1(rdd1)
    rdd2.collect().foreach(println)
    sc.stop()
  }
}
//query 为需要查找的子字符串
class Searcher(val query:String) extends Serializable {
  //判断s中是否包含子字符串query
  def isMatch(s:String):Boolean ={
    s.contains(query)
  }
  //判断出包含query字符串的字符串组成的新的RDD
  def getMathchedRDD1(rdd:RDD[String])= {
    //.filter是在driver调用
    //isMatch方法在executor上执行
    rdd.filter(isMatch)
  }
}

注意:若将getMathchedRDD方法改写成如下代码,同样也需要序列化

//若用到了对象的属性,所以类也需要序列化

  def  getMathchedRDD2(rdd:RDD[String]) ={
      rdd.filter(x => x.contains(query))
  }
             

方法的序列化:把方法所在的类实现接口:Serializable,这个类创建的对象就可以序列化。
属性的序列化:
1.把方法所在的类实现接口:Serializable,这个类创建的对象就可以序列化。
2.可以把属性的值存入到一个局部变量,然后传递局部变量(局部变量的类型需要为内置类型,如String、Int)。

 def  getMathchedRDD3(rdd:RDD[String]) ={
  val q = query    //将query赋值给局部变量q,q为内置的String类型,一般内置的变量类型都支持序列化,所以这种情况下不需要再进行序列化
  rdd.filter(x => x.contains(q))
}

注意:有些值无法序列化:与外部存储系统的连接不能序列化。

4 序列化的原理

在这里插入图片描述

5 Kyro序列化操作

Java 的序列化比较重, 能够序列化任何的类.,比较灵活,但是相当的慢, 并且序列化后对象的体积也比较大。Spark 出于性能的考虑, 支持另外一种序列化机制: kryo (2.0开始支持),kryo 比较快和简洁.(速度是Serializable的10倍),想获取更好的性能应该使用 kryo 来序列化。
实现方法:
(1)指定序列化器:

 .set("spark.serializer",classOf[Kryo].getName)

(2)注册需要使用Kyro序列化的类

.registerKryoClasses(Array(classOf[Searcher]))
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值