Sparkエラーがサーバに接続できない解決策について(Failed to connect to master_hostname:7077)


問題発生
Sparkクラスタは、MesosまたはYARNに基づいて導入することも、独自のクラスタマネージャを使用してstandaloneモードで導入することもできます.筆者がstandaloneモードを導入する際、
まず、次のコマンドでMasterを起動します.
./sbin/start-master.sh

正常に起動したら、http://master_ip:8080/Masterに接続されたUIは、ページにURLがspark://host_name:7077.
そして、次のコマンドでSlaveを起動します.
./sbin/start-slave.sh spark://host_name:7077

しかしSlaveはMasterに接続できず、そのログを調べると、以下のエラーが得られます.
17/02/20 15:31:12 INFO Worker: Retrying connection to master (attempt # 2)
17/02/20 15:31:12 INFO Worker: Connecting to master 10.xx.xx.xx:7077...
17/02/20 15:31:12 WARN Worker: Failed to connect to master 10.xx.xx.xx:7077
org.apache.spark.SparkException: Exception thrown in awaitResult
        at org.apache.spark.rpc.RpcTimeout$$anonfun$1.applyOrElse(RpcTimeout.scala:77)
        at org.apache.spark.rpc.RpcTimeout$$anonfun$1.applyOrElse(RpcTimeout.scala:75)
        at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
        at org.apache.spark.rpc.RpcTimeout$$anonfun$addMessageIfTimeout$1.applyOrElse(RpcTimeout.scala:59)
        at org.apache.spark.rpc.RpcTimeout$$anonfun$addMessageIfTimeout$1.applyOrElse(RpcTimeout.scala:59)
        at scala.PartialFunction$OrElse.apply(PartialFunction.scala:167)
        at org.apache.spark.rpc.RpcTimeout.awaitResult(RpcTimeout.scala:83)
        at org.apache.spark.rpc.RpcEnv.setupEndpointRefByURI(RpcEnv.scala:88)
        at org.apache.spark.rpc.RpcEnv.setupEndpointRef(RpcEnv.scala:96)
        at org.apache.spark.deploy.worker.Worker$$anonfun$org$apache$spark$deploy$worker$Worker$$tryRegisterAllMasters$1$$anon$1.run(Worker.scala:216)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Failed to connect to /10.xx.xx.xx:7077
        at org.apache.spark.network.client.TransportClientFactory.createClient(TransportClientFactory.java:228)
        at org.apache.spark.network.client.TransportClientFactory.createClient(TransportClientFactory.java:179)
        at org.apache.spark.rpc.netty.NettyRpcEnv.createClient(NettyRpcEnv.scala:197)
        at org.apache.spark.rpc.netty.Outbox$$anon$1.call(Outbox.scala:191)
        at org.apache.spark.rpc.netty.Outbox$$anon$1.call(Outbox.scala:187)
        ... 4 more
Caused by: java.net.ConnectException: Connection refused: /10.xx.xx.xx:7077
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
        at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:224)
        at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:289)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:528)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
        ... 1 more

これはよくある問題で、インターネットで検索しても多くの人が出会ったことがわかります.具体的にどのようにこの問題を解決するか、以下を見てください.
問題解決プロセス
これはいったいネットワーク接続の問題なのか、それともSpark接続の問題なのか.以下は筆者がこの問題を解決する構想の過程である.
ファイアウォールを閉じる
ファイアウォールでは、接続やポートがブロックされる場合があります.また、どのサービスが役に立つか分からない場合は、まずファイアウォールを閉じ、ファイアウォールによる問題であることを確認し、ファイアウォールの戦略を調整することが最善の方法です.筆者はUbuntu Serverを使用しており、ファイアウォールを閉じるコマンドは以下の通りです.
ufw disable

ファイアウォールのステータスを確認するには、次のコマンドを使用します.
ufw status verbose

この問題に対して、ファイアウォールを閉めたが、同じエラーメッセージが表示されたことに気づいた.他の案を考え続ける.
hostnameの変更
筆者MasterのいるLinux、hostnameはrootで、簡単すぎて、接続しますspark://host_name:7077はDNSによって他のホストに解析されますか.Masterホストでhostnameを変更するには、次のコマンドで2つのファイルを変更する必要があります.
vim /etc/hostname 
vim /etc/hosts

修正後、Masterを起動し、Slave接続を再起動しますspark://new_host_name:7077、まだ間違っています.newに接続できないと推測しますhost_name、Slave接続の開始に変更spark://master_ip:7077、依然としてエラーが発生しています.newに接続できないと推測しますhost_name、Slave接続sparkの起動に変更
Masterホストポート7077に接続できることをnmapで確認する
では、Masterの7077ポートは接続できないのではないでしょうか.nmapツール(apt install nmap)をダウンロードし、Slaveホストで次のコマンドでテストします.
nmap -p 7077 master_ip

7077ポートが接続可能であることを確認します.
python環境
筆者の環境ではpythonバージョンが2.7であるのがデフォルトですが、筆者はvirtualenvでSparkをPython 3.5環境で実行しています.ここではpython 2.7でもPython 3.5のvirtualenvでも問題は解決できません.
JDK構成
筆者のJAVA_HOME,CLASSSPATH,PATHは~/.bashrcに書かれており,ここではsourceコマンドでこれらの環境変数を再利用できる.依然として問題を解決できない.
Sparkプロファイルの変更
stackoverflowではconf/spark-env.shを大量に修正する方法も調べた.これらの修正はそれぞれMasterとSlaveで行われたが、まだ問題を解決できない.
マスター起動パラメータの追加
最後に、stackoverflowで小さな回答を見つけ、Masterの起動方法を修正しました.
./sbin/start-master.sh -h master_ip

正常に起動したら、http://master_ip:8080/Masterに接続されたUIは、ページにURLがspark://master_ip:7077.ここのURLはspark://host_name:7077からspark://master_ip:7077.
そして、次のコマンドでSlaveを正常に起動しました!!
./sbin/start-slave.sh spark://master_ip:7077

結論Best Practice:-hパラメータでMasterを起動し、MasterのUIに接続し、URLがspark://master_ip:7077ではなくspark://host_name:7077.これでSlave接続Masterの問題は発生しません.