Как узнать, какой фрагмент кода работает на драйвере или исполнителе?
Я новичок в Spark. Как узнать, какой фрагмент кода будет работать на драйвере и который будет работать у исполнителей?
Всегда ли мы должны пытаться кодировать, чтобы все выполнялось над исполнителями?. Существуют ли какие-либо рекомендации/способы заставить большую часть вашего кода работать с исполнителями?
Обновление: насколько я понимаю, Transformations запускается на исполнителях и действиях, запускаемых на драйвере, потому что ему нужно вернуть значение. Так ли это нормально, если действие выполняется на драйвере или оно также должно выполняться на исполнителе? Где действительно работает драйвер? на кластере?
Ответы
Ответ 1
Любое приложение Spark состоит из одного процесса драйвера и одного или нескольких процессов Executor. Процесс драйвера будет выполняться на главном узле вашего кластера, а процессы Executor выполняются на узлах Worker. Вы можете увеличить или уменьшить количество процессов Executor динамически в зависимости от вашего использования, но процесс драйвера будет существовать на протяжении всего срока службы вашего приложения.
Процесс драйвера отвечает за множество вещей, включая управление общим потоком управления вашим приложением, перезапуск неудачных этапов и все направления высокого уровня, как ваше приложение будет обрабатывать данные.
Кодирование вашего приложения, чтобы больше данных обрабатывалось Executors, больше подпадает под задачу оптимизации вашего приложения, чтобы он более эффективно/быстрее обрабатывал данные, используя все доступные ему ресурсы в кластере. На практике вам не нужно беспокоиться о том, чтобы все ваши данные обрабатывались исполнителями.
При этом есть некоторые действия, которые при запуске обязательно включают перетасовку данных. Если вы вызываете действие collect
на RDD, все данные передаются в процесс драйвера, и если ваш RDD имеет достаточно большой объем данных, ошибка приложения Out Of Memory
будет вызвана приложением, так как одиночная машина работает процесс драйвера не сможет хранить все данные.
Помня об этом, трансформации ленивы, а действия - нет. Преобразования в основном преобразуют один RDD в другой. Но вызов преобразования на RDD фактически не приводит к обработке каких-либо данных в любом месте, водителю или исполнителе. Все преобразование состоит в том, что он добавляет к графику линии DAG, который будет выполняться при вызове Action.
Таким образом, фактическая обработка происходит, когда вы вызываете действие на RDD. Простейшим примером является то, что вызова collect
. Как только действие вызывается, Spark начинает работать и выполняет ранее сохраненные вычисления DAG на указанном RDD, возвращая результат обратно. Выполнение этих вычислений полностью зависит от вашего приложения.
Ответ 2
Здесь нет простого и простого ответа.
Как правило, все, что выполняется внутри закрытий функций более высокого порядка, таких как mapPartitions
(map
, filter
, flatMap
) или combineByKey
должно обрабатываться в основном машинами-исполнителями. Все операции за их пределами обрабатываются водителем. Но вы должны знать, что это серьезное упрощение.
В зависимости от конкретного метода и языка, по крайней мере часть работы может обрабатываться драйвером. Например, когда вы используете методы combine
-like (reduce
, aggregate
), окончательное слияние применяется локально на машине драйвера. Сложные алгоритмы (как и многие инструменты ML/MLlib) могут чередовать распределенную и локальную обработку, когда это необходимо.
Кроме того, обработка данных - это всего лишь часть всей работы. Драйвер отвечает за ведение учета, обработку аккумулятора, начальное вещание и другие второстепенные задачи. Он также обрабатывает обработку линий и DAG и создает планы выполнения для API более высокого уровня (Dataset
, SparkSQL
).
В то время как вся картина относительно сложна на практике, ваш выбор относительно ограничен. Ты можешь:
- Избегайте сбора данных (
collect
, toLocalIterator
) для обработки локально. - Выполните больше работы с рабочими с
treeReduce
методов tree*
(treeAggregate
, treeReduce
). - Избегайте ненужных задач, которые увеличивают расходы на ведение бухгалтерского учета.
Ответ 3
Я не мог получить ответ ясно. В hadoop у нас есть класс драйвера, карта и класс сокращения, чтобы мы могли четко сказать, какой код будет работать как драйвер.
В spark, есть ли способ понять, какая часть кода будет выполняться в драйвере, а другая - в executor?