1. 程式人生 > >Spark的另一個核心的奧祕:任務

Spark的另一個核心的奧祕:任務

任務(Task)是Spark的最小執行單元,Spark任務是通過Task來執行的。Spark的任務體系是最神祕也是最容易學習的核心模組,任務執行機制點透了那麼Spark也就瞭解的更深入了。Task是任務體系的一個抽象類,有兩個子類:ResultTask和ShuffleMapTask,這三個類構成了任務系統的核心。

ResultTask好理解,就是直接執行Task中RDD某個分割槽的資料操作,還記得之前的RDD的結構嗎,裡面有一個compute函式,任務就是執行compute函式。

ShuffleMapTask也是執行Task中RDD某個分割槽的資料操作,所不同的是輸出結果的儲存方式不一樣。ShuffleMapTask會把資料操作的結果儲存到類似BlockManager的全域性儲存中,ShuffleMapTask的結果可供下一個Task作為輸入資料。為什麼分兩種呢?換個說法就很清楚了,ResultTask對應窄依賴的RDD,ShuffleMapTask對應寬依賴的RDD操作(如全連線操作)。ShuffleMapTask需要對資料的讀寫進行特殊的處理,要用BlockManager來輸出資料集的;同樣,ShuffleMapTask的子RDD的讀取資料集也是從BlockManager來的。

ResultTask和ShuffleMapTask的類的程式碼非常簡單,就是重寫runTask方法。

Task通過Task描述物件來反序列化,獲得RDD和分割槽等物件後,建立TaskContextImpl作為任務上下文,然後執行run方法執行任務,讀取RDD中的迭代器資料並處理資料。run方法實際是呼叫子類重寫的runTask方法具體執行的。而runTask方法在ResultTask和ShuffleMapTask中被重寫。

1、 ResultTask

直接結果任務,這類任務執行完也就完了,其資料不需要被下一個任務再次處理。可以任務是終結者任務。

重寫runTask方法。runTask方法的核心程式碼如下:

override def runTask(context: TaskContext): U = { 
 val ser = SparkEnv.get.closureSerializer.newInstance()
 val (rdd, func) = ser.deserialize[(RDD[T], (TaskContext, Iterator[T]) => U)](
 ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader) 
 func(context, rdd.iterator(partition, context))
 }

反序列化得到RDD中定義的資料處理函式func,func符合格式:

(TaskContext, Iterator[T]) => U

然後執行:

func(context, rdd.iterator(partition, context))

這方法的意思就是對rdd分割槽的資料迭代器輪詢,每次取出一條資料執行func操作。ResultTask的重寫部分就是這麼簡單。

2、ShuffleMapTask

ShuffleMap格式的任務,這類任務的執行結果是要被下一個RDD消費的,因此輸出資料需要寫出到Shuffle區域。Shuffle區域會在分割槽資料管理中詳細的介紹。

重寫runTask方法。runTask方法的核心程式碼如下:

override def runTask(context: TaskContext): MapStatus = {
 val ser = SparkEnv.get.closureSerializer.newInstance()
 val rddAndDep = ser.deserialize[(RDD[_], ShuffleDependency[_, _, _])](
 ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader)
 val rdd = rddAndDep._1
 val dep = rddAndDep._2
 dep.shuffleWriterProcessor.write(rdd, dep, partitionId, context, partition)
 }

前半段和Result類似,反序列化得到RDD和分割槽,以及依賴分割槽dep。然後迭代rdd中的資料並寫入到依賴dep的shuffle區域中。

Spark的任務的執行過程這裡就說的很明白了,理解了這點,如果再搞清楚了Spark如何分配任務到不同機器上執行的過程,那麼可以說Spark的精髓也就掌握的清清楚楚了!是