Spark job
我們都知道,spark的執(zhí)行是lazy的,也就是spark的函數(shù)分為兩類: Transform和action. 只有在使用action函數(shù)時(shí),才會(huì)觸發(fā)一個(gè)spark job.
串行的Spark job
在一個(gè)Spark Streaming的程序中,一個(gè)比較常見的case是,外部有一個(gè)n次循環(huán),循環(huán)的內(nèi)容里有個(gè)action函數(shù),這樣相當(dāng)于說(shuō)一共會(huì)有n個(gè)Spark job。基于Spark的調(diào)度策略,只有當(dāng)上一個(gè)job執(zhí)行完成后,下一個(gè)job才會(huì)執(zhí)行,這樣相當(dāng)于n個(gè)作業(yè)順序執(zhí)行。scala代碼如下:
// events是一個(gè)長(zhǎng)度為n的數(shù)組,對(duì)每個(gè)元素進(jìn)行了buildEvent操作,其中buildEvent函數(shù)中有個(gè)action操作。
events.map(event => event.buildEvent())
如果這n個(gè)job之間沒有依賴關(guān)系的話,串行的執(zhí)行會(huì)使資源利用率較低。因此,很自然就會(huì)想到能否并發(fā)的提交執(zhí)行各個(gè)job。
并行提交Spark job
并行提交的思路很簡(jiǎn)單,使用threadpool, 將循環(huán)內(nèi)的每個(gè)action放到不同的線程中,這樣由各線程處理action邏輯。上述串行的代碼邏輯就相應(yīng)的改為如下:
val threadPool: ExecutorService = Executors.newCachedThreadPool
val eventService = new ExecutorCompletionService[String](threadPool)
events.map(event => eventService.submit(new buildEvent()))
//等待每個(gè)作業(yè)返回結(jié)果
for (index <- 0 until events.size) {
val result = eventService.take.get()
}