欢迎关注大数据技术架构与案例微信公众号:过往记忆大数据
过往记忆博客公众号iteblog_hadoop
欢迎关注微信公众号:
过往记忆大数据

Spark作业代码(源码)IDE远程调试

我们在编写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里面看到如下的信息:



如果想及时了解Spark、Hadoop或者Hbase相关的文章,欢迎关注微信公共帐号:iteblog_hadoop

调试 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)
喜欢 (21)
分享 (0)
发表我的评论
取消评论

表情
本博客评论系统带有自动识别垃圾评论功能,请写一些有意义的评论,谢谢!
(16)个小伙伴在吐槽
  1. Spark on yarn cluster模式,将程序提交后,怎么知道driver运行在哪个节点上了呢?

    Reynold.C2016-06-15 19:11 回复
    • 看博主后面的博文,不要把Standalone跟yarn-cluster搞混乱了

      Reynold.C2016-06-17 10:40 回复
      • 啥意思?

        w3970907702016-06-17 11:33 回复
  2. 报错如下:java.lang.ClassNotFoundException: scala.ScalaShuffle

    环境是spark1.6.4-hadoop2.6.4

    为什么?

    Chinesejie-ZH2016-03-08 17:33 回复
  3. -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

    用户38975978432015-04-13 21:30 回复
    • 不是放到etc/profile。SPARK_HOME的bin目录下有个加载环境变量的文件,将这个加载到SPARK_CLASSPATH中。

      w3970907702015-04-13 21:47 回复
      • 是spark-class文件吗?

        用户38975978432015-04-13 21:50 回复
        • 噢,抱歉,昨天回错了,不是那个文件。是spark-env.sh文件里面,加上下面配置即可:
          export SPARK_JAVA_OPTS+="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9191"

          w3970907702015-04-14 09:53 回复
          • 哈哈,大神谢谢了,灰常感谢。

            用户38975978432015-04-14 10:06
  4. 请问JVM这个参数-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888在哪里设置?我把它放到spark-env.sh会导致程序的执行失败。

    invoker2015-03-13 17:31 回复
    • 我也不知道把这几个参数放哪?你解决这个问题了吗?

      用户38975978432015-04-13 21:28 回复
    • 直接 spark-submit 加入--driver-java-options "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888"

      dandykang2015-07-23 18:04 回复
  5. spark-submit之后程序没有暂停,不知道是什么原因呢?求指教

    shixuluoji2015-01-07 23:39 回复
    • 断点设置了吗?

      w3970907702015-01-30 17:37 回复
  6. 设置好程序的断电,此处有错别字。这几天我一直在看你的blog,收获不小。

    eclipse_spring2015-01-07 21:36 回复
  7. 设置好程序的断电,存储有错别字

    eclipse_spring2015-01-07 21:36 回复