Натан Аннекен, старший инженер по данным, 84,51 °

По мере того как продолжается наш путь к пониманию потребителя лучше, чем кто-либо другой, растет и потребность в больших и лучших науках. Благодаря нашему переходу на распределенные технологии, такие как Spark, возможности обработки данных, доступные нам теперь, позволяют манипулировать гораздо большими наборами данных за небольшую часть времени. Несмотря на этот возросший потенциал, слепая передача терабайтов данных в Hadoop редко дает обещанную производительность, которую вы ожидаете от технологии, и, скорее всего, приведет вас в опасное положение с одним из наших дружелюбных администраторов Hadoop. Однако не бойтесь, поскольку в этой короткой статье я надеюсь показать вам несколько советов и приемов, которые вы можете использовать в своих заданиях Spark, чтобы помочь управлять обработкой больших данных.

Первое, что следует учитывать при запуске заданий Spark, - это конфигурация YARN. Как бы мне ни хотелось, я мог бы назвать вам магические числа, которые помогут обеспечить бесперебойную работу всех ваших заданий, правильное количество исполнителей, ядер, случайных разделов, памяти и многого другого будет полностью зависеть от сложности программы, размер входящих данных, размер кластера и т. д. С учетом сказанного, вот несколько общих рекомендаций по некоторым из наиболее важных конфигураций, которые вы можете установить:

  • spark.sql.shuffle.partitions - количество перемешиваемых разделов для вашей программы. Это общее количество сегментов, на которые будут разделены ваши данные при выполнении любых действий, требующих перемешивания по сети. Хорошей отправной точкой является размер ваших входящих данных, разделенный на 250 МБ.
  • num-executors - общее количество исполнителей, которые будут выделены вашей программе во время выполнения. Хотя может возникнуть соблазн подумать, что увеличение этого числа автоматически приведет к увеличению скорости, иногда добавление дополнительных исполнителей может фактически снизить производительность вашей программы. Помните о других командах, которые также используют кластер, и начните тестировать свои задания примерно с 10 исполнителями, прежде чем переходить к более высоким показателям.
  • executor-cores - количество ядер, которые будут выделены вашему заданию Spark для каждого исполнителя во время выполнения. Обычно это число должно быть где-то между 2-6 ядрами, в основном в зависимости от типа операций, которые вы выполняете в своем задании Spark. Как и в случае с количеством исполнителей, попробуйте начать с малого с двух ядер, прежде чем увеличивать.
  • spark.yarn.executor.memoryOverhead - объем служебной памяти, выделенной для каждого исполнителя, запускаемого во время выполнения. Если вы начинаете обнаруживать, что несколько ваших исполнителей разрывают соединение в середине ваших заданий, или видите сообщения об ошибках, в которых говорится, что YARN убил исполнителя из-за превышения пределов памяти, попробуйте увеличить объем служебной памяти исполнителя где-то между 4-8 ГБ.
  • spark.yarn.driver.memoryOverhead - Объем зарезервированного пространства в драйвере для управления любыми накладными расходами, связанными с вашей работой - очень похож на накладные расходы памяти исполнителя. Вообще говоря, чем сложнее ваша программа и чем больше исполнителей вы задействуете для своей работы, тем больше вы должны увеличить накладные расходы на драйверы.
  • driver-memory - объем памяти, зарезервированный для основного выполнения вашей программы. Как правило, память вашего драйвера не должна быть очень большой, если вы не собираете какие-либо данные обратно в драйвер или не выполняете много вычислений за пределами библиотек Spark и функций, доступных для вашей программы. Если YARN часто убивает ваш драйвер из-за превышения пределов памяти, хорошее практическое правило - увеличить объем памяти до 6 ГБ, а затем продолжить увеличение на 2 ГБ, если вы продолжите получать сбои.
  • executor-memory - Общий объем памяти, выделенной каждому исполнителю во время выполнения для вашего задания, аналогично памяти драйвера. Опять же, начните с малого с примерно 6 ГБ выделенной памяти на каждого исполнителя, а затем увеличивайте оттуда по мере необходимости.

Еще одна вещь, которую следует учитывать при запуске заданий Spark, - это структура ваших программ. В общем, есть много простых вещей, которые вы можете сделать программно, чтобы помочь уменьшить объем данных, передаваемых по вашей программе, объем данных, которые должны перемещаться по сети, объем перетасовки данных, который должен произойти, и т. Д. Вот несколько советов по повышению эффективности ваших программ Spark:

  • Примените выборки и фильтры к данным как можно скорее. Отложенное позднее время в вашей программе для фильтрации фреймов данных или отбрасывания столбцов может быть крайне неэффективным; дополнительное время, необходимое для передачи этих данных в случайном порядке по сети, быстро увеличивается.
  • При записи больших таблиц в HDFS выполняйте разделение по ключам соединения / агрегации. Если входящие данные уже были разделены по столбцам, которые вы будете использовать для объединения фреймов данных или вычисления агрегатов, Spark пропустит дорогостоящую операцию перемешивания. Чем больше операций чтения данных будет выполнено ниже по потоку, тем больше времени вы сэкономите на пропущенных перетасовках. Кроме того, разделение по столбцам, которое часто будет использоваться для фильтрации данных, позволит Spark использовать сокращение разделов, чтобы быстро отфильтровать любые ненужные данные.
  • При объединении очень больших наборов данных с небольшими наборами данных используйте широковещательные объединения, чтобы сократить ненужное перетасование сети и, в свою очередь, повысить скорость вашей программы. Широковещательные объединения - это особый тип объединений, которые работают, беря меньший фрейм данных и копируя его каждому исполнителю. Таким образом, Spark больше не нужно перетасовывать данные в обоих фреймах данных по сети, потому что каждый исполнитель может просто использовать свою (полную) копию меньшего фрейма данных для соединения со своей частью большего набора данных.

Последнее, что мы рассмотрим, - это перекос. Перекошенные данные, пожалуй, одна из самых серьезных проблем, с которыми сегодня сталкиваются пользователи Spark, из-за того, как Spark распределяет рабочую нагрузку между исполнителями в задании. Для большинства агрегатов и объединений, требующих перетасовки данных по сети, Spark применяет простой алгоритм хеширования к ключу groupby или join. Алгоритм хеширования создает детерминированное число на основе ключа текущей записи, которое указывает, какому разделу тасования должна быть назначена эта запись. Поскольку каждая запись назначается разделу с перемешиванием, она будет перемещена к тому исполнителю, который отвечает за этот раздел с перемешиванием.

После того, как все данные были перемешаны, все записи с одним и тем же ключом будут назначены одному и тому же разделу перемешивания (и одному исполнителю), чтобы ускорить работу по агрегированию или объединению. Хотя у этого подхода есть много положительных моментов, разделение данных по ключам работает хорошо, только если у вас есть почти четное количество записей для каждого отдельного ключа. Скажем, например, половина ваших данных имеет то же значение, что и его ключ, а остальные ваши данные равномерно разделены между еще 300 ключами. Если бы вы запускали какой-либо тип агрегации или объединения с использованием этого ключа, половина вашего набора данных будет в конечном итоге в одном исполнителе, и этому исполнителю потребуется значительно больше времени для завершения, чем другим исполнителям (если он вообще завершится ). Чтобы обойти эту проблему, группа цифровых инженеров (мы называем себя Jetsons) разработала инструмент, позволяющий принимать два входных фрейма данных и создавать настраиваемое количество «соленых» ключей, которые помогут разделить данные на блоки более равного размера; Если вы столкнетесь с этой проблемой, вы можете подумать о создании аналогичной утилиты.

Хотя использование Spark иногда является проблемой, эффективная настройка и организация программы могут иметь большое значение для улучшения опыта. Я надеюсь, что эти советы помогут вам сделать ваши рабочие процессы более эффективными.