Spark, исполнители загружают/запрашивают данные - очень низкая производительность

Мой пример использования:

Вставьте RDD в файл с помощью saveAsTable (поэтому в файлы ORC). Каждое сохранение создает новый файл (поэтому 1000 000 записи дают мне 1000 000 файлы ORC). Я знаю, что естественно, что для каждого RDD создаются новые файлы (ов) ORC. Тем не менее, я не знаю, почему это так медленно, когда дело доходит до запроса от ThriftServer.

Мой вопрос: как понять такое странное поведение?
Например, SELECT COUNT(*) на 1000 000 строк (так же файлы) занимает около 1 minute (!).
Однако, когда я сохраняю 1000 000 строки в один файл, тот же запрос работает в 50ms.

Я хотел бы понять эту разницу. В конце концов, 1000 000 файлов мало.

Ответ 1

План выполнения высокого уровня действия вашего счета будет таким (если у вас есть файлы в распределенной файловой системе, в качестве примера я буду использовать HDFS):

  • Запросить файлы из HDFS NameNode

  • Загрузка блоков HDFS в исполнителей

  • Рассчитывать на каждый раздел (используя метаданные ORC или напрямую - зависит от реализации) и суммировать все вместе

Некоторые оценки: 1000 000 файлов требуют одинакового количества запросов в NameNode для разрешения физического расположения блоков данных. Это было сделано в < 60 с (< 0,06 мс на запрос) - довольно хорошая работа, выполняемая NameNode. В остальное время Spark загружает данные в память (если необходимо) или/и получает статистику из метаданных ORC. Поэтому я хотел бы профилировать NameNode (или подобную службу, если вы используете S3 или другую) - первым кандидатом является узкое место. От ORC документация:

По сравнению с форматом RCFile, например, формат файла ORC имеет много преимущества, такие как:

a single file as the output of each task, which reduces the NameNode load

В то время как ORC пытается уменьшить количество файлов, ваш код делает наоборот. И

Размер полосы по умолчанию - 250 МБ. Большие размеры полос обеспечивают большие, эффективные чтения из HDFS.

Нижний колонтитул файла содержит список полос в файле, количество строк на полосу и каждого типа данных столбца. Он также содержит количество агрегатов на уровне столбца, мин, макс и сумма.

Простая статистика, такая как счет, предварительно вычисляется и не должна быть проблемой производительности. Вы можете попытаться решить проблему с помощью грубой силы, просто добавляя память и мощность процессора в HDFS NameNode, но я думаю, что разумно хранить небольшое количество файлов. Если ваши данные поступают из какого-то источника потока, вы можете создать какое-то задание уплотнения, которое объединяет небольшие файлы в большой и периодически запускает их. Или, в качестве альтернативы, вы можете читать из источника один раз в 2-5 минут, если такая задержка подходит для вашего случая использования.