task的locality有五種
1)、PROCESS_LOCAL:進程本地化,代碼和數據在同一個進程中,也就是在同一個executor中。計算數據的task由executor執行,數據在executor的BlockManager中,性能最好。
2)、NODE_LOCAL:節點本地化,代碼和數據在同一個節點中。比如說,數據作為一個HDFS block塊,就在節點上,而task在節點上某個executor中運行,或者是,數據和task在一個節點上的不同executor中,數據需要在進程間進行傳輸。
3)、NO_PREF:對于task來說,數據從哪里獲取都一樣,沒有好壞之分。
4)、RACK_LOCAL:機架本地化,數據和task在一個機架的兩個節點上,數據需要通過網絡在節點之間進行傳輸。
5)、ANY:數據和task可能在集群中的任何地方,而且不在一個機架中,性能最差。
調節本地等待時長背景
Spark在Driver上,對Application的每一個stage的task進行分配之前都會計算出每個task要計算的是哪個分片數據。Spark的task分配算法優先會希望每個task正好分配到它要計算的數據所在的節點,這樣的話,就不用在網絡間傳輸數據。
但是,有時可能task沒有機會分配到它的數據所在的節點。為什么呢,可能那個節點的計算資源和計算能力都滿了。所以這種時候, Spark會等待一段時間,默認情況下是3s到最后,實在是等待不了了,就會選擇一個比較差的本地化級別。比如說,將task分配到靠它要計算的數據所在節點比較近的一個節點,然后進行計算。
對于第二種情況,通常來說,肯定是要發生數據傳輸,task會通過其所在節點的BlockManager來獲取數據,BlockManager發現自己本地沒有數據,會通過一個getRemote()方法,通過TransferService(網絡數據傳輸組件)從數據所在節點的BlockManager中,獲取數據,通過網絡傳輸回task所在節點。
對于查詢時,并不希望是類似于第二種情況的發生。最好的,當然是task和數據在一個節點上,直接從本地executor的BlockManager中獲取數據,純內存,或者帶一點磁盤IO。如果要通過網絡傳輸數據的話,性能會下降。大量網絡傳輸,以及磁盤IO,都是性能的殺手。
調節數據本地等待時長的適合場景
觀察spark作業的運行日志。推薦大家在測試的時候,先用client模式在本地就直接可以看到比較全的日志。日志里面會顯示:starting task…,PROCESS LOCAL、NODE LOCAL。觀察大部分task的數據本地化級別,如果大多都是PROCESS_LOCAL,那就不用調節了。如果是發現,好多的級別都是NODE_LOCAL、ANY,最好就去調節一下數據本地化的等待時長。要反復調節,每次調節完以后再運行并觀察日志,看看大部分的task的本地化級別有沒有提升,看看整個spark作業的運行時間有沒有縮短。注意,不要本末倒置,不要本地化級別是提升了,但是因為大量的等待時長,spark作業的運行時間反而增加了,那還是不要調節了。
調節方式
spark.locality.wait,默認是3s。6s,10s
默認情況下,下面3個的等待時長,都是跟上面那個是一樣的,都是3s
spark.locality.wait.process
spark.locality.wait.node
spark.locality.wait.rack
new SparkConf().set("spark.locality.wait", "10")