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, он не поддерживается, и в целом это приведет к хрупкому и запутанному дизайну, где корректность зависит от деталей конфигурации, выбора конкретного менеджера кластера и общего использования кластера.