«Ресурсы превышены во время выполнения запроса» - это статья, в которой обсуждаются проблемы с ограничением памяти, с которыми сталкивается программное обеспечение Google BigQuery, а также способы предотвращения и решения таких проблем.

Эта статья изначально опубликована в моем блоге list.to 5 августа 2019 г.

Предложение Google BigQuery - действительно мощный инструмент для анализа огромных объемов данных в диапазоне менее нескольких секунд, и он разработан для анализа данных в масштабе Интернета с возможностью сканирования данных объемом в петабайты, или, по крайней мере, это то, что GCP Претензии к оферте. Это может стать неожиданностью, учитывая, что название этой статьи предполагает, что мы собираемся говорить о превышении ресурсов. Что ж, это может быть так, а может и нет, и давайте посмотрим, что это такое и как мы можем избежать этой ловушки!

tl: dr Вы неправильно используете BigQuery, избегайте определенных действий, которые не следует выполнять. Потому что BigQuery предназначен для выполнения определенных действий в масштабе петабайтов в субсекундном диапазоне, но не все они предназначены для обработки всех типов запросов.

Чтобы расширить tl: dr, это верно только на момент написания, и однажды это может измениться, но пока давайте разберемся, почему это все так.

В некоторых случаях, когда вы пытаетесь выполнить запрос, вы получаете ошибку «Ресурсы превышены во время выполнения запроса» при попытке построить большую производную таблицу в BigQuery, а иногда даже когда ваш запрос не обрабатывает огромный объем данных и вам может быть интересно, почему вы достигли предела памяти, когда очевидно, что другие организации, такие как Google и Twitter, с гораздо большим объемом данных, похоже, отлично используют это программное обеспечение.

Для начала нам нужно сначала понять некоторые основные детали дизайна / реализации Big Query.

Big Query можно рассматривать как «программное обеспечение для бессерверных распределенных реляционных баз данных», и, если разбить его на части, в основном это означает:

  1. Само программное обеспечение базы данных не всегда доступно, и оно работает как бессерверная функция, когда программное обеспечение запускается только тогда, когда вам нужны ресурсы, например, когда вы запрашиваете данные в базе данных.
  2. Распределенный означает, что программное обеспечение, которое запускается для чтения и записи в вашу базу данных, работает как несколько узлов и, возможно, в нескольких системах / сетевых кластерах. Это связано с тем, что масштабирование по горизонтали, а не по вертикали может быть намного быстрее и экономически целесообразным для такого облачного провайдера, как Google, по сравнению с предоставлением выделенной мощной виртуальной машины с завышенными характеристиками для каждого отдельного пользователя.
  3. Реляционная база данных, по сути, означает, что реляционные данные хорошо хранятся. Если данные имеют фиксированную форму / схему и работают на основе записей и таблиц, а не документов и коллекций, если вы из мира NoSQL.

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

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

BQ действительно хорош в чтении / выборе данных и в определенной степени хорош в их группировке, но когда дело доходит до сортировки и упорядочивания, это плохо. Точно так же, как бессерверные функции предназначены для простых уровней приложений и простоты разработки, а не для тяжелых внутренних вычислений.

Вычислительные ресурсы этих узлов также фиксированы в том смысле, что вы, как конечный пользователь, не можете фактически изменить ограничения и каким-то образом заставить его масштабироваться по вертикали.

Обычно это происходит с запросами, требующими огромного объема памяти для выполнения, или когда внутреннему / производному запросу требуется огромный объем памяти для временного хранения, пока с ним выполняется больше операций.

Почему так происходит?

Поскольку большинство запросов выполняется на нескольких узлах, существуют определенные операции, которые требуют обработки всех данных на одном узле из-за потребностей вычислений, а это означает, что все данные, необходимые для вычисления, должны находиться на одном узле. Это необходимо для этих вычислений, даже если BQ является «распределенной БД», и поскольку BQ - это база данных, работающая по «бессерверной парадигме», у нее есть несколько ограничений для запросов вычислений с одним узлом.
Когда ваш запрос требует слишком много данные должны обрабатываться на одном узле и больше не могут уместиться на этом узле, вы получите ошибку «Ресурсы превышены во время выполнения запроса», и весь запрос завершится неудачно.
В случае сбоя, даже если ваш запрос уже обработал огромный объем данных или запускался очень долго, Google не будет выставлять счет для вашего аккаунта за этот запрос. Поскольку все неудавшиеся запросы не оплачиваются (см. Биллинг BQ).

Какие операции выполняются на одном узле?

Операции, которым необходимо просмотреть все данные в результирующей таблице одновременно, должны выполняться на одном узле.
Неразделенные оконные функции, такие как RANK () OVER () или ROW_NUMBER () OVER (), будут работать с одним node.
Еще одна операция, которая, как упоминалось, сталкивается с множеством проблем, - это предложение ORDER BY. Это операция, которая требует, чтобы один узел видел все данные, поэтому он может достичь предела памяти одного.
Предложение ORDER BY:

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

Когда это будет иметь значение?

Если вы хотите сгенерировать первичный ключ для производной таблицы. Обычный способ сделать это - использовать ROW_NUMBER () OVER () в качестве идентификатора, чтобы сгенерировать порядковый номер для каждой строки в вашей таблице. Если таблица большая, мы выдаем ошибку «Ресурсы превышены», потому что эта функция пытается работать с одним узлом.
Другие ситуации возникают при упорядочивании таблицы, которая требует наличия всех данных для правильной сортировки.
Или на самом деле любые другие задачи, которые не основаны на группировке данных, или задачи, которые нельзя легко разделить для параллельной работы, могут столкнуться с проблемами этого типа.

Как избежать работы с одним узлом, чтобы запрос не завершился ошибкой?

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

Разбиение с использованием сгенерированного ключа

К счастью, есть простой способ обойти это. Вы можете РАЗБИРАТЬ оконную функцию по дате и построить строку в качестве первичного ключа. Например:

CONCAT (CAST (ROW NUMBER () OVER (PARTITION BY event date) AS STRING),
‘|’, (CAST (event_date AS STRING)) как id

Разделение запроса и использование «временных таблиц»

Вы можете попытаться разделить свой запрос на части.
Запишите результаты каждого отдельного подчиненного / внутреннего запроса в другую таблицу в качестве временного хранилища для дальнейшей обработки. Поскольку Big Query также имеет ограничение на максимальный размер ответа, который может быть обработан.
Вы можете сделать это, если используете Legacy или Standard SQL, и вы можете следовать инструкциям в документации. легко.
Делая это, вы эффективно уменьшаете нагрузку на сканирование данных по запросу и можете помочь решить проблему с ограничением памяти.

Дополнительные ресурсы для чтения:

Вот еще несколько ресурсов, которые также отвечают на этот вопрос. Взгляните на этот вопрос с разных точек зрения!

Еще раз спасибо за чтение, JJ здесь и я работаем консультантом по распределенным системам, специализирующимся на создании сложных распределенных систем, которые масштабируются вместе с вашим бизнесом. Этот пост спонсируется Enkel Digital, фирмой по управлению консультантами, которая помогает независимым консультантам, таким как я, добиться успеха в нашей конкурентной отрасли! Следуйте за мной и нашей публикацией здесь на Medium, чтобы получать больше подобных статей, и не стесняйтесь оставлять комментарии для вопросов или обращаться ко мне напрямую через здесь или [email protected] за помощью!

Подпишитесь на нас на linkedin, чтобы получать больше обновлений!



Первоначально опубликовано на list.to.