概述
確保 HADOOP_CONF_DIR 或者 YARN_CONF_DIR 指向包含 Hadoop(客戶端)配置文件的目錄。這些配置文件用於寫HDFS和連接YARN ResourceManager。這個目錄下包含的配置文件被分發給YARN集群,這樣application所使用的容器都使用同樣的配置。如果配置引用了Java系統屬性或非YARN管理的環境變量,他們也應該被配置在Spark application的配置中(driver,executors,client 模式下的AM)。
有兩種YARN上的部署模式。cluster模式,Spark driver運行在由YARN管理的一個application master進程內。啟動這個application後,客戶端可以撤離。client模式,driver運行在客戶端進程內,application master僅被用於向YARN請求資源。
和Spark standalone,Mesos不同,部署在YARN上,master的地址由--master指定,ResourceManager的地址從Hadoop配置中獲取。這樣--master配置為”yarn”。
以cluster模式在YARN上運行application
$ ./bin/spark-submit --class path.to.your.Class --master yarn --deploy-mode cluster [options]
例如:
$ ./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 \\
lib/spark-examples*.jar \\
10
上面啟動一個 YARN 客戶端程序,這個客戶端程序啟動了默認的 Application Master。SparkPi將作為Application Master的子線程運行。客戶端定期地輪詢Application Master獲得狀態的更新並將在控制檯展示出來。一旦Application 運行完成客戶端就退出。
添加其他的jar
在cluster模式下,driver運行在與客戶端不同的機器上,因此SparkContext.addJar不能使用位於客戶端本地的文件。為了使SparkContext.addJar可以利用客戶端本地文件,通過--jars指定這些文件(jar)。
$ ./bin/spark-submit --class my.main.Class \\
--master yarn \\
--deploy-mode cluster \\
--jars my-other-jar.jar,my-other-other-jar.jar \\
my-main-jar.jar \\
app_arg1 app_arg2
準備工作
在YARN上運行Spark需要YARN 支持的binary distribution of Spark(Spark的二進制分佈式文件),可以下載他:
http://spark.apache.org/downloads.html
為了能夠在YARN上使用Spark運行時jar(Spark runtime jars),需要設置spark.yarn.archive 或spark.yarn.jars,如果沒有指定其中之一,那麼Spark會將$SPARK_HOME/jars下的文件打包為zip文件並上傳到分佈式緩存。
為了省去這個過程,將jar包放到HDFS上,並在程序中設置這個參數:
sparkConf.set("spark.yarn.jar", "hdfs://192.168.106.210:8020/sparkjar/spark-assembly-1.6.0-hadoop2.6.0.jar");
調試應用
在YARN術語中,executors和application masters運行在“containers”中。YARN有兩種處理應用完成後的container日誌的模式。如果啟用日誌聚合(配置yarn.log-aggregation-enable),container日誌會被拷貝到HDFS並將本機日誌刪除。在集群的任何一臺機器上都可以使用yarn logs這個命令查看日誌。
yarn logs -applicationId
打印指定application的全部容器的所有日誌的全部內容。也可以使用HDFS Shell或API查看日誌。通過查看yarn.nodemanager.remote-app-log-dir 和yarn.nodemanager.remote-app-log-dir-suffix可以找到日誌文件的目錄。也可以在Spark Web UI中找到這些日誌,前提是Spark history server和MapReduce history server必須運行,並且配置了yarn-site.xml的yarn.log.server.url屬性。Spark history server的日誌URL會重定向到MapReduce history server以展示聚合信息。
日誌聚合沒有開啟的話,每臺機器生成的日誌仍然保存在本地,存儲路徑通過YARN_APP_LOGS_DIR配置指定,常被指定為/tmp/logs 或$HADOOP_HOME/logs/userlogs,這取決於Hadoop版本和具體的安裝情況。這時查看container日誌要到包含那個container的主機去查。
要想回顧每個container的運行環境,增大yarn.nodemanager.delete.debug-delay-sec的值(如36000),並且通過設置yarn.nodemanager.local-dirs來使用每個在container啟動的節點上
的application緩存。這個目錄包含了啟動腳本,jar和所有用來啟動container的環境變量。這個過程有助於調試路徑問題。注意,啟用此功能需要集群設置的管理員權限並且還要重啟所有node manager,因此這不適用於託管集群。
application master或executor要使用自定義的log4j配置,一些選項如下:
1)使用spark-submit命令,將log4j.properties文件路徑加入--files文件列表,實現上傳log4j.properties。
2)設置spark.driver.extraJavaOptions(對於驅動)或spark.executor.extraJavaOptions(對於executors)為
-Dlog4j.configuration=<location>。如果使用文件,應明確指出file:協議並且這個文件在每個節點都應存在。/<location>
3)更新$SPARK_CONF_DIR/log4j.properties並且這個配置文件會和其他配置一起上傳到集群。如果指定了多個選項,那麼上兩個選項的優先權比此項高。
注意,對於第一個選項,所有的driver和executor將共享相同的log4j配置文件,如果這些driver和executor都運行在一個節點上就會有問題(日誌都寫到一個文件裡)。
如果你需要一個引用,指向YARN上的正確位置來放置日誌文件,以便YARN能夠正確地展示和聚合他們,那麼在log4j.properties中配置spark.yarn.app.container.log.dir。例如log4j.appender.file_appender.File=${spark.yarn.app.container.log.dir}/spark.log。對於streaming application,配置RollingFileAppender並且將文件路徑設置為YARN的日誌目錄,這樣可以避免大日誌文件引起磁盤溢出,並且YARN日誌工具可以訪問這些日誌文件。
為了使用application master和executor的自定義度量屬性,更新$SPARK_CONF_DIR/metrics.properties文件。這個文件連同其他配置一起被上傳,這樣你就不用使用--files來指定他。
Spark Properties(Spark屬性)
註釋
1)調度描述中的核心請求是否會執行取決於使用的調度器(scheduler )和如何配置他。
2)在cluster模式在,Spark executors和Spark driver使用的本地目錄
是YARN上配置的本地目錄(Hadoop YARN 的配yarn.nodemanager.local-dirs)
如果用戶指定了spark.local.dir,他會被忽略。在client模式中,Spark executors會使用YARN上配置的本地目錄,然而Spark driver會使用spark.local.dir。這是因為client模式下Spark driver不會在YARN集群上運行,只有Spark executors在YARN集群上運行。
3)--files和--archives選項支持以#指定的文件名,這與hadoop類似。例如可以指定:--files localtest.txt#appSees.txt,會將本地名為localtest.txt的文件上傳到HDFS上,但會使用appSees.txt來連接,當應用運行在YARN上時,要使用appSees.txt來引用這個文件。
4)如果模式為cluster,--jars選項使用本地文件,那麼他使SparkContext.addJar這個方法起作用。如果使用HDFS, HTTP, HTTPS, 或FTP,那麼不必使用--jars。
在一個安全的集群上運行
在安全的Hadoop集群上使用Kerberos來認證與服務端和客戶端相關聯的主體。這樣客戶端就能向已認證的服務端發起請求。服務端為已認證的主體賦予權限。
Hadoop服務發行hadoop tokens來授予訪問服務和獲得數據的權限。客戶端必須先獲得與要訪問服務相關的tokens,然後連同application一起發生給YARN集群。
Spark application與Hadoop文件系統(HDFS,webhdfs),HBase,Hive等交互,他必須獲得相關的tokens,這個tokens使用提交application的用戶的Kerberos憑據,這樣這個身份的主體就成為了提交Spark application的主體。
一般在提交應用的時候,Spark自動從集群的默認hadoop文件系統獲得一個token,有可能是HBase或Hive。
如果HBase在classpath中,一個HBase token將被獲得。HBase配置聲明瞭application是安全的(例如hbase-site.xml設置hbase.security.authentication為kerberos),並且spark.yarn.security.credentials.hbase.enabled設置為true。
相似地,如果Hive在classpath中,Hive token將被獲得。他的配置包含了存儲元數據的URI(hive.metastore.uris),並且spark.yarn.security.credentials.hive.enabled設置為true。
如果application需要和其他的安全的hadoop文件系統交互,那麼要使用這些token訪問集群,就必須在調用時明確地指出,可通過spark.yarn.access.hadoopFileSystems這個屬性列出來集群
spark.yarn.access.hadoopFileSystems hdfs://ireland.example.org:8020/,webhdfs://frankfurt.example.org:50070/
Spark支持通過Java Services機制與安全感知系統交互(參見java.util.ServiceLoader)。為了實現這一功能,org.apache.spark.deploy.yarn.security.ServiceCredentialProvider的實現可用於Spark,通過在jar的META-INF/services路徑中的相應的文件列出他們的名字,可以配置spark.yarn.security.credentials.{service}.enabled為false來禁用這個插件,{service}是憑據提供者的名字。
配置外部的Shuffle服務
在每個NodeManager上啟動Spark Shuffle Service,請遵照以下指令:
1)構建Spark,如果使用構建好的,跳過此步驟。
2)找到spark-<version>-yarn-shuffle.jar。如果自己構建Spark,那麼應該放在$SPARK_HOME/common/network-yarn/target/scala-<version>目錄下,如果使用分發版本,應該放在YARN下。/<version>/<version>
3)把這個jar放到集群的所有的NodeManager下。
4)在每個節點的yarn-site.xml文件中,添加spark_shuffle到yarn.nodemanager.aux-services,設置yarn.nodemanager.aux-services.spark_shuffle.class為org.apache.spark.network.yarn.YarnShuffleService
5)在etc/hadoop/yarn-env.sh中,通過設置YARN_HEAPSIZE 增大NodeManager的堆內存,可避免Shuffle過程的垃圾收集問題。
6)重啟所有NodeManager。
shuffle service運行在YARN上時,額外的參數是:
spark.yarn.shuffle.stopOnFailure默認是false,這個參數的含義是當Spark Shuffle Service初始化失敗時,是否停止NodeManager。當Spark Shuffle Service沒有在NodeManager上運行,而NodeManager的container正在運轉,這樣的錯誤可以通過設置上面的參數來阻止。
Kerberos排錯
記錄針對Kerberos操作的額外日誌,設置HADOOP_JAAS_DEBUG這個環境變量
bash export HADOOP_JAAS_DEBUG=true
通過系統屬性sun.security.krb5.debug和sun.security.spnego.debug=true來配置JDK類,即可開啟針對Kerberos和SPNEGO/REST認證的日誌。
-Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true
在Application Master中,可以啟用上面的所有選項
spark.yarn.appMasterEnv.HADOOP_JAAS_DEBUG true spark.yarn.am.extraJavaOptions -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true
如果日誌級別org.apache.spark.deploy.yarn.Client被設置為DEBUG,日誌會包含獲得的所有token,以及這些token到期的詳細信息。
使用Spark History Server
應用端設置Spark的配置為spark.yarn.historyServer.allowTracking=true
在Spark History Server,添加org.apache.spark.deploy.yarn.YarnProxyRedirectFilter到spark.ui.filters配置列表。
實踐
在集群中選擇一臺服務器,輸入命令:spark-submit 回車,得到如下命令模式及參數註釋:
注意:
1)在YARN上運行,那麼master一定是 yarn。
2)deploy-mode值有兩個,一個是cluster,一個是client。在程序中無法指定deploy-mode,只能由spark-submit命令指定。如果在命令中不指定deploy-mode參數,那麼運行方式為client(即默認)。
3)可以通過命令設定master的值,也可以在程序中設置。
4)指定運行應用的用戶賬號。運行spark-submit命令默認以root身份執行命令(即登錄Linux服務器的身份),但是Spark訪問HDFS會遇到權限問題:
18/10/25 08:57:26 INFO yarn.ApplicationMaster: Unregistering ApplicationMaster with FAILED (diag message: User class threw exception: org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=EXECUTE, inode="/home":hdfs:supergroup:d-wx------
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:400)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkTraverse(FSPermissionChecker.java:316)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:243)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:194)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1846)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1830)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkOwner(FSDirectory.java:1775)
at org.apache.hadoop.hdfs.server.namenode.FSDirAttrOp.setPermission(FSDirAttrOp.java:64)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.setPermission(FSNamesystem.java:1886)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.setPermission(NameNodeRpcServer.java:849)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.setPermission(ClientNamenodeProtocolServerSideTranslatorPB.java:509)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:523)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:991)
at org.apache.hadoop.ipc.Server$RpcCall.run(Server.java:869)
這一句:
yarn.ApplicationMaster: Unregistering ApplicationMaster with FAILED (diag message: User class threw exception: org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=EXECUTE, inode="/home":hdfs:supergroup:d-wx------
充分顯示了問題,即以root用戶訪問/home文件,然而其屬於hdfs這個用戶,那麼要以hdfs用戶身份執行spark-submit命令,使用:
sudo -u hdfs spark-submit --class path.to.your.Class --master yarn --deploy-mode cluster [options]
有博文說添加:System.setProperty("HADOOP_USER_NAME", "hdfs");然而只能解決以client模式運行的應用,對於cluster模式這種方式不起作用,所以還是指定執行腳本的用戶這種方式最可靠。
例:不指定master和deploy-mode
spark-submit --class net.cnki.xtsj.a_statistical_information.WordRetrievedStatistics \\
/home/a-statistical-information-0.0.1-SNAPSHOT-jar-with-dependencies.jar
在程序中指定master為yarn:
SparkConf sparkConf = new SparkConf().setMaster("yarn").setAppName("write words to mongodb");
閱讀更多 甜橙很酸 的文章