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...
. Кроме того, используйте относительные пути (опустите косую черту в начале ссылки на ресурс). Я бы предложил пойматьNullPointerException
s и пытается оба, так что ваша банка работает независимо от того, как она упакована. - если вы используете классы, реализующие
Function
интерфейсы и тому подобное, убедитесь, что вы создали конструктор no-arg, который выполняет всю инициализацию, от которой вы можете зависеть. Spark использует сериализацию Kryo (в отличие от сериализации Java) для обоих замыканий и экземпляры функций, и если вы пренебрегаете предоставлением конструктору no-arg кода инициализации для конкретного приложения (например, загрузка из ресурсов), вы не будете выполнять всю инициализацию, которую ожидаете.