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,啟動之后集群如圖顯示:
需要大數據學習資料和交流學習的同學可以加大數據學習群:724693112 有免費資料分享和一群學習大數據的小伙伴一起努力
進入spark-sql,從hive中掃描一張表,執行情況如下:
奇怪的是,所有讀取HDFS文件的Task Locality Level全部是ANY,也就是說,沒有一個使用NODE_LOCAL本地化任務,這樣導致集群的網絡消耗非常大(因為所有的數據都要經網絡拷貝一遍),如圖,后面那個峰值是執行任務的網絡情況:
直接說原因和解決辦法吧。
請注意最上面集群情況的圖中,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 ,這樣啟動之后,Spark WEBUI中Worker Id和Address中都以hostname來顯示了,如圖:
再次進入spark-sql,執行同樣的任務,所有的Task Locality Level都是NODE_LOCAL,沒有網絡傳輸,速度比之前快了好幾倍。
這才是期望的結果,至于導致salves文件中配置的明明是hostname,為何Spark集群中解析成IP地址的原因,后續再查吧。