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

 

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