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,自己标记断点即可。
小技巧
#配置根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
+- 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[@]}"
shell变量${CMD[@]}就是最终启动JVM进程的java命令,可以在运行之前把它打印出来:
echo "${CMD[@]}"
修改之后,以local模式提交一个job:
/bin/spark-submit \
--class "App" \
--master local[*] \
target/spark-1.0-SNAPSHOT.jar
打印出的命令命令类似于:
/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
可以看出,实际就是运行一个java命令,调试的话我们需要在启动的时候增加调试选项。
-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=20000
(使用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
得到这个命令后,我们就不需要通过脚本来启动spark了,在spark机器上直接运行这个命令,会看到:
Listening for transport dt_socket at address: 20000
被调试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
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.配置被调试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计算环境。