複数マシン上で Spark アプリケーションをいくつか動かすとき、リソースの割り当てをその都度人が制御していると大変である。 そんなとき、YARN クラスタを構築して、リソースの割り当てを YARN に任せてしまおう。
環境
- Apache Hadoop 3.1.0
- Apache Spark 2.3.0
- OS : Ubuntu 16.04.3 LTS
YARN クラスタの構築
設定ファイルを編集し、YARN サーバ、クライアントを始動する。
設定ファイルの編集
編集する設定ファイル
- ${HADOOPHOME}/etc/hadoop/core-site.xml
- HDFS (分散ファイルシステム)を制御するサーバをどのマシンにするか指定したりする。
- ${HADOOPHOME}/etc/hadoop/hdfs-site.xml
- HDFS 関連の設定ができる。
- ${HADOOPHOME}/etc/hadoop/yarn-site.xml
- マシンのリソースマネージャーの設定ができる。
- どのマシンをリソースマネージャーのサーバにするか、各マシンが YARN に割けるメモリ量をどのくらいにするか、などを指定できる。
- ${HADOOPHOME}/etc/hadoop/workers
- HDFS や YARN の各種サーバのクライアントとなるマシンのIPアドレスを指定する。
それぞれの中身
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://192.168.0.1:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/work1/user/hadoop/datanode</value>
</property>
</configuration>
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
<configuration>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>192.168.0.1</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>28672</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>28672</value>
</property>
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
</configuration>
node01
node02
node03
node04
node05
node06
node07
node08
YARN クラスタの始動
まずは、各マシンが HDFS のデータ置き場として扱うディレクトリ(hadoop.tmp.dir で設定したディレクトリ)を mkdir -p /work1/user/hadoop/datanode
で作る。 これは各マシンが異なるデータを格納するので、共有ディレクトリだとまずい。
次に、作成したディレクトリを HDFS 用のファイルシステムにフォーマットする。
$ hdfs namenode -format # 作成したディレクトリを HDFS ようにフォーマット
$ ${HADOOPHOME}/sbin/start-dfs.sh
$ ${HADOOPHOME}/sbin/start-yarn.sh
起動できたかを確認する。
各ノードにログインして jps
コマンドを打つか、次のコマンドを入力(dshのインストールが必要)
dsh -M -g cluster01 jps
node01: 22168 Jps
node01: 3641 NameNode
node01: 4082 SecondaryNameNode
node01: 4341 ResourceManager
node01: 21739 DataNode
node01: 21885 NodeManager
node02: 14867 Jps
node02: 14422 DataNode
node02: 14567 NodeManager
node03: 26995 Jps
node03: 26550 DataNode
node03: 26695 NodeManager
node04: 18628 NodeManager
node04: 18952 Jps
node04: 18478 DataNode
node05: 16592 Jps
node05: 16120 DataNode
node05: 16270 NodeManager
node06: 23204 DataNode
node06: 23354 NodeManager
node06: 23677 Jps
node07: 29779 DataNode
node07: 29929 NodeManager
node07: 30250 Jps
node08: 9056 Jps
node08: 4694 NodeManager
node08: 3846 DataNode
サーバで5つ、クライアントで3つずつマネージャーが動作していればOK!
Spark アプリケーションの実行
アプリケーションを YARN 上で正しく実行するための設定をし、 YARN のリソースマネージャーにアプリケーションを渡して、実行してもらう。
Spark の設定
${SPARKHOME}/conf/spark-defaults.conf を編集する
# アプリケーションのログを吐くようにする。
spark.eventLog.enabled true
# ログを吐く場所を設定
spark.eventLog.dir file:/work1/user01/tmp/spark-events
# history-server(後述)が読み込むログのディレクトリを設定:基本ログを吐く場所に合わせる。
spark.history.fs.logDirectory file:/work1/user01/tmp/spark-events
# おそらく実行中の一時ファイルの保管場所。 hadoop fs -mkdir とかで作っておくか、file:// のどこかを指定する。
spark.yarn.stagingDir=hdfs:///user01
実行済みのアプリケーションのログをWebUIでチェックするためのサーバを始動する。
${SPARKHOME}/sbin/start-historyserver.sh
YARN に Spark job を投げる。
Spark job の実行の仕方は、spark-submit と spark-shell があるが、これらを実行するときに、「YARN 上で実行してください」、と命令する必要がある。
普通、リソースマネージャーが稼働しているノードの IP & port を明示的に指定するのかなと思うだろうが、worker 上で実行する場合はなぜかその設定をせずに実行できる。
例として、以下のように実行する。
spark-submit \
-master yarn \
--deploy-mode client \
--num-executors 8 \
--executor-cores 4 \
--executor-memory 23g \
--class example.SparkApp \
spark-application.jar
IP アドレスとか指定して、リモートの YARN にジョブを投げる場合はどうすればいいのだろうか。分かる方がいらっしゃいましたら教えてください。
webUI でジョブの状態を確認する。
YARN クラスタの状態はデフォルト設定では、web ブラウザで http://node01:8088 にアクセスすると確認できる。ここから実行中のジョブを監視できる。
一方で、実行後のジョブは、デフォルト設定で http://node01:18080 にアクセスすることで確認できる。