文章目录
我们在编写Spark Application或者是阅读源码的时候,我们很想知道代码的运行情况,比如参数设置的是否正确等等。用Logging方式来调试是一个可以选择的方式,但是,logging方式调试代码有很多的局限和不便。今天我就来介绍如何通过IDE来远程调试Spark的Application或者是Spark的源码。
本文以调试Spark Application为例进行说明,本文用到的IDE是IntelliJ IDEA。步骤如下:
设置调试相关参数
JAVA自身支持调试功能,我们仅仅需要在程序启动之前,在JVM里面设置以下参数:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888
-Xdebug 启用调试特性
-Xrunjdwp 启用JDWP实现,包含若干子选项:
transport=dt_socket JPDA front-end和back-end之间的传输方法。dt_socket表示使用套接字传输。
address=8888 JVM在8888端口上监听请求,这个设定为一个不冲突的端口即可。
server=y y表示启动的JVM是被调试者。如果为n,则表示启动的JVM是调试器。
suspend=y y表示启动的JVM会暂停等待,直到调试器连接上才继续执行。suspend=n,则JVM不会暂停等待。
因为 Spark 应用程序是分布式的,所有调试的时候有点麻烦。但是如果知道方法也是很容易的。这里分两种情况来说明:
调试 Driver 端相关代码
Spark应用程序都有一个 Driver,如果你是 yarn-client 模式,这个 Driver 一般在你启动程序的机器上运行。如果你想调试这块模块,我们需要在 Driver 相关参数里面设置调试参数如下:
spark.driver.extraJavaOptions -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888
这个配置可以放到 $SPARK_HOME/conf/spark-defaults.conf
里面;也可以在启动作业的时候通过 --conf
设置,比如:--conf "spark.driver.extraJavaOptions=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888"
这时候我们就可以调试 Driver 相关的代码了。
调试 Executor 端相关代码
一个Spark应用程序一般会启动一个或多个 Executor ,我们应用程序相关的计算逻辑一般都是在这里完成的,所有如果你想调试这块的代码,需要在 Executor 启动的 JVM 加入相关的调试参数如下:
spark.executor.extraJavaOptions -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888
这个配置可以放到 $SPARK_HOME/conf/spark-defaults.conf
里面;也可以在启动作业的时候通过 --conf
设置,比如:--conf "spark.executor.extraJavaOptions=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888"
可以看见,Executor 的调试代码和 Driver 很类似。
启动Spark Application
上面我们已经设置好了相关的调试参数,现在我们可以启动 Spark Application 应用程序了。如下:
[iteblog.com@spark spark]$ ./bin/spark-submit --class scala.ScalaShuffle --master yarn-client --queue queue1 --num-executors 1 --executor-memory 10g --executor-cores 1 spark-1.0-SNAPSHOT.jar /home/wyp/shuffle /home/wyp/sparkshuffle Spark assembly has been built with Hive, including Datanucleus jars on classpath Listening for transport dt_socket at address: 8888
如果你看到第九行的输出(Listening for transport dt_socket at address: 8888),那恭喜你了,启动了远程调试。而且Spark Application正在等待我们的IDE连接它。
在IntelliJ IDEA设置远程调试的IP和Port
如果你需要调试 Driver 相关代码,依次选择 Edit Configurations->点击左上角的+号->Remote
,在弹出的页面里面将Host和Port两个选项设置为你Driver运行所在节点机器的IP和Port。
设置完后,设置好程序的断电,然后再点击IDE上面的 Debug 按钮(就是那个虫子按钮)。
这时候,程序会继续运行,而且在IDE里面会输出以下信息
Connected to the target VM, address: 'www.iteblog.com:8888', transport: 'socket'
而且程序会跳到你设置断点的地方,你可以在你IDE的Dubegger里面看到如下的信息:
调试 Executor 相关的代码和上面设置类似,这里就不介绍了。
问题
在调试 Executor 相关代码大家可能会遇到相关的问题。如下:
17/10/27 13:40:35 WARN cluster.YarnSchedulerBackend$YarnSchedulerEndpoint: Container marked as failed: container_1504162679223_4890447_01_000003 on host: 192.168.0.126. Exit status: 134. Diagnostics: Exception from container-launch: org.apache.hadoop.util.Shell$ExitCodeException: /bin/bash: line 1: 9767 Aborted /home/q/java/jdk1.7.0_25//bin/java -server -Xmx10240m '-Xdebug' '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888' -Djava.io.tmpdir=/tmp/iteblog/nm-local-dir/usercache/iteblog/appcache/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/tmp '-Dspark.driver.port=49676' -Dspark.yarn.app.container.log.dir=/tmp/iteblog/userlogs/application_1504162679223_4890447/container_1504162679223_4890447_01_000003 -XX:OnOutOfMemoryError='kill %p' org.apache.spark.executor.CoarseGrainedExecutorBackend --driver-url spark://CoarseGrainedScheduler@192.168.0.125:49676 --executor-id 2 --hostname 192.168.0.126 --cores 1 --app-id application_1504162679223_4890447 --user-class-path file:/tmp/iteblog/nm-local-dir/usercache/iteblog/appcache/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/__app__.jar --user-class-path file:/tmp/iteblog/nm-local-dir/usercache/iteblog/appcache/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/hadoop-lzo-0.4.20-SNAPSHOT.jar --user-class-path file:/tmp/iteblog/nm-local-dir/usercache/iteblog/appcache/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/mysql-connector-java-5.1.35.jar > /tmp/iteblog/userlogs/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/stdout 2> /tmp/iteblog/userlogs/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/stderr at org.apache.hadoop.util.Shell.runCommand(Shell.java:464) at org.apache.hadoop.util.Shell.run(Shell.java:379) at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:589) at org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.launchContainer(DefaultContainerExecutor.java:200) at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:283) at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:79) 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)
这个问题是 Spark 在同一台机器上启动多个 Executor, 导致端口被占用,出现的异常,这时候你只需要把 --num-executors
设置为1即可解决这个问题。
我们还有可能遇到下面的问题:
17/10/27 13:56:42 WARN spark.HeartbeatReceiver: Removing executor 1 with no recent heartbeats: 12301 ms exceeds timeout 12000 ms 17/10/27 13:56:42 ERROR cluster.YarnScheduler: Lost executor 1 on www.iteblog.com: Executor heartbeat timed out after 12301 ms 17/10/27 13:56:42 WARN scheduler.TaskSetManager: Lost task 0.0 in stage 0.0 (TID 0, www.iteblog.com, executor 1): ExecutorLostFailure (executor 1 exited caused by one of the running tasks) Reason: Executor heartbeat timed out after 12301 ms 17/10/27 13:56:46 ERROR cluster.YarnScheduler: Lost executor 1 on www.iteblog.com: Container container_1504162679223_4902148_01_000002 exited from explicit termination request.
这是因为我们在调试出现的时候,整个程序运行流程就卡到那了。这时候 Driver 就无法接收到 Executor 发来的心跳信息了,从而产生这种异常。解决办法也很简单,只需要把下面两个参数加大即可:
spark.executor.heartbeatInterval spark.network.timeout
spark.executor.heartbeatInterval
参数不能设的比 spark.network.timeout
大。
原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【Spark作业代码(源码)IDE远程调试】(https://www.iteblog.com/archives/1192.html)
Spark on yarn cluster模式,将程序提交后,怎么知道driver运行在哪个节点上了呢?
看博主后面的博文,不要把Standalone跟yarn-cluster搞混乱了
啥意思?
报错如下:java.lang.ClassNotFoundException: scala.ScalaShuffle
环境是spark1.6.4-hadoop2.6.4
为什么?
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888这几个参数放哪里啊?我放到etc/profile里的JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888说无法识别-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888
不是放到etc/profile。SPARK_HOME的bin目录下有个加载环境变量的文件,将这个加载到SPARK_CLASSPATH中。
是spark-class文件吗?
噢,抱歉,昨天回错了,不是那个文件。是spark-env.sh文件里面,加上下面配置即可:
export SPARK_JAVA_OPTS+="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9191"
哈哈,大神谢谢了,灰常感谢。
请问JVM这个参数-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888在哪里设置?我把它放到spark-env.sh会导致程序的执行失败。
我也不知道把这几个参数放哪?你解决这个问题了吗?
直接 spark-submit 加入--driver-java-options "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888"
spark-submit之后程序没有暂停,不知道是什么原因呢?求指教
断点设置了吗?
设置好程序的断电,此处有错别字。这几天我一直在看你的blog,收获不小。
设置好程序的断电,存储有错别字