Spark UIでスレッドダンプを見る
どこかで詰まってる/デッドロックしているなどを調べたい場合、スレッドダンプを見るのが有効ですが、それだけならSpark UI上でできます。
EMR上でJMXリモートデバッグ
ここではjvisualvmを使うことにします。
jvisualvmの準備
jvisualvmにプラグインを入れておくと捗ります。
Tools > Plugins
からプラグイン管理画面を開き、Threads Inspectorあたりは入れておくと便利です。
ステップを追加する
前提
- アプリケーションはjarに固めて
s3://path/to/app.jar
に置いてあるとします -
command-runner.jar
でspark-submit
する方法でステップを実行します - EMRクラスタのmasterおよび各ノードは、22番が空いてるものとします
EMRにステップの追加
以下のようなコマンドラインオプションをつけてステップを追加します。
spark-submit --deploy-mode cluster --class com.example.Main --master yarn-cluster \
--conf "spark.executor.extraJavaOptions=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8002 -Dcom.sun.management.jmxremote.rmi.port=8002 -Djava.rmi.server.hostname=127.0.0.1" \
--conf "spark.driver.extraJavaOptions=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=8003 -Dcom.sun.management.jmxremote.rmi.port=8003 -Djava.rmi.server.hostname=127.0.0.1" \
--num-executors 3 --driver-memory 2g --executor-memory 5g --executor-cores 2 \ # このへんはお好みで
s3://path/to/app.jar
これで、driverプロセスに対しては8003
、executorプロセスに対しては8002
でjmx接続できるようになります。
今回は、executorプロセスに接続してみます。
※注意
一つのノードで複数のexecutorが割り当てられうる設定で実行した場合、これだと8002がバッティングする可能性があります。
そういった場合はcom.sun.management.jmxremote.port=0
として、動的にポートを取得するなどの手段をとる必要があります。
executorプロセスの実行されているノードの特定
YARNクラスタ上のどのノードでexecutorが実行されるかは動的に決まるため、各ノードにSSHで入ってlsof
などで8002
番が使われているかどうか確認し、つなぐ先のノードを特定します。
ここでは、ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
だったとします。
SSHトンネルを開く
手元のマシンで以下のコマンドを実行し、8002番のSSHトンネルを開きます。
$ ssh -i key.pem -NL 8002:ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com:8002 hadoop@ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
jvisualvmから接続
あとは127.0.0.1:8002
に対してjvisualvmから接続すればOKです。
IntelliJでステップ実行する(localモード)
IntelliJのリモートデバッグを使えば、Sparkアプリケーションをステップ実行などできます。
ここではlocalモードで行います。(EMR上でもできるはずだけど)
前提
- sparkバイナリを落として
/path/to/spark_home
に解凍しておきます - アプリケーションはjarに固めて
/path/to/app.jar
に置いておきます
IntelliJの前準備
IntelliJを起動し、Run > Edit Configurationsから、リモートデバッグ用のconfigurationを追加しておきます。
+
からRemote
を選択すれば勝手にこれが入力されています。
spark-submit
リモートデバッグ用のオプションをつけて、spark-submitします。
$ cd /path/to/spark_home
$ ./bin/spark-submit --master local \
--driver-java-options "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" \
/path/to/app.jar
IntelliJでリモートデバッグを開始
少し経ってSparkアプリケーションが起動したら、さきほど作成したconfigurationを実行すれば、いつものようにブレークポイントを貼ったりスレッドの状態を見たりwatchを仕込んだりできます。