Spark序列化专题一 ---- 数据序列化反序列化位置验证

 

版权声明:本文为博主原创文章,未经博主允许不得转载!!

欢迎访问:https://blog.csdn.net/qq_21439395/article/details/81266889

交流QQ: 824203453

 

1.java中的序列化的回顾

val stream = new ObjectOutputStream(new FileOutputStream("f:/person.txt"))
val p1 = new Person("x1", 28)
stream.writeObject(p1)
stream.writeInt(10)
stream.flush()
val out = new ObjectInputStream(new FileInputStream("f:/person.txt"))
val obj = out.readObject()
val p2 = obj.asInstanceOf[Person]
println(p1 == p2)
println(out.readInt())

 

2.Spark序列化:

2.1 序列化方案:

Spark中提供了2种序列化方案:

Spark中默认使用的是java的序列化机制,JavaSerializer

如果需要使用Kryo序列化,需要进行注册。

 

2.2 Kryo 序列化


// 设置kryo序列化

  conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")

conf.registerKryoClasses(Array(classOf[MyClass1]))

kryo序列化特点:

速度快,占用资源少。

需要注册

 

3.Spark序列化位置验证

3.1 在函数中调用

如果直接在函数中调用类的实例对象或者 object,

该类或者对象不需要进行序列化。

原因:数据并没有driver和executor之间传输,类是在executor中实例化的

task在处理每一条数据的时候,

如果使用的是类,处理每一条数据时都需要对类进行实例化。(同一个task中的每一条数据,对应着一个实例

// 类的定义

class MyTask {

  val mp = Map("hadoop" -> 10, "spark" -> 1000)

}


val f1 = sc.textFile(args(0))

  val result = f1.map(t => {

  // 创建一个对象 该对象在哪里创建? executor driver task?

  val mt = new MyTask()

  // 打印当前的对象

  println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")

  // 通过该对象的集合获取值

  mt.mp.getOrElse(t, 0)

  // 获取当前的主机名

  val hostName = InetAddress.getLocalHost.getHostName

  // 获取当前的线程名

  val threadName = Thread.currentThread().getName

  (hostName, threadName ,mt.mp.getOrElse(t,0),mt.toString)
)})
result.saveAsTextFile(args(1))
sc.stop()

 

如果使用的是object,object是单例的,所以在一个进程中,只需要有一个实例就可以了。

object是在executor中,一个executor进程中实例化了一次。

val f1 = sc.textFile(args(0))
val result = f1.map(t => {
  // 获取当前的主机名
  val hostName = InetAddress.getLocalHost.getHostName
  // 获取当前的线程名
  val threadName = Thread.currentThread().getName
  // 直接在函数中引用object
  (hostName, threadName, MyTaskObj.mp.getOrElse(t, 0), MyTaskObj.toString)
})
result.saveAsTextFile(args(1))
sc.stop()





// object

object MyTaskObj extends Serializable{
  val mp = Map("hadoop" -> 10, "spark" -> 1000)
  val hostName = InetAddress.getLocalHost.getHostName
  // 获取当前的线程名
  val threadName = Thread.currentThread().getName
  println(s"###########-----${hostName},${threadName}---###########")
}

3.2 闭包引用

当我们在函数内部使用了一个外部的引用,该引用对象对应的类或者object必须要进行序列化。 extends Serializable 

 

在driver端的对象和executor中的对象,不是同一个,每次在一个task中,进行反序列化,获取到了新的对象。

如果使用的是类:

类是在driver端实例化了,然后序列化发送给executor,在executor中,每一个task处理的所有数据,对应着一个新的实例对象。(同一个task中的所有数据,共用一个实例

 

val f1 = sc.textFile(args(0))

// 在driver端创建一个类的实例对象 该类必须实现序列化
val mt = new MyTask()
// 打印当前的实例对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
val result = f1.map(t => {
  // 获取当前的主机名
  val hostName = InetAddress.getLocalHost.getHostName
  // 获取当前的线程名
  val threadName = Thread.currentThread().getName
  (hostName, threadName, mt.mp.getOrElse(t, 0), mt.toString)
})
result.saveAsTextFile(args(1))
sc.stop()





// 序列化

class MyTask extends Serializable{
  val mp = Map("hadoop" -> 10, "spark" -> 1000)
}

 

使用的是object:

object 也是在driver端实例化的,然后序列化发送给executor,但是在executor中,每一个executor中的所有task共用一个实例对象,不同的executor之间,对象是不相同的。

(同一个executor中的数据,共用一个实例)

val f1 = sc.textFile(args(0))
// 在driver端定义一个对象
val mt = MyTaskObj
// 打印当前的实例对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
val result = f1.map(t => {
  // 获取当前的主机名
  val hostName = InetAddress.getLocalHost.getHostName
  // 获取当前的线程名
  val threadName = Thread.currentThread().getName
  (hostName, threadName, mt.mp.getOrElse(t, 0), mt.toString)
})
result.saveAsTextFile(args(1))
sc.stop()



// 使用对象

object MyTaskObj extends Serializable{
  val mp = Map("hadoop" -> 10, "spark" -> 1000)
}

 

当在函数内部使用了一个外部的引用,就生成一个闭包。

闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。比如说,在函数中使用定义在其外的局部变量,这就形成了一个闭包。

var sum = 0

List(1,2,3,4,5).foreach(x => sum += x)

在scala中,闭包捕获了变量本身,而不是变量的值。

闭包的本质:代码块+上下文

3.3 广播变量

当把一个类的实例进行广播时,该类必须要实现序列化

同一个executor中的所有task处理不同数据时,共享一份数据。

val f1 = sc.textFile(args(0))

// 在driver端创建一个类的实例对象
val mt = new MyTask()
val bc = sc.broadcast(mt)
// 打印当前的实例对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
val result = f1.map(t => {

val newTask = bc.value
  // 获取当前的主机名
  val hostName = InetAddress.getLocalHost.getHostName
  // 获取当前的线程名
  val threadName = Thread.currentThread().getName
  (hostName, threadName, newTask.mp.getOrElse(t, 0), newTask.toString)
})
result.saveAsTextFile(args(1))
sc.stop()

 

版权声明:本文为博主原创文章,未经博主允许不得转载!!

欢迎访问:https://blog.csdn.net/qq_21439395/article/details/81266889

交流QQ: 824203453

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章