如何在Spark Standalone上调试Spark应用程序?

24
我正在尝试使用主节点和多个工作节点在集群上调试一个Spark应用程序。我已成功地使用Spark独立集群管理器设置了主节点和工作节点。我下载了带有二进制文件的spark文件夹,并使用以下命令设置工作节点和主节点。这些命令是在spark目录中执行的。
启动主节点的命令:
./sbin/start-master.sh

启动工作节点的命令
./bin/spark-class org.apache.spark.deploy.worker.Worker master-URL

提交应用程序的命令
./sbin/spark-submit --class Application --master URL ~/app.jar

现在,我想了解当我提交应用程序时,在工作节点上通过Spark源代码的控制流程(我只想使用其中一个使用reduce()的给定示例) 。我假设我应该在Eclipse上安装Spark。Apache Spark网站上的Eclipse设置链接似乎已损坏。我希望能得到一些关于设置Spark和Eclipse以启用在工作节点上步进Spark源代码的指导。
谢谢!
4个回答

37

重要的是区分调试驱动程序和调试执行器。它们需要在spark-submit中传递不同的选项。

要调试驱动程序,您可以将以下内容添加到spark-submit命令中。然后将远程调试器设置为连接到您启动驱动程序的节点。

--driver-java-options -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
在这个例子中指定了端口5005,但如果该端口上已经有其他程序在运行,则可能需要自定义端口。连接到执行器类似,将以下选项添加到您的spark-submit命令中。
--num-executors 1 --executor-cores 1 --conf "spark.executor.extraJavaOptions=-agentlib:jdwp=transport=dt_socket,server=n,address=wm1b0-8ab.yourcomputer.org:5005,suspend=n"

将地址替换为本地计算机的地址。(测试是否可以从您的Spark集群访问它是一个好主意)。

在这种情况下,以监听模式启动调试器,然后启动Spark程序,等待执行器连接到调试器。重要的是将执行器数量设置为1,否则多个执行器都会尝试连接到调试器,可能会导致问题。

这些示例是用sparkMaster设置为yarn-client运行的,尽管在运行mesos时也可能适用。如果您使用yarn-cluster模式运行,则可能需要将驱动程序设置为连接到您的调试器,而不是将调试器连接到驱动程序,因为您不一定事先知道驱动程序将在哪个节点上执行。


9

如果您只需要调试转换逻辑,可以在本地模式下运行Spark应用程序。这可以在您的IDE中运行,并且您将能够像任何其他应用程序一样进行调试:

val conf = new SparkConf().setMaster("local").setAppName("myApp")

当然,您使用这种设置不会分发问题。将问题分发的方法很简单,只需更改主节点指向您的集群即可。

2
当您在YARN上运行Spark应用程序时,有一个选项如下:
YARN_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5455 $YARN_OPTS"

你可以将以下内容添加到yarn-env.sh文件中,这样就可以通过端口5455进行远程调试。
如果你使用独立模式的spark,我相信这会有所帮助:
export SPARK_JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

1
我已经按照相同的步骤设置了一个Spark独立集群。我能够调试驱动程序、主节点、执行器JVM。
主节点和工作节点配置在服务器级别的机器上。该机器有12个CPU核心。Spark-2.2.0的源代码已从Spark Git Repo克隆。
步骤:
1] 启动主JVM的命令:
root@ubuntu:~/spark-2.2.0-bin-hadoop2.7/bin#
    ./spark-class  -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8787     org.apache.spark.deploy.master.Master

Shell脚本spark-class用于手动启动主节点。第一个参数是以调试模式启动主节点的JVM参数。JVM会暂停并等待IDE进行远程连接。

以下是显示远程调试IDE配置的屏幕截图:

2] 启动Worker JVM的命令:

root@ubuntu:~/spark-2.2.0-bin-hadoop2.7/bin# ./spark-class -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8788 org.apache.spark.deploy.worker.Worker spark://10.71.220.34:7077

与主节点(master)相同,最后一个参数指定了Spark主节点的地址。工作节点(worker)的调试端口为8788。
作为启动的一部分,工作节点会向主节点注册。 截图 3] 一个包含main方法的基本Java应用程序被编译并打包成uber/fat jar。这在文本“学习Spark”中已经解释过。简而言之,Uber jar包含所有传递依赖项。
通过在以下目录运行mvn package来创建:
root@ubuntu:/home/customer/Documents/Texts/Spark/learning-spark-master# mvn package

上述操作会在./target文件夹下生成一个jar包。
下面的屏幕截图是Java应用程序,将提交到Spark集群:
4] 提交命令以将命令提交到独立的集群。
root@ubuntu:/home/customer/Documents/Texts/Spark/learning-spark-master# /home/customer/spark-2.2.0-bin-hadoop2.7/bin/spark-submit --master spark://10.71.220.34:7077

--conf "spark.executor.extraJavaOptions=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8790"

--conf "spark.executor.extraClassPath=/home/customer/Documents/Texts/Spark/
learning-spark-master/target/java-0.0.2.jar" 

--class com.oreilly.learningsparkexamples.java.BasicMapToDouble

--name "MapToDouble"

./target/java-0.0.2.jar

spark://10.71.220.34:7077 → Argument to the java program → 

com.oreilly.learningsparkexamples.java.BasicMapToDouble

· 上述命令来自于运行有主方法应用的客户端节点。然而,转换是在远程执行器 JVM上执行的。

·

  • –conf参数很重要。它们用于配置执行器JVM。执行器JVM由Worker JVM在运行时启动。

    · 第一个conf参数指定Executor JVM应该以调试模式启动并立即暂停。它在端口8790上启动。

    · 第二个conf参数指定执行器类路径应包含提交给执行器的特定应用程序jar。在分布式设置中,这些jar需要移动到Executor JVM机器上。

    · 最后一个参数由客户端应用程序用于连接Spark主节点。

要了解客户端应用程序如何连接到Spark集群,我们需要对客户端应用程序进行调试并逐步执行它。为此,我们需要将其配置为以调试模式运行。

要调试客户端,我们需要编辑脚本spark-submit,如下所示:

从spark-submit中获取的内容

exec "${SPARK_HOME}"/bin/spark-class -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8789 org.apache.spark.deploy.SparkSubmit "$@"

5] 客户端注册后,工作线程在运行时启动执行程序。

下面的截图显示了ExecutorRunner.scala类。

6] 现在我们使用IDE连接到分叉的执行程序JVM。执行程序JVM将在我们提交的应用程序中运行转换函数。

 JavaDoubleRDD result = rdd.mapToDouble( → ***Transformation function/lambda***
      new DoubleFunction<Integer>() {
        public double call(Integer x) {
          double y = (double) x;
          return y * y;
        }
      });

7] 只有当执行“collect”操作时,转换函数才会运行。

8] 下面的截图显示了在列表的多个元素上并行调用mapToDouble函数时,执行器视图的情况。由于有12个核心,执行器JVM将函数在12个线程中执行。由于没有在命令行上设置核心数,工作节点默认设置了选项:-cores=12。

9] 屏幕截图显示客户端提交的代码[maptodouble()]在远程分叉的Executor JVM中运行。

10] 所有任务执行完毕后,Executor JVM退出。客户端应用程序退出后,工作节点解除阻止并等待下一次提交。

参考资料

https://spark.apache.org/docs/latest/configuration.html

我已经创建了一个博客,描述了如何调试这些子系统的步骤。希望能对其他人有所帮助。 概述步骤的博客:

https://sandeepmspark.blogspot.com/2018/01/spark-standalone-cluster-internals.html


1
欢迎来到SO!虽然您的答案可能是100%正确的,但如果该链接被移动、更改、合并到另一个链接或主站点消失,则它也可能变得100%无用。因此,请[编辑]您的答案,并将链接中的相关步骤复制到您的答案中,从而保证您的答案在本网站的整个生命周期内都是100%有效的!**;-)** 您始终可以将链接留在答案底部作为材料来源... - Murmel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接