Искры из памяти

У меня есть папка с 150 G файлов txt (около 700 файлов, в среднем каждый 200 МБ).

Я использую scala для обработки файлов и вычисления статистики агрегатов в конце. Я вижу два возможных подхода:

  • вручную перебирать все файлы, выполнять вычисления на файл и объединять результаты в конце
  • прочитайте всю папку на один RDD, выполните все операции над этим единственным RDD и пусть искра сделает все распараллеливание

Я склоняюсь к второму подходу, поскольку он кажется более чистым (нет необходимости в распараллеливании определенного кода), но мне интересно, будет ли мой сценарий соответствовать ограничениям, налагаемым моим оборудованием и данными. У меня есть одна рабочая станция с 16 потоками и 64 ГБ оперативной памяти (так что распараллеливание будет строго локальным между разными процессорными ядрами). Я мог бы масштабировать инфраструктуру с большим количеством машин позже, но на данный момент я хотел бы сосредоточиться на настройке параметров для этого сценария с одной рабочей станцией.

Код, который я использую: - считывает TSV файлы и извлекает значимые данные в триплеты (String, String, String) - после этого выполняется некоторая фильтрация, сопоставление и группировка - наконец, данные уменьшаются и вычисляются некоторые агрегаты

Мне удалось запустить этот код с одним файлом (~ 200 МБ данных), однако я получаю java.lang.OutOfMemoryError: превышен верхний предел GC  и/или Java из исключения кучи при добавлении большего количества данных (приложение разбивается на 6 ГБ данных, но я хотел бы использовать его с 150 ГБ данных).

Думаю, мне пришлось бы настроить некоторые параметры, чтобы сделать эту работу. Я был бы признателен за любые советы о том, как подойти к этой проблеме (как отлаживать требования к памяти). Я попытался увеличить "spark.executor.memory" и использовать меньшее количество ядер (разумное существо, что каждому ядру требуется некоторое кучное пространство), но это не помогло решить мои проблемы.

Мне не нужно, чтобы решение было очень быстрым (он может легко работать в течение нескольких часов даже дней, если это необходимо). Я также не кэширую какие-либо данные, а просто сохраняю их в файловой системе в конце. Если вы считаете, что было бы более целесообразно просто пойти с ручным распараллеливанием, я тоже мог бы это сделать.

Ответ 1

Я и моя команда обработали данные csv размером более 1 ТБ на 5 машинах при 32 ГБ оперативной памяти каждый успешно. Это зависит от того, какую обработку вы делаете и как.

  • Если вы перепечатываете RDD, это требует дополнительных вычислений, имеет накладные расходы выше вашего размера кучи, попробуйте загрузить файл более паралелизм за счет уменьшения раздельного размера в TextInputFormat.SPLIT_MINSIZE и TextInputFormat.SPLIT_MAXSIZE (если вы используете TextInputFormat), чтобы повысить уровень paralelism.

  • Попробуйте использовать mapPartition вместо карты, чтобы вы могли обрабатывать вычисление внутри раздела. Если в расчете используется временная переменная или экземпляр, и вы все еще сталкиваетесь с нехваткой памяти, попробуйте уменьшение количества данных на раздел (увеличение раздела число)

  • Увеличьте предел памяти драйвера и памяти исполнителя, используя "spark.executor.memory" и "spark.driver.memory" в искры конфигурации перед созданием Spark Context

Обратите внимание, что Spark - это универсальная кластерная вычислительная система, поэтому она неэффективна (IMHO) с использованием Spark в одной машине

Ответ 2

Чтобы добавить другую перспективу на основе кода (в отличие от конфигурации): иногда лучше понять, на каком этапе ваше приложение Spark превышает память, и посмотреть, можете ли вы внести изменения, чтобы исправить проблему. Когда я изучал Spark, у меня было приложение Python Spark, которое разбилось с ошибками OOM. Причина была в том, что я собирал все результаты обратно в мастер, а не позволял задачам сохранять результат.

например.

for item in processed_data.collect():
   print(item)
  • не удалось с ошибками OOM. С другой стороны,

processed_data.saveAsTextFile(output_dir)

  • работал нормально.