AWS Athena Query Partitioning - PullRequest
       26

AWS Athena Query Partitioning

0 голосов
/ 26 апреля 2019

Я пытаюсь использовать AWS Athena для предоставления аналитики для существующей платформы.В настоящее время поток выглядит следующим образом:

  1. Данные закачиваются в Kinesis Firehose как события JSON.
  2. Firehose преобразует данные в паркет с использованием таблицы в AWS Glue и выполняет запись в S3 либо каждые 15 минут, либо когда поток достигает 128 МБ (макс. Поддерживаемые значения).
  3. Когда данные записываются в S3, они разделяются с путем /year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/...
  4. Сканер AWS Glue обновляет таблицу с самыми последними данными разделов каждые 24 часа и делает ее доступной для запросов.

Базовый процесс работает.Однако есть несколько проблем с этим ...

Первая (и самая важная) заключается в том, что эти данные являются частью многопользовательского приложения.Внутри каждого события есть свойство, которое называется account_id.Каждый запрос, который когда-либо будет выполнен, будет выдан определенной учетной записью, и я не хочу сканировать все данные учетной записи для каждого запроса.Мне нужно найти масштабируемый способ запроса только соответствующих данных.Я пытался заставить нас, Kinesis, извлечь account_id и использовать его как раздел.Однако в настоящее время это не поддерживается, и с> 10 000 учетными записями ограничение размера раздела AWS 20k быстро становится проблемой.

Вторая проблема - размер файла!AWS рекомендует, чтобы размер файлов не превышал 128 МБ, поскольку это отрицательно сказывается на времени запросов, поскольку механизм выполнения может тратить дополнительное время на накладные расходы на открытие файлов Amazon S3.Учитывая природу Firehose, я могу достичь максимального размера не более 128 МБ на файл.

1 Ответ

1 голос
/ 28 апреля 2019

С таким количеством учетных записей вы, вероятно, не захотите использовать account_id в качестве ключа раздела по многим причинам. Я думаю, у вас все в порядке с ограничениями, лимит разделов на таблицу составляет 1M , но это не значит, что это хорошая идея.

Однако вы можете значительно уменьшить объем отсканированных данных, разделив их на части идентификатора учетной записи. Если идентификаторы вашей учетной записи распределены равномерно (например, идентификаторы учетной записи AWS), вы можете разделить их по префиксу. Если идентификаторы вашей учетной записи представляют собой числовое разбиение на первую цифру, это уменьшит объем данных, которые каждый запрос будет сканировать, на 90%, а с двумя цифрами - на 99% - при сохранении количества разделов на очень разумных уровнях.

К сожалению, я тоже не знаю, как это сделать с помощью клея. Я считаю, что клей очень бесполезен, когда дело доходит до ETL. Даже простые вещи сложны в моем опыте. Я добился гораздо большего успеха, используя функцию CTAS Athena в сочетании с простой операцией S3 для добавления данных, полученных в результате операции CTAS, в качестве раздела в существующую таблицу.

Если вы найдете способ извлечь идентификатор учетной записи, вы также можете поэкспериментировать с отдельными таблицами для каждой учетной записи, вы можете иметь 100K таблиц в базе данных . Он не будет сильно отличаться от разделов в таблице, но может быть быстрее в зависимости от того, как Athena определяет, какие разделы запрашивать.

Не слишком переживайте по поводу правила о размере файла 128 МБ. Совершенно верно, что иметь много маленьких файлов хуже, чем иметь несколько больших файлов, но также верно и то, что сканирование большого количества данных для отфильтровывания крошечной порции очень плохо сказывается на производительности и стоимости. Athena может выдавать результаты за секунду даже для запросов к сотням файлов размером всего в несколько килобайт. Я бы беспокоился о том, чтобы Афина сначала читала правильные данные, а об идеальных размерах файлов позже.

Если вы расскажете мне больше о количестве данных на учетную запись и ожидаемом сроке службы учетных записей, я могу дать более подробные предложения о том, к чему стремиться.


Обновление: Учитывая, что Firehose не позволяет вам изменять структуру каталогов входных данных, и что Glue, как правило, довольно плох, и дополнительный контекст, который вы предоставили в комментарии, я бы сделал что-то как это:

  • Создание таблицы Athena со столбцами для всех свойств данных и датой в качестве ключа раздела. Это ваша входная таблица, к этой таблице будут выполняться только ETL-запросы. Не беспокойтесь, что входные данные имеют отдельные каталоги для года, месяца и даты, вам нужен только один ключ раздела. Это просто усложняет их использование в качестве отдельных ключей разделов, и наличие одного означает, что он может иметь тип DATE вместо трех отдельных столбцов STRING, которые необходимо собирать в дату каждый раз, когда вы хотите сделать дату расчет.

  • Создайте еще одну таблицу Athena с теми же столбцами, но разделенными на account_id_prefix и либо датой, либо месяцем. Это будет таблица, к которой вы выполняете запросы. account_id_prefix будет одним или двумя символами от идентификатора вашей учетной записи - вам придется проверить, что работает лучше всего. Вам также придется решить, следует ли разбивать на даты или на более длительный промежуток времени. Даты сделают ETL проще и дешевле, но более длительный промежуток времени приведет к уменьшению количества файлов большего размера, что может сделать запросы более эффективными (но, возможно, более дорогими). ​​

  • Создание конечного автомата пошаговых функций, который выполняет следующие функции (в лямбда-функциях):

    • Add новые разделы во входной таблице.Если вы планируете запускать конечный автомат один раз в день, он может просто добавить раздел, соответствующий текущей дате.Используйте API-вызов Glue CreatePartition для создания раздела (к сожалению, для работы требуется много информации, однако для его получения можно выполнить вызов GetTable. Используйте, например, ["2019-04-29"] какValues и "s3://some-bucket/firehose/year=2019/month=04/day=29" как StorageDescriptor.Location. Это эквивалентно запуску ALTER TABLE some_table ADD PARTITION (date = '2019-04-29) LOCATION 's3://some-bucket/firehose/year=2019/month=04/day=29' - но выполнение с помощью Glue быстрее, чем выполнение запросов в Афине, и больше подходит для Lambda.
    • Запуск Запрос CTAS по входной таблице с фильтром на текущую дату, разбитым по первым символам или идентификатору учетной записи и текущей дате. Используйте расположение для вывода CTAS, которое находится ниже местоположения таблицы запросов.Сгенерируйте случайное имя для таблицы, созданной операцией CTAS, эта таблица будет удалена на более позднем этапе. Используйте формат Parquet.
    • Посмотрите на Опрос для статуса задания пример состояниямашина для вдохновения о том, как ждать завершения операции CTAS.
    • После завершения операции CTAS перечислите разделы, созданные во временной вкладкеСоздайте файл с помощью Glue GetPartitions и создайте те же разделы в таблице запросов с помощью BatchCreatePartitions.
    • Наконец удалите все файлы, которые принадлежат разделамтаблицу запросов, которую вы удалили, и удалите временную таблицу, созданную операцией CTAS.

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

Это выглядит много, и похоже на то, что делают Glue Crawlers и Glue ETL - но по моему опыту они не делаютэто так просто.

В вашем случае данные разделены с использованием разделения в стиле Hive, что понимают сканеры клея, но во многих случаях вы не получаете разделы в стиле Hive, а просто Y / M / D (и я не делална самом деле не знаю, что Firehose может доставлять данные таким образом, я думал, что это только Y / M / D).Glue Crawler также будет выполнять много дополнительной работы при каждом запуске, потому что он не может знать, куда были добавлены данные, но вы знаете, что единственный раздел, который был добавлен со вчерашнего дня, это тот, который был добавлен вчера, поэтому сканирование будет сокращено.к сделке в один шаг.

Клей ETL также усложняет задачу и является дорогостоящим сервисом по сравнению с лямбда и пошаговыми функциями.Все, что вам нужно сделать, - это преобразовать исходную форму данных JSON в Parquet и заново разбить ее.Насколько я знаю, это невозможно сделать с меньшим количеством кода, чем запрос Athena CTAS.Даже если бы вы могли выполнить операцию преобразования с помощью Glue ETL в меньшем количестве кода, вам все равно пришлось бы писать много кода для замены разделов в таблице назначения - потому что это то, что Glue ETL и Spark просто не поддерживают.

Athena CTAS на самом деле не была создана для ETL, и я думаю, что описанный выше метод гораздо сложнее, чем должен быть, но я уверен, что он менее сложен, чем попытка сделать то же самое(т.е. постоянно обновлять и потенциально заменять разделы в таблице, основываясь на данных в другой таблице, не перестраивая всю таблицу каждый раз).

Что вы получаете с этим процессом ETL, так это то, что ваш прием не должен беспокоитьсяо разделении больше, чем по времени, но вы по-прежнему получаете таблицы, оптимизированные для запросов.

...