TL;DR Существует много законных применений методов getOrCreate
, но попытка найти лазейку для выполнения соединений на стороне карты не входит в их число.
В целом нет ничего серьезного в SparkContext.getOrCreate
. У этого метода есть свои приложения, и хотя есть некоторые оговорки, в первую очередь:
- В своей простейшей форме он не позволяет вам задавать специфичные для задания свойства, а второй вариант (
(SparkConf) => SparkContext
) требует передачи SparkConf
, что вряд ли является улучшением по сравнению с сохранением SparkContext
/ SparkSession
в область действия.
- Это может привести к непрозрачному коду с "волшебной" зависимостью. Это влияет на стратегии тестирования и общую читабельность кода.
Однако ваш вопрос, в частности:
Теперь иногда внутри задания Spark возникают опасения, что ссылка на SparkContext может взять большой объект (контекст Spark), который не сериализуем, и попытаться распространить его по сети
и
Не используйте SparkContext
getOrCreate
вместо этого вы можете и должны использовать соединения
предполагает, что вы на самом деле используете метод не так, как предполагалось. Используя SparkContext
на узле исполнителя.
val rdd: RDD[_] = ???
rdd.map(_ => {
val sc = SparkContext.getOrCreate()
...
})
Это определенно то, чего вам не следует делать.
Каждое приложение Spark должно иметь один и только один SparkContext
, инициализированный в драйвере, и разработчики Apache Spark во многом предотвратили любые попытки пользователей использовать SparkContex
вне драйвера. Дело не в том, что SparkContext
велико или невозможно сериализовать, а в том, что это фундаментальная особенность вычислительной модели Spark.
Как вы, наверное, знаете, вычисления в Spark описываются ориентированным ациклическим графом зависимостей, который:
- Описывает конвейер обработки таким образом, чтобы его можно было преобразовать в реальную задачу.
- Включает плавное восстановление в случае сбоя задачи.
-
Позволяет правильно распределять ресурсы и обеспечивает отсутствие циклических зависимостей.
Давайте сосредоточимся на последней части. Поскольку каждый исполнитель JVM получает свой собственный экземпляр SparkContext
, циклические зависимости не являются проблемой - RDDs
и Datasets
существуют только в области своего родительского контекста, поэтому вы не сможете использовать объекты, принадлежащие драйверу приложения.
Правильное распределение ресурсов — это совсем другое. Поскольку каждый SparkContext
создает собственное приложение Spark, ваш «основной» процесс не сможет учитывать ресурсы, используемые контекстами, инициализированными в задачах. При этом в менеджере кластера не будет никаких указаний на то, что приложение или как-то взаимосвязано. Это, вероятно, вызовет тупиковые ситуации.
Технически возможно обойти это с тщательным распределением ресурсов и использованием пулов планирования на уровне менеджера или даже отдельного менеджера кластера со своим собственным набором или ресурсами, но Spark не предназначен для этого, он не поддерживается и в целом приведет к хрупкой и запутанной конструкции, где правильность зависит от деталей конфигурации, конкретного выбора менеджера кластера и общего использования кластера.