1. 程式人生 > >Spark讀取HDFS檔案,任務本地化(NODE_LOCAL)

Spark讀取HDFS檔案,任務本地化(NODE_LOCAL)

Spark也有資料本地化的概念(Data Locality),這和MapReduce的Local Task差不多,如果讀取HDFS檔案,Spark則會根據資料的儲存位置,分配離資料儲存最近的Executor去執行任務。

這麼理解沒錯,我搭建的Spark叢集情況是這樣:

15臺DataNode節點的HDFS叢集,我在每個DataNode上都部署了一個Spark Worker,並且,啟動Spark Application的時候,每個Worker都有一個Executor,這樣理論上來說,只要讀取HDFS檔案,Spark都可以使用本地任務來讀取(NODE_LOCAL)。

在$SPARK_HOME/conf/slaves檔案中配置了每個Worker的hostname,之後在Master上,執行$SPARK_HOME/sbin/start-slaves.sh來啟動Workers,啟動之後叢集如圖顯示:

Spark WebUI

進入spark-sql,從hive中掃描一張表,執行情況如下:

Spark WebUI

奇怪的是,所有讀取HDFS檔案的Task Locality Level全部是ANY,也就是說,沒有一個使用NODE_LOCAL本地化任務,這樣導致叢集的網路消耗非常大(因為所有的資料都要經網路拷貝一遍),如圖,後面那個峰值是執行任務的網路情況:

Spark NetWork

直接說原因和解決辦法吧。

請注意最上面叢集情況的圖中,Worker Id和Address中都使用的IP地址作為Worker的標識,而HDFS叢集中一般都以hostname作為slave的標識,這樣,Spark從HDFS中獲取檔案的儲存位置對應的是hostname,而Spark自己的Worker標識為IP地址,兩者不同,因此沒有將任務的Locality Level標記為NODE_LOCAL,而是ANY。奇怪的是,我在Spark的slaves檔案中都配置的是hostname,為何叢集啟動後都採用了IP地址?最大的可能是/etc/hosts檔案的配置。

大資料學習交流群:724693112 歡迎想學習大資料和需要大資料學習資料的同學來一起學習。

解決辦法是:沒有采用slaves檔案+start-slaves.sh的方式啟動,而是每臺Worker單獨啟動,

使用命令:$SPARK_HOME/sbin/start-slave.sh -h <hostname> <masterURI>,這樣啟動之後,Spark WEBUI中Worker Id和Address中都以hostname來顯示了,如圖:

Spark WebUI

再次進入spark-sql,執行同樣的任務,所有的Task Locality Level都是NODE_LOCAL,沒有網路傳輸,速度比之前快了好幾倍。

Spark WebUI

這才是期望的結果,至於導致salves檔案中配置的明明是hostname,為何Spark叢集中解析成IP地址的原因,後續再查吧。