我们在编写 Spark Application 或者是阅读源码的时候, 我们很想知道代码的运行情况, 比如参数设置的是否正确等等 用 Logging 方式来调试是一个可以选择的方式, 但是,logging 方式调试代码有很多的局限和不便 今天我就来介绍如何通过 IDE 来远程调试 Spark 的 Application 或者是 Spar k 的源码 本文以调试 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 和 backend 之间的传输方法 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,ad dress=8888 1 / 5
这个配置可以放到 $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/sparkshu ffle Spark assembly has been built with Hive, including Datanucleus jars on classpath Listening for transport dt_socket at address: 8888 2 / 5
如果你看到第九行的输出 (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 3 / 5
调试 Executor 相关的代码和上面设置类似, 这里就不介绍了 问题 在调试 Executor 相关代码大家可能会遇到相关的问题 如下 : 17/10/27 13:40:35 WARN cluster.yarnschedulerbackend$yarnschedulerendpoint: Container m arked as failed: container_1504162679223_4890447_01_000003 on host: 192.168.0.126. Exit st atus: 134. Diagnostics: Exception from container-launch: org.apache.hadoop.util.shell$exitcod eexception: /bin/bash: line 1: 9767 Aborted /home/q/java/jdk1.7.0_25//bin/java -server -Xmx 10240m '-Xdebug' '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888' -Djava.io.tmpdir=/tmp/iteblog/nm-local-dir/usercache/iteblog/appcache/application_1504162679223_4 890447/container_1504162679223_4890447_01_000003/tmp '-Dspark.driver.port=49676' -Dsp ark.yarn.app.container.log.dir=/tmp/iteblog/userlogs/application_1504162679223_4890447/co ntainer_1504162679223_4890447_01_000003 -XX:OnOutOfMemoryError='kill %p' org.apache.s park.executor.coarsegrainedexecutorbackend --driver-url spark://coarsegrainedscheduler@1 92.168.0.125:49676 --executor-id 2 --hostname 192.168.0.126 --cores 1 --app-id application_15 04162679223_4890447 --user-class-path file:/tmp/iteblog/nm-local-dir/usercache/iteblog/appc ache/application_1504162679223_4890447/container_1504162679223_4890447_01_000003/ app.jar --user-class-path file:/tmp/iteblog/nm-local-dir/usercache/iteblog/appcache/applicati on_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-c onnector-java-5.1.35.jar > /tmp/iteblog/userlogs/application_1504162679223_4890447/contain er_1504162679223_4890447_01_000003/stdout 2> /tmp/iteblog/userlogs/application_1504162 679223_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.containerlaun ch.call(containerlaunch.java:283) at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.containerlaun ch.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, 4 / 5
Powered by TCPDF (www.tcpdf.org) 导致端口被占用, 出现的异常, 这时候你只需要把 --num-executors 设置为 1 即可解决这个问题 我们还有可能遇到下面的问题 : 17/10/27 13:56:42 WARN spark.heartbeatreceiver: Removing executor 1 with no recent heartb eats: 12301 ms exceeds timeout 12000 ms 17/10/27 13:56:42 ERROR cluster.yarnscheduler: Lost executor 1 on www.iteblog.com: Execut or 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.ite blog.com, executor 1): ExecutorLostFailure (executor 1 exited caused by one of the running tas ks) Reason: Executor heartbeat timed out after 12301 ms 17/10/27 13:56:46 ERROR cluster.yarnscheduler: Lost executor 1 on www.iteblog.com: Contain er container_1504162679223_4902148_01_000002 exited from explicit termination request. 这是因为我们在调试出现的时候, 整个程序运行流程就卡到那了 这时候 Driver 就无法接收到 Executor 发来的心跳信息了, 从而产生这种异常 解决办法也很简单, 只需要把下面两个参数加大即可 : spark.executor.heartbeatinterval spark.network.timeout spark.executor.heartbeatinterval 参数不能设的比 spark.network.timeout 大 本博客文章除特别声明, 全部都是原创! 转载本文请加上 : 转载自过往记忆 (https://www.iteblog.com/) 本文链接 : () 5 / 5