使用Intellij-idea调试Spark-Application

https://blog.csdn.net/vfgbv/article/details/51952815

https://blog.csdn.net/sddyljsx/article/details/81055313

https://blog.csdn.net/tmzk_hzau/article/details/52181043

https://blog.csdn.net/sinat_27545249/article/details/78443299  ideallij调试spark源码的n中方法

1.背景: Spark是基于内存的分布式计算框架,在大数据时代应用广阔,同Hadoop一样,在写代码时一般都需要将jar部署到集群或者单节点上,这样可能会造成操作上的繁琐。

对此,本人查找了一些方法,使得Spark或者Hadoop程序可以在本地IDE中执行(常见的java编写工具有Eclipse或者IntelliJ),

2. 介绍:在直接运行中肯定报 “A master URL must be set in your configuration“

3. 解决办法:在配置参数(Run/Debug Configuration)中添加本地运行模式(“ -Dspark.master=local ”),即可问题解决。

spark应用调试(idea 环境)

spark shell可以比较方便的分步执行调试spark应用程序,但有时候不是很方便。下面介绍一种直接在idea中调试spark程序的方法。

maven 新建工程

这个不多赘述,注意一点是pom文件中把依赖的spark的scope的provided去掉,因为我们要在idea中直接运行,不会用spark-submit。

以spark pi为例,这里注意要加上.master(“local”),在local模式运行

运行调试

配置一个run configure 就可以运行调试了,简单快捷。

idea会自动帮你下载source,自己标记断点即可。

小技巧

  • 将log4j.propertities设置为trace level,spark会打印更多的调试信息

#配置根Logger 后面是若干个Appender

#log4j.rootLogger=DEBUG,A1,R,E

log4j.rootLogger=TRACE,A1

# ConsoleAppender 输出

log4j.appender.A1=org.apache.log4j.ConsoleAppender

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n

  • 调试 spark sql程序,打印 tree 信息 

  • println(spark.sql("select * from a").queryExecution.analyzed.treeString) 

+- LocalLimit 21` 

+- AnalysisBarrier 

+- Project [cast(age#6L as string) AS age#12, cast(name#7 as string) AS name#13] 

+- Relation[age#6L,name#7] json

这里的spark application是指需要被submit到spark集群计算环境上运行的job,也就是一个jar包,它虽然有main方法,但是肯定不能以直接在IDEA中右键main函数所在类然后选择debug的方式来调试。因为它不是一个独立的可运行的程序,而是运行云spark集群环境之上,是由另外一个JVM来调用的。就如同调试web程序,把web程序部署在tomcat上后,需要以debug的方式启动tomcat才能调试web程序。因此调试Spark Job的关键就是要以debug的方式启动spark Job将要跑的JVM。

启动一个JVM当然是要有一个主类,使用java命令启动,所以需要找到spark启动的java命令。阅读下spark的bin目录下的各个脚本,可以知道,不管是启动master,还是worker,或者是submit一个job,都是最终会落脚到spark-class脚本的最后1行:

    exec "${CMD[@]}"

  • 1

shell变量${CMD[@]}就是最终启动JVM进程的java命令,可以在运行之前把它打印出来:

    echo "${CMD[@]}"

  • 1

修改之后,以local模式提交一个job:

/bin/spark-submit \

  --class "App" \

  --master local[*] \

  target/spark-1.0-SNAPSHOT.jar

  • 1
  • 2
  • 3
  • 4

打印出的命令命令类似于:

/home/zoukang/it/java/jdk1.8.0_77/bin/java -cp /home/zoukang/it/spark/spark-home/conf/:/home/zoukang/it/spark/spark-home/lib/spark-assembly-1.6.2-hadoop2.2.0.jar:/home/zoukang/it/hadoop/hadoop-home/etc/hadoop/:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/common/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/common/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/hdfs/:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/hdfs/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/hdfs/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/yarn/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/yarn/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/mapreduce/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/mapreduce/*:/home/zoukang/it/hadoop/hadoop-home/contrib/capacity-scheduler/*.jar -Xms1g -Xmx1g org.apache.spark.deploy.SparkSubmit --master local[*] --class com.tmzk.App spark-apps/spark-1.0-SNAPSHOT.jar

  • 1
  • 2

可以看出,实际就是运行一个java命令,调试的话我们需要在启动的时候增加调试选项。

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=20000

  • 1

(使用20000端口,可以指定其他的端口)

修改后的命令就是:

/home/zoukang/it/java/jdk1.8.0_77/bin/java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=20000 -cp /home/zoukang/it/spark/spark-home/conf/:/home/zoukang/it/spark/spark-home/lib/spark-assembly-1.6.2-hadoop2.2.0.jar:/home/zoukang/it/hadoop/hadoop-home/etc/hadoop/:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/common/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/common/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/hdfs/:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/hdfs/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/hdfs/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/yarn/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/yarn/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/mapreduce/lib/*:/home/zoukang/it/hadoop/hadoop-home/share/hadoop/mapreduce/*:/home/zoukang/it/hadoop/hadoop-home/contrib/capacity-scheduler/*.jar -Xms1g -Xmx1g org.apache.spark.deploy.SparkSubmit --master local[*] --class com.tmzk.App spark-apps/spark-1.0-SNAPSHOT.jar

  • 1

得到这个命令后,我们就不需要通过脚本来启动spark了,在spark机器上直接运行这个命令,会看到:

    Listening for transport dt_socket at address: 20000

  • 1

被调试JVM已经准备就绪,下一步就是使用IDEA去调式这个JVM。

我们准备的一个简单的spark app如下:

    import org.apache.spark.SparkConf;

    import org.apache.spark.api.java.JavaRDD;

    import org.apache.spark.api.java.JavaSparkContext;

    public class App {

        public static void main( String[] args ) {

            String dataFile = "/test.txt";

            SparkConf sparkConf = new SparkConf().setAppName("Simple App");

            JavaSparkContext sparkContext = new JavaSparkContext(sparkConf);

            JavaRDD<String> data = sparkContext.textFile(dataFile).cache();

            long numAs = data.filter((String str) -> str.contains("a")).count();

            long numBs = data.filter((String str) -> str.contains("b")).count();

            System.out.println("Lines with a : " + numAs + " , lines with b : " + numBs);

        }

    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在程序开头先打一个断点:

建立一个调试:

配置:

1.命一个名字

2.配置被调试JVM所在机器的ip或者主机名

3.端口,和启动被调JVM相同,这里为20000端口

4.配置搜寻源码范围

确定之后点击开始调试:

可以看到:

可以愉快的调试spark app了,而不用每次改了代码->加点print语句->打包->submit->查看输出

这里只讨论了一个机器的spark以本地local的模式启动app,对于调试足够了。不怕麻烦的话应该可以已同样的方式使用debug的方式启动spark集群类各个机器上的JVM,然后在IDEA建立多个remote debug,连接到每个被调试的JVM,完全控制每个worker的执行流程。

另外,如果经常需要调试,可以把spark的bin下的脚本复制一份,适当修改以下($RUNNER变量的值)方便以调试的方式启动spark计算环境。

猜你喜欢

转载自blog.csdn.net/hellojoy/article/details/81232603