IDEA远程调试Spark

1.前言

本文讲述如何使用IDEA远程调试spark,这里所说的调试spark包括:

  1. 调试spark应用程序,也就是使用spark算子编写的driver application
  2. spark自身,包括master,worker,所以这个主要针对的是standalone模式下的,使用yarn提交时不存在master和worker这两个角色。

在开始之前会介绍一下如何使用idea远程debug普通的jar应用,然后远程debug spark原理是一样的。

2. 远程debug 普通的jar应用

先假设远程debug的适用场景是:我将应用程序打成jar包,让它运行在服务器上,然后在本地idea里以debug模式去运行这个jar包,希望达到的效果就像在idea里debug本地代码一样:可以断点,可以查看变量值等等。

下文将这个运行在服务器上的jar包称为被调试对象(debuggee)。 本地idea称为调试者(debugger).

远程调试有两种模式,或者说有两种方式可选:

  1. attach模式, 运行debuggee,让其监听某个ip:port,然后等待debugger启动并连接这个端口,然后就可以在debugger上断点调试。
  2. listen模式,让debugger监听某个ip:port, 然后启动debugee连接这个端口,接下来在debugger上断点调试。

以"HelloWorld" 程序为例:

package me.test.helloworld;

public class HelloWorld {
    public static void main(String[] args){
        System.out.println("hello world");
        for(String arg : args){
            System.out.println(arg);
        }
    }
}

-----------
使用mvn打包,然后可以通过如下命令运行:
> java -cp helloworld-1.0-SNAPSHOT.jar me.test.helloworld.HelloWorld arg1 arg2   

2.1 远程调试模式-1 attach模式

在这种模式下让debuggee监听端口等待debugger连接.
IDEA里操作如下图:

模式1.png

按照上图复制-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005,这个是给debuggee的jvm参数。

  • 这里将suspend=n, 改成了suspend=y, 这样debuggee启动后会阻塞住直到debugger连接它
  • address=5005,表示debuggee监听这个端口,也可以指定成address=<ip>:<port>的形式,这里ip是debuggee运行所在的机器的ip
  • 上图中Host, Port应该和上面address中的ip,port一样,debugger会连接这个ip:port
  • transport=dt_socket是debugger和debuggee之间传输协议
  • server=y, 在模式1下这样指定, 表示debuggee作为server等待debugger连接

在idea(debugger)里指定好这些以后, 接下来就是先 运行debuggee了,如下:

java -cp helloworld-1.0-SNAPSHOT.jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=192.168.1.102:5005  me.test.helloworld.HelloWorld arg1 arg2 

运行后出现下面信息:

Listening for transport dt_socket at address: 5005

表示debuggee等待连接。
接下来的过程就是在idea里,设置断点,然后像本地debug一样了。

2.2 远程调试模式-2 listen模式

即让debugger监听端口等待debuggee的连接, 因此先启动debugger。

IDEA里操作如下:


模式2.png

该模式下先启动debugger,也就是启动idea调试,debugger会监听端口等待debuggee连接。

按照上图复制给debuggee的jvm参数:

-agentlib:jdwp=transport=dt_socket,server=n,address=172.16.202.150:5005,suspend=y
  • 这里去掉了onthrow=<FQ exception class name>,onuncaught=<y/n> 不知道是干什么的
  • address==172.16.202.150:5005, debuggee连接该ip:port
  • suspend=y, listen模式下可以去掉
  • server=n, 表示由debuggee发起连接到debugger。

此时debugger先运行并监听端口,接下来运行debuggee就可以了,如下:

java -cp helloworld-1.0-SNAPSHOT.jar -agentlib:jdwp=transport=dt_socket,server=n,address=172.16.202.150:5005 me.test.helloworld.HelloWorld

本章参考使用 Eclipse 远程调试 Java 应用程序

3. 调试Spark

Spark按照角色可以分为Master、 Worker、Driver、Executor。其中Master, Worker只有在Standalone部署模式下才有,使用Yarn提交时只有Driver可Executor。使用Spark算子开发的应用提交执行后会都一个Driver和至少一个Executor,Driver充当job manager的角色,executor作为task executor执行算子。

下文先按照Master,Worker,Driver,Executor的顺序介绍如何远程调试。

3.1 调试Master

Master的main 方法入口在org.apache.spark.deploy.master.Master中。
通过spark源码包中的sbin/start-master.sh运行Master,源码包中查找的jar包的路径是assembly/target/scala-<version>/jars/, 修改了源码后可以通过运行mvn install -DskipTests重新生成jar包到该路径下。

想要远程调试Master主要就是怎么将-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005这种参数设置为启动Master的jvm参数了。

这里涉及到了启动Master的过程,不讲了,直接说方法。Master启动时会接收:SPARK_MASTER_OPTSSPARK_DAEMON_JAVA_OPTS这两个环境变量的值作为master启动的jvm参数,其中:

  1. SPARK_MASTER_OPTS仅仅被Master使用
  2. SPARK_DAEMON_JAVA_OPTS,会被Master和Worker使用

因此可以在start-master.sh中设置环境变量如下:

export SPARK_MASTER_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005

这样运行start-master.sh, 随后就能在${SPARK_HOME}/logs路径下生成的日志文件里看到
Listening for transport dt_socket at address: 5005
这样一条日志信息,表示Master的jvm阻塞并监听端口等待debugger连接,结下来就是在idea里建立远程连接。

还可以在${SPARK_HOME}/conf下面新建一个文件名为java-opts, 在这个文件里放jvm参数,一个参数一行,如下所示:

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

但是这个文件内容会被Master,Worker启动时作为jvm参数使用。

:不要通过以上在几种方式里加-Xmx指定最大堆内存,可以通过设置环境变量SPARK_DAEMON_MEMORY1G等等这种方式设置-Xmx的值。对于Worker也是同样的。

3.2 调试Worker

Worker的main方法在org.apache.spark.deploy.worker.Worker中。
通过sbin/start-worker.sh启动worker。

和Master不同的是Worker的jvm启动参数的值是从环境变量SPARK_WORKER_OPTS读取的。

可以在start-worker.sh中通过

export SPARK_WORKER_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5006

设置。其他和Master一样。

3.3 调试Driver

用户自己使用Spark算子开发应用,然后使用spark-submit.sh提交应用去集群作为一个job运行,job运行起来后会有一个driver和若干executor,driver相当于这个运行中的job的JobManager,负责将RDD DAG划分为stage,创建task,调度task去executor执行等等。

从运行spark-submit脚本,到用户打包的jar被提交的集群运行,中间经历好几个过程。最终是由org.apache.spark.deploy.SparkSubmit,SparkSubmit自身的启动命令是由 org.apache.spark.launcher.Main创建的,创建时会从环境变量SPARK_SUBMIT_OPTS获取值作为SparkSubmit的jvm参数,所以可用export SPARK_SUBMIT_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=<port>来调试SparkSubmit。

说回Driver,可以在${SPARK_HOME}/conf/下创建spark-defaults.conf文件,加入下面一行:

spark.driver.extraJavaOptions      -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5009

spark.driver.extraJavaOptions后面的配置都会作为driver的jvm启动参数,后面就是在idea里断点调试driver了

3.4 调试Executor

driver只是一个job manager的角色,任务的执行(也就是那些spark 算子map, filter...的执行是在executor上执行的)。

executor对应的main方法所在类是org.apache.spark.executor.CoarseGrainedExecutorBackend
由于一个job 可能有多个executor,不是很好调试,不过测试环境下应该可以设置一个executor,executor的jvm启动参数可以通过在${SPARK_HOME/conf/spark-defaults.conf}文件中加入:

spark.executor.extraJavaOptions  your-executor-jvm-params

传递。 比如:

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

设置按照这种方式设置好后,使用spark-submit.sh提交任务,假设是在standalone模式的集群,那么提交运行后Driver会先运行起来, 然后Driver申请在某个Worker上运行org.apache.spark.executor.CoarseGrainedExecutorBackend, 这个会单独起一个jvm,使用spark.executor.extraJavaOptions参数,如果使用模式1 attach模式,你就可以在CoarseGrainedExecutorBackend里断点调试了。

CoarseGrainedExecutorBackend运行起来不代表运行spark 算子的任务运行起来了,Driver会将任务序列化发送给CoarseGrainedExecutorBackend去执行,CoarseGrainedExecutorBackend创建Executor(包org.apache.spark.executor.Executor)去执行task,可以在Executor的run方法断点去调试任务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339