AWS EMR-IntelliJ удаленная отладка приложения Spark

Я хотел бы отладить приложение Spark, которое работает в кластере AWS EMR. Было бы здорово, если бы я мог подключить и отладить его удаленно с помощью IntelliJ. Я искал, но нашел очень мало.

возможно ли это, и если да, может ли кто-нибудь любезно указать мне в правильном направлении?

спасибо.

1 ответов


во-первых, я хотел бы предупредить, что то, что вы пытаетесь сделать, в основном невозможно из-за множества ошибок и неожиданных случаев использования AWS EMR. Я настоятельно рекомендую заплатить за самый большой экземпляр, который вы можете запустить (у них есть c4.8xlarge в доступном конце и x1.32xlarge для настоящих психов!), и просто установка spark внутри этого экземпляра, и работает свою работу.

предпосылки

  • ваш VPC должен быть правильно настроен чтобы обеспечить любую связь с внешним миром. Это означает, что ваш интернет-шлюз работает правильно. Вы можете проверить это, запустив кластер с парой ключей EC2, изменив группу безопасности мастера, чтобы разрешить SSH-соединения с Вашего компьютера (они, естественно, не делают этого по умолчанию) и пытаясь подключиться к мастеру с Вашего компьютера. Если вы не можете этого сделать,вы не сможете отлаживать. Я даже не мог выполнить это предварительное условие на новом кластере без дополнительных конфигурация!
  • машина, на которой выполняется IntelliJ для отладки, должна быть доступна из интернета. Чтобы проверить это, измените группу безопасности Главного экземпляра, чтобы разрешить исходящие подключения к компьютеру на порту 5005. Затем запустите nc -l 5005 на своей машине. SSH в ваш мастер и попробуйте echo "test" | nc your_ip_address 5005. Пока не увидишь test на терминале вашего устройства не продолжайте.

настройки IntelliJ

создайте новую удаленную конфигурацию. Изменение Режим отладчика для прослушивания. Назовите конфигурацию и сохраните ее. Когда вы нажмете debug, он будет ждать подключения. В этом окне вы увидите "аргументы командной строки для запуска удаленной JVM", читая что-то вроде:

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

вы можете удалить onthrow и oncaught строки как я сделал. Предположим, что ваша отладочная машина доступна через Интернет по адресу 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 ...

отладка executor является дополнительным сложным, так как будет несколько процессов. Вы не можете отлаживать несколько процессов так, как Вы себе представляете в IntelliJ. Кроме того, вы не можете ограничить число исполнителей до 1 в AWS EMR, даже если они утверждают, что это возможно. Я считаю, что это нормально, если другие исполнители не будут (они будут, когда они не могут подключиться к сеансу отладки). Но этот шаг непроверен.

все вместе

вы можете изменить аргументы spark-submit как с SDK и веб-консоль. Обратите внимание, что в SDK вы не должны пытаться объединить "args" самостоятельно-передать их как элементы массива, как он просит вас.

вам нужно будет изменить группу безопасности ведущего устройства с момента создания кластера для отладки драйвера (аналогично с группой безопасности ведомого устройства для отладки исполнителя). Создайте группу безопасности, которая разрешает исходящие соединения с вашим IP-адресом и портом отладчика (т. е. TCP Outbound to 24.13.242.141:5005). Вы следует создать группу безопасности с этой записью и добавить ее в группы безопасности конфигурации экземпляра потока заданий master/slave с помощью AWS SDK (.withAdditionalMasterSecurityGroups(...)). Я не уверен, как это сделать с веб-консоли.

некоторые общие gotchas

  • обязательно используйте Gradle для создания теневой банки с classpath "com.github.jengelman.gradle.plugins:shadow:1.2.4" плагин. Кроме того, включить Zip64. Вы будете загружать результат :shadowJar задача для S3 для фактического выполнения на AWS ЭМИ.
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
}
  • не забудьте запустить приложение Spark с помощью --deploy-mode cluster и --master yarn (в основном нелегальных).
  • чтобы получить доступ к S3 изнутри драйвера или исполнителей на EMR, do не сделайте rigamarole модификации 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 log для ошибок, прежде чем беспокоиться отладки!
  • если вы видите эту ошибку, "предупредите YarnClusterScheduler: начальное задание не принимало никаких ресурсов; проверьте пользовательский интерфейс кластера, чтобы убедиться, что работники зарегистрированы и имеют достаточные ресурсы", в журналах контейнеров обязательно добавьте maximizeResourceAllocation настройки собственность на spark классификация.
new Configuration()
        .withClassification("spark")
        .addPropertiesEntry("maximizeResourceAllocation", "true"))
  • не забудьте закрыть контекст в конце программы драйвера (sc.close()). Иначе пряжа никогда не начнется. Смехотворно недокументирован.
  • ресурсы в теневых банках могут загружаться только классом внутри той же" банки", что и ресурс. Другими словами, Не используйте ClassLoader.getSystemClassLoader(). Если class A обычно в a.jar хочет получить доступ к ресурсу в b.jar и class B класса в b.jar, использовать B.class.getClassLoader().getResource.... Кроме того, используйте относительные пути (опустите косую черту в начале ссылки на ресурс). Я бы предложил поймать NullPointerExceptions и пытается оба, так что ваша банка работает независимо от того, как она упакована.
  • если вы используете классы, реализующие Function интерфейсы и тому подобное, убедитесь, что вы создали конструктор no-arg, который выполняет всю инициализацию, от которой вы можете зависеть. Spark использует сериализацию Kryo (в отличие от сериализации Java) для обоих замыканий и экземпляры функций, и если вы пренебрегаете предоставлением конструктору no-arg кода инициализации для конкретного приложения (например, загрузка из ресурсов), вы не будете выполнять всю инициализацию, которую ожидаете.