Apache YARN 上で Apache Spark を動かす。


複数マシン上で 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アドレスを指定する。

それぞれの中身

core-site.xml
<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>
hdfs-site.xml
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>
yarn-site.xml
<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>
workers.
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-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 にアクセスすることで確認できる。