1. 程式人生 > 其它 >Spark on YARN

Spark on YARN

前言
Spark 可以跑在很多叢集上,比如跑在local上,跑在Standalone上,跑在Apache Mesos上,跑在Hadoop YARN上等等。不管你Spark跑在什麼上面,它的程式碼都是一樣的,區別只是–master的時候不一樣。其中Spark on YARN是工作中或生產上用的非常多的一種執行模式。

YARN產生背景
以前沒有YARN的時候,每個分散式框架都要跑在一個叢集上面,比如說Hadoop要跑在一個叢集上,Spark用叢集的時候跑在standalone上,MPI要跑在一個叢集上面,等等。
而且每個分散式框架在各自的叢集上跑的時候,都有高峰期低峰期的時候,每個時間點也可能不一樣。
這樣的話整個叢集的資源的利用率非常的低。而且管理起來比較麻煩,因為每個框架都跑在各自的叢集上,要去分別管理。
那麼能不能進行統一的資源管理和排程?這樣YARN就產生了。
那麼在YARN上面能跑哪些框架呢?

在YARN上面能執行的框架
有了YARN之後,下圖所有的框架都可以跑在YARN叢集之上,所有的叢集管理都由YARN來負責,可以把YARN理解為:一個作業系統級別的資源管理和排程的框架。
可以在YARN之上跑各種不同的框架,只要它符合YARN的標準就行。這樣做的好處,多種計算框架可以共享叢集資源,按需分配,你需要多少資源,就取YARN上面申請多少資源,這樣可以提升整個資源的利用率。這就是要把各種框架跑在YARN上面的根本原因。

備註:Hive可以跑在MR上面,Tez上面,Spark上面。

YARN架構簡單介紹
之前對YARN架構有詳細介紹,這裡簡單說一下。
角色:RM、NM、AM、Container。
面試題必考:各個角色的職責?一個作業掛掉了之後,它怎麼重試的,重試的機制?YARN的執行流程?

1.client(比如spark)提交一個作業到RM上;
2.RM會找一個NM,並在上面啟動一個Container;
3.在Container裡面跑AM(作業的主程式);
4.一個作業如果要跑的話要申請資源的,所以AM要到RM上面去申請資源。假如說現在拿到了資源:可以在三個NM上面分別啟動Container。
5.拿到了資源列表後,去三個NM上面啟動分別啟動Container來執行task。
上面是一個通用的執行流程。
對於MR來說,這個task是map task或者reduce task;對於Spark來說,這個task就是executor。
如果是MR的話,那麼AM就是MapReduce的Application Master主程式(main函式驅動程式),如果是Spark的話就是Spark的的Application Master主程式(main函式驅動程式)。

Spark on Yarn 概述
直接上圖:

關於之前講的Spark的核心概念:
一個Spark應用程式包含一個driver和多個executor。
Driver program是一個程序,它執行應用程式application裡面的main()函式,並在main函式裡面建立SparkContext。在main函式裡面建立了一堆RDD,遇到action的時候會觸發job,所以程式會有很多job。
job:由Spark action觸發的由多個tasks組成的平行計算。當一個Spark action(如save, collect)被觸發,一個包含很多個tasks的平行計算的job將會生成。
每個job被切分成小的任務集,這些小的任務集叫做stages。
task是被髮送給一個executor的最小工作單元。每個executor上面可以跑多個task。
Executor:在worker node上啟動應用程式的程序,這個程序可以執行多個任務並將資料儲存在記憶體或磁碟儲存中。每個Spark應用程式都有它自己的一組executors。executor執行在Container裡面。
executor是程序級別,一個程序上面可以並行的跑多個執行緒的,所以每個executor上面可以跑多個task。

MapReduce和Spark一個本質的區別:
在MapReduce裡,每一個task都在它自己的程序裡,map對應maptask,reduce對應reducetask,這些都是程序,當一個task完成(maptask或者reducetask)後,這個task程序就結束了。
但是在Spark裡面是不一樣的,在Spark裡面,它的task能夠併發的執行在一個程序裡,就是說一個程序裡面可以執行多個task,而且這個程序會在Spark Application的整個生命週期一直存在,Spark Application是包含一個driver和多個executor的,即使你的作業不再運行了,job執行完了,沒有作業在running,它的executor還是一直在的,
對比MapReduce和Spark可知,MapReduce是基於程序的base-process,Spark是基於執行緒的base-thread。
這樣的話,Spark帶來的好處就是:
如果是MR的話,你跑task的程序資源都要去申請,用完之後就銷燬;但是Spark的話,只要一開始拿到了這些程序資源,後面所有的作業,不需要申請資源,就可以直接快速的啟動,是非常的快。用記憶體的方式進行計算。

當Spark Application去執行的時候,第一步是向Cluster Manager申請資源。
Spark 可以跑在local、Standalone、Apache Mesos、YARN、K8S上。
Cluster Manager可以適配以上各種模式,是Pluggable可插拔的。

ApplicationMaster:AM
每一個YARN上面的Application都有一個AM,這個AM程序,是在第一個Container裡執行的,就是說第一個Container就是來執行AM的,AM去和RM互相通訊請求資源,然後拿到資源後告訴NM,讓NM啟動其它的Container,給我們的程序使用,比如去跑executor。
在YARN裡面,沒有worker Node概念的,因為在YARN裡面,executor是執行在container裡面的,worker概念在standalone存在的。executor是在Container裡執行的,所以Container的記憶體的設定要大於executor的記憶體的,不然跑不起來的。
Spark on yarn模式下,spark僅僅是一個客戶端而已,生產中只需要在有gateway許可權機器上直接解壓部署spark即可,非常的方便,並不需要裝一個叢集。

Spark on Yarn
如何提交Spark應用程式,之前已經講過,官網也有:
http://spark.apache.org/docs/latest/submitting-applications.html
Spark Running on Yarn看官網:
http://spark.apache.org/docs/latest/running-on-yarn.html
支援YARN上執行spark是在版本Spark 0.6.0上新增的,並在後續版本中進行了一些改善。

YARN上面啟動Spark–理論
確保HADOOP_CONF_DIR或YARN_CONF_DIR指向包含hadoop叢集配置檔案的資料夾。這些配置用來寫資料到hdfs,連線到YARN的resourceManager。(就是說要在配置檔案中配置一下,告訴Spark,你要跑在YARN上面,怎麼連線到上面等)。此目錄中包含的配置將分發到YARN群集,以便應用程式使用的所有容器都使用相同的配置。(比如說,你啟動了後,會有很多executor,那麼這些executor的配置都是一樣的,一樣是因為讀取的都是相同的檔案配置)。如果配置引用了不受YARN管理的Java系統屬性或環境變數,那麼也應該在Spark應用程式的配置(driver,executors和AM在客戶端模式下執行時)中進行設定。
(舉例:export HADOOP_CONF_DIR=/home/hadoop/app/hadoop-2.6.0-cdh5.7.0/etc/hadoop/)
There are two deploy modes that can be used to launch Spark applications on YARN. In cluster mode, the Spark driver runs inside an application master process which is managed by YARN on the cluster, and the client can go away after initiating the application. In client mode, the driver runs in the client process, and the application master is only used for requesting resources from YARN.
有兩種模式可以在YARN上啟動Spark 應用。在叢集模式下,Spark驅動程式執行在由叢集上的YARN管理的application master程序(AM程序)內部,客戶端可以在啟動應用程式後關閉。在客戶端模式下,驅動程式在客戶端程序中執行, application master僅用於從YARN請求資源,客戶端是不能關閉的,關掉的話作業就會掛掉。
Unlike other cluster managers supported by Spark in which the master’s address is specified in the --master parameter, in YARN mode the ResourceManager’s address is picked up from the Hadoop configuration. Thus, the --master parameter is yarn.
與Spark支援的其他叢集管理器不同比如Spark standalone和Mesos模式,主節點地址在–master引數中指定,在YARN模式下,ResourceManager的地址從Hadoop配置中提取。因此,–master的引數是yarn。
To launch a Spark application in cluster mode:
$ ./bin/spark-submit --class path.to.your.Class --master yarn --deploy-mode cluster [options] <app jar> [app options]
For example:

$ ./bin/spark-submit --class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \
--driver-memory 4g \
--executor-memory 2g \
--executor-cores 1 \
--queue thequeue \
examples/jars/spark-examples*.jar \
10

以上啟動了執行預設Application Master的YARN客戶端程式。SparkPi 將作為Application Master的一個子執行緒執行。客戶端將定期輪詢Application Master的狀態更新並將其顯示在控制檯中。一旦你的應用結束執行,客戶端將退出。
To launch a Spark application in client mode, do the same, but replace cluster with client. The following shows how you can run spark-shell in client mode:
$ ./bin/spark-shell --master yarn --deploy-mode client
–deploy-mode client不寫的話預設就是client

YARN上面啟動Spark–測試
在我自己的雲主機上(4G記憶體,2個core)
先執行:export HADOOP_CONF_DIR=/home/hadoop/app/hadoop-2.6.0-cdh5.7.0/etc/hadoop/
執行命令:
spark-shell --master yarn --deploy-mode client
發現報錯,修改下,把executor改成1個,記憶體改小一些,執行下面這個命令:

spark-shell --master yarn --deploy-mode client \
--executor-memory 500M \
--num-executors 1

還是報錯,如下。一直沒有解決,可能是雲主機資源太少了的緣故。跑不起來。待解決。。。。。。

ERROR YarnClientSchedulerBackend: The YARN application has already ended! It might have been killed or the Application Master may have failed to start. Check the YARN application logs for more details.
ERROR SparkContext: Error initializing SparkContext.
org.apache.spark.SparkException: Application application_1559720994730_0007 failed 2 times due to AM Container for appattempt_1559720994730_0007_000002 exited with exitCode: 1
For more detailed output, check application tracking page:http://hadoop001:18088/proxy/application_1559720994730_0007/Then, click on links to logs of each attempt.
Diagnostics: Exception from container-launch.
Container id: container_1559720994730_0007_02_000001
Exit code: 1
Stack trace: ExitCodeException exitCode=1:
.....
org.apache.spark.SparkException: Application application_1559720994730_0007 failed 2 times due to AM Container for appattempt_1559720994730_0007_000002 exited with exitCode: 1
....
Container exited with a non-zero exit code 1
Failing this attempt. Failing the application.
.....
如果跑起來之後,可以通過web介面去看相應的job等等,上面有很多資訊。
比如:一個job下面有多個stage,一個stage下面有多個task。
舉例:

//在spark-shell上執行這個命令:
sc.textFile("hdfs://檔案路徑").flatMap(_.split("\t").map((_,1)).reduceByKey(_+_).collect

然後可以去介面上看DAG圖:

可以看出,collect是一個action,遇到collect的時候觸發了這個job;reduceByKey含有shuffle,遇到reduceByKey的時候拆分成兩個stage。

然後deploy-mode為 cluster來啟動,報錯:

[hadoop@hadoop001 ~]$ spark-shell --master yarn --deploy-mode cluster
Exception in thread "main" org.apache.spark.SparkException: Cluster deploy mode is not applicable to Spark shells.
at org.apache.spark.deploy.SparkSubmit.error(SparkSubmit.scala:857)
at org.apache.spark.deploy.SparkSubmit.prepareSubmitEnvironment(SparkSubmit.scala:292)
at org.apache.spark.deploy.SparkSubmit.submit(SparkSubmit.scala:143)
at org.apache.spark.deploy.SparkSubmit.doSubmit(SparkSubmit.scala:86)
at org.apache.spark.deploy.SparkSubmit$$anon$2.doSubmit(SparkSubmit.scala:924)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:933)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
[hadoop@hadoop001 ~]$

之前在yarn的執行架構的時候,提到過:由於driver是在叢集上排程各個任務的,所以它應該靠近工作節點執行,最好是在同一區域網上執行。如果你想傳送請求給遠端的叢集,最好向驅動程式開啟RPC並讓它從附近提交操作,而不是遠離工作節點執行驅動程式。
所以把driver執行在叢集裡面,這樣driver靠近工作節點(executor節點)執行,效能會更好一點。
但是,如果driver執行在本地local,它的日誌就在本地,但是如果執行在叢集裡面,不知道AM執行在哪個節點上,日誌不知道在哪裡,你需要怎麼看日誌?
可通過yarn logs -applicationId 命令查詢yarn上作業日誌。

Spark Properties 屬性
Spark的屬性有:
spark.yarn.am.memory、spark.yarn.max.executor.failures、spark.executor.instances、spark.yarn.am.cores等等
這些都有預設值,也都是可以調的。

當這樣啟動spark-shell的時候:

[hadoop@hadoop001 ~]$ spark-shell --master yarn --deploy-mode client
WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
WARN Client: Neither spark.yarn.jars nor spark.yarn.archive is set, falling back to uploading libraries under SPARK_HOME.
。。。。。

裡面的這個:
Neither spark.yarn.jars nor spark.yarn.archive is set, falling back to uploading libraries under SPARK_HOME.
spark.yarn.jars和spark.yarn.archive沒有被設定,會把SPARK_HOME下面的這些東西打個包上傳到HDFS上面去,這個過程是非常耗效能的。
看一下SPARK_HOME下面,jars和conf路徑下面有很多東西,如果打包上傳到HDFS上面肯定要耗效能的。
可以通過下面這些引數進行設定,不讓它上傳(你可以自己先上傳到HDFS上面去)
spark.yarn.dist.archives
spark.yarn.dist.files
spark.yarn.dist.jars
這個在生產上很有用的。

spark on yarn總結:
1)如果是local模式,driver跑在本地,driver排程task,把task任務傳送給executor,如果是cluster模式,driver跑在叢集裡。
2)如果是local模式,客戶端不可以在啟動應用程式後關閉。如果是cluster模式,客戶端可以在啟動應用程式後關閉
2)AM:Application Master
本地local模式:AM僅僅用於申請資源
cluster叢集模式:AM不僅僅用於申請資源,還有task的排程
(cluster叢集模式:driver跑在AM程序裡面,driver的對task的排程就由AM來執行了)

什麼時候選擇client,什麼什麼選擇cluster?都可以的,你可以選擇cluster,但是很多場景都是選擇client模式的。


————————————————
版權宣告:本文為CSDN博主「liweihope」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/liweihope/article/details/91358144