当前位置:  开发笔记 > 开发工具 > 正文

AWS EMR - IntelliJ远程调试Spark应用程序

如何解决《AWSEMR-IntelliJ远程调试Spark应用程序》经验,为你挑选了1个好方法。

我想调试在AWS EMR集群上运行的Spark应用程序.如果我可以使用IntelliJ远程连接和调试它将是太棒了.我搜索过但发现很少.

有可能,如果是这样,有人可以指出我正确的方向吗?

谢谢.



1> DoctorPanglo..:

首先,我要提醒您,由于众多错误和AWS EMR的意外使用案例,您尝试做的事情基本上是不可能的.我强烈建议您支付最大的单个实例来运行您的工作(他们拥有c4.8xlarge经济实惠的终端和x1.32xlarge真正的疯狂!),只需spark在该实例内部安装并运行您的工作.

先决条件

您的VPC必须正确配置,以允许任何与外界的连接.这意味着您的Internet网关正常工作.您可以通过启动具有EC2密钥对的群集来进行测试,修改主服务器的安全组以允许来自您的计算机的SSH连接(默认情况下它们自然不会这样做)并尝试从您的计算机连接到主服务器.如果你不能这样做,你将无法调试.我甚至无法在没有其他配置的新集群上满足此先决条件!

必须可以从Internet访问运行IntelliJ以进行调试的计算机.要对此进行测试,请修改主实例的安全组,以允许在端口5005 nc -l 5005上与计算机建立出站连接.然后,在您的计算机上运行.SSH进入你的主人并尝试echo "test" | nc your_ip_address 5005.test在您的机器终端上看到之前,请不要继续.

IntelliJ设置

创建新的远程配置.将调试器模式更改为Listen.命名配置并保存.当你点击调试时,它将等待连接.在该窗口中,您将看到"运行远程​​JVM的命令行参数",读取如下内容:

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

你可以像我一样删除onthrowoncaught行.假设您的调试机器可通过Internet访问24.13.242.141.假装它实际上是读:

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

我们将使用它来设置Spark进程的调试.

Spark设置

有两个可以调试的进程:驱动程序进程(执行SparkContext实例化的代码)和执行程序进程.最终,您将这些JVM选项传递给特殊参数以spark-submit使连接发生.要调试驱动程序,请使用

spark-submit --driver-java-options -agentlib:jdwp=transport=dt_socket,server=n,address=24.13.242.141:5005,suspend=y --class ...

对于调试执行程序进程,您将使用配置选项:

spark-submit --conf "spark.executor.extraJavaOptions=-agentlib:jdwp=transport=dt_socket,server=n,address=24.13.242.141:5005,suspend=y" --class ...

调试执行程序是非常棘手的,因为会有多个进程.您无法以IntelliJ中的想象方式真正调试多个进程.此外,您无法在AWS EMR中将执行程序的数量限制为1,即使他们声称您可以.我相信如果其他执行程序失败(他们将无法连接到您的调试会话时),这是可以的.但这一步未经测试.

把它们放在一起

您可以spark-submit使用SDK和Web控制台修改两者的参数.请注意,在SDK中,您不应该尝试自己连接"args" - 将它们作为数组项传递给它,就像它要求的那样.

您需要从群集开始时修改主安全组,以便调试驱动程序(同样使用从属安全组来调试执行程序).创建一个安全组,允许出站连接到调试器的IP地址和端口(即TCP Outbound到24.13.242.141:5005).您应该使用该条目创建一个安全组,并使用AWS SDK(.withAdditionalMasterSecurityGroups(...))将其添加到主/从作业流实例配置的安全组.我不知道如何从Web控制台执行此操作.

一些常见的陷阱

确保使用Gradle生成带classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4"插件的阴影罐.另外,启用Zip64.您将把:shadowJar任务结果上传到S3以在AWS EMR上实际执行.

buildscript {
    repositories {
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4"
    }
}

apply plugin: "com.github.johnrengelman.shadow"

shadowJar {
    zip64 true
}

确保使用--deploy-mode cluster--master yarn(基本上没有文档)启动Spark应用程序.

为了从EMR中的驱动程序或执行程序内部访问S3,请不要进行修改sc.hadoopConfiguration()(例如,configuration.set("fs.s3n.impl", "org.apache.hadoop.fs.s3native.NativeS3FileSystem");).根本不要配置这些属性!hadoop-aws默认情况下,在EMR环境中正常工作,并自动设置相应的属性.

log4j日志记录选项设置为仅报告WARN和更高.在此SDK中,您将执行以下操作:

.withConfigurations(new Configuration()
    .withClassification("spark-log4j")
    .addPropertiesEntry("log4j.rootCategory", "WARN, console"))

containers/applications_.../container.../stderr.gz在打扰调试之前,请检查日志中的错误!

如果您看到此错误,"WARN YarnClusterScheduler:初始作业未接受任何资源;检查您的集群UI以确保工作者已注册并具有足够的资源",请在容器日志中确保添加分类的maximizeResourceAllocation配置属性spark.

new Configuration()
        .withClassification("spark")
        .addPropertiesEntry("maximizeResourceAllocation", "true"))

不要忘记在驱动程序结束时关闭上下文(sc.close()).否则,Yarn永远不会开始.好笑无言.

shadow JAR中的资源只能由与资源相同的"JAR"内的类加载.换句话说,不要使用ClassLoader.getSystemClassLoader().如果class A通常a.jar想要访问资源b.jar,并且class B是一个类b.jar,请使用B.class.getClassLoader().getResource....此外,使用相对路径(省略资源引用开头的正斜杠).我建议捕捉NullPointerException并尝试两者,这样无论打包方式如何,你的JAR都能正常工作.

如果您使用实现Function接口和类似的类,请确保创建一个无参数构造函数,执行您可能依赖的所有初始化.Spark对闭包和函数实例使用Kryo序列化(而不是Java序列化),如果你忽略了使用特定于应用程序的初始化代码(例如,从资源加载)提供无参数构造函数,则不会执行所有操作你期望的初始化.


我什至不想再尝试了。反正...很好的回应
推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有