Ограничения на запросы

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

Ограничение на параллелизм запросов

Ограничение на параллелизм запросов — это ограничение кластера на число запросов, выполняющихся одновременно.

  • Значение по умолчанию для ограничения зависит от SKU виртуальных машин в кластере, на которых эти запросы выполняются, и рассчитывается по формуле Cores-Per-Node x 10.
    • Например, для кластера, настроенного на SKU D14v2, где каждый компьютер имеет 16 виртуальных ядер, ограничение по умолчанию — 16 cores x10 = 160.
  • Значение по умолчанию можно изменить, настроив политику ограничения частоты запросов для группы рабочей нагрузки default.
    • Фактическое число запросов, которые можно одновременно выполнять в кластере, зависит от различных факторов. Основные факторы — это SKU виртуальных машин в кластере, доступные ресурсы кластера и шаблоны использования. Политику можно настроить на основе результатов нагрузочных тестов, выполняемых для аналогичных шаблонов использования в рабочей среде.

Дополнительные сведения см. в статье Оптимизация для высокого уровня параллелизма с Azure Data Explorer.

Ограничение на размер результирующего набора (усечение результата)

Усечение результата — это ограничение, заданное по умолчанию для результирующего набора, возвращаемого запросом. Kusto ограничивает число записей, возвращаемых клиенту, до 500 000, а общий объем данных для таких записей — до 64 МБ. При превышении какого-либо из этих ограничений запрос завершается с частичным сбоем выполнения. Превышение общего объема данных приведет к возникновению исключения с таким сообщением:

The Kusto DataEngine has failed to execute a query: 'Query result set has exceeded the internal data size limit 67108864 (E_QUERY_RESULT_SET_TOO_LARGE).'

Превышение числа записей приведет к сбою с таким исключением:

The Kusto DataEngine has failed to execute a query: 'Query result set has exceeded the internal record count limit 500000 (E_QUERY_RESULT_SET_TOO_LARGE).'

Есть несколько стратегий для устранения такой ошибки.

  • Уменьшите размер результирующего набора, изменив запрос, чтобы он возвращал только интересующие вас данные. Эта стратегия полезна, если изначальный запрос с ошибкой охватывает слишком широкий спектр данных, например не отбрасывает ненужные столбцы данных.
  • Уменьшите размер результирующего набора, реализовав в самом запросе последующую обработку, например агрегирование. Такая стратегия подходит для сценариев, в которых выходные данные запроса передаются в другую систему обработки для других операций агрегирования.
  • Чтобы экспортировать крупные наборы данных из службы, используйте функцию экспорта данных вместо запросов.
  • Используйте приведенные ниже инструкции set или флаги в свойствах клиентских запросов, чтобы указать службе не применять ограничение на запросы.

Вы можете использовать следующие методы для уменьшения размера результирующего набора, создаваемого запросом:

Вы можете отключить усечение результатов с помощью параметра запроса notruncation. Но мы все равно рекомендуем использовать ограничения в каком-либо виде.

Пример:

set notruncation;
MyTable | take 1000000

Результат усечения также можно сделать еще более точным с помощью значений truncationmaxsize (максимальный размер данных в байтах, по умолчанию 64 МБ) и truncationmaxrecords (максимальное число записей, по умолчанию 500 000). Например, в приведенном ниже запросе усечение результатов выполняется при достижении 1105 записей или размера в 1 МБ (в зависимости от того, что произойдет раньше).

set truncationmaxsize=1048576;
set truncationmaxrecords=1105;
MyTable | where User=="UserId1"

Отмена ограничения с усечением результатов приведет к тому, что из Kusto будут передаваться все данные.

Вы можете отменить это ограничение, если вы хотите экспортировать данные (с помощью команды .export) или выполнить дальнейшее агрегирование. Во втором случае мы рекомендуем для агрегирования использовать Kusto.

Kusto предоставляет несколько клиентских библиотек, которые могут обрабатывать "бесконечно большие" объемы результатов, передавая их вызывающему объекту в потоковом режиме. Используйте одну из таких библиотек и настройте ее для потоковой передачи. Например, используйте клиент .NET Framework (Microsoft.Azure.Kusto.Data) и задайте для свойства потоковой передачи в строке подключения значение true или используйте вызов ExecuteQueryV2Async() , который всегда выполняет потоковую передачу результатов. Пример использования ExecuteQueryV2Async() см. в разделе Приложение HelloKustoV2 .

Вы также можете ознакомиться с примером приложения для приема потоковой передачи с использованием C#.

Усечение результатов применяется по умолчанию, а не только к потоку результатов, возвращаемого клиенту. Оно также применяется по умолчанию ко всем вложенным запросам, выдаваемым одним кластером другому кластеру в межкластерном запросе, и имеет аналогичное действие.

Установка нескольких свойств усечения результатов

При использовании инструкций set и (или) при указании флагов в свойствах клиентского запроса применяются следующие условия:

  • Если задано свойство notruncation и при этом установлен параметр truncationmaxsize, truncationmaxrecords или query_take_max_records, то notruncation игнорируется.
  • Если truncationmaxsize, truncationmaxrecords и (или) query_take_max_records заданы несколько раз, для каждого свойства применяется меньшее значение.

Ограничение памяти, потребляемой операторами запросов (E_RUNAWAY_QUERY)

Kusto ограничивает память, которую каждый оператор запроса может использовать для защиты от "неуправляемых" запросов. Это ограничение может быть достигнуто некоторыми операторами запросов, такими как join и summarize, которые работают, удерживая значительные данные в памяти. По умолчанию ограничение составляет 5 ГБ (на узел кластера), и его можно увеличить, задав параметр maxmemoryconsumptionperiteratorзапроса :

set maxmemoryconsumptionperiterator=68719476736;
MyTable | summarize count() by Use

При достижении этого предела создается частичный сбой запроса с сообщением, включающим текст E_RUNAWAY_QUERY.

The ClusterBy operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete E_RUNAWAY_QUERY.

The DemultiplexedResultSetCache operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The ExecuteAndCache operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The HashJoin operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The Sort operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The Summarize operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The TopNestedAggregator operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

The TopNested operator has exceeded the memory budget during evaluation. Results may be incorrect or incomplete (E_RUNAWAY_QUERY).

Если свойство maxmemoryconsumptionperiterator задано несколько раз, например в свойствах клиентского запроса и с помощью инструкции set, применяется меньшее значение.

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

Runaway query (E_RUNAWAY_QUERY). Aggregation over string column exceeded the memory budget of 8GB during evaluation.

При превышении этого ограничения, скорее всего, соответствующим оператором joinзапроса является , summarizeили make-series. Чтобы обойти ограничение, необходимо изменить запрос, чтобы использовать стратегию запросов в случайном режиме . (Это также может повысить производительность запроса.)

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

T | where rand() < 0.1 | ...

T | where hash(UserId, 10) == 1 | ...

Ограничение на объем памяти для узла

Максимальный объем памяти на запрос для узла — это еще одно ограничение для защиты от неконтролируемых запросов. Это ограничение, представленное параметром запроса max_memory_consumption_per_query_per_node, задает верхнюю границу для объема памяти, который может использоваться отдельным узлом для конкретного запроса.

set max_memory_consumption_per_query_per_node=68719476736;
MyTable | ...

Если свойство max_memory_consumption_per_query_per_node задано несколько раз, например в свойствах клиентского запроса и с помощью инструкции set, применяется меньшее значение.

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

Ограничение на время ожидания выполнения

Время ожидания сервера — это время ожидания на стороне службы, применяемое ко всем запросам. Время ожидания при выполнении запросов (запросов и команд управления) применяется в нескольких точках в Kusto:

  • в клиентской библиотеке (если она используется);
  • на конечной точке службы, которая принимает запрос;
  • в подсистеме службы, которая обрабатывает запрос.

По умолчанию время ожидания равно четырем минутам для запросов и 10 минутам для команд управления. При необходимости его можно увеличить (до 1 часа).

  • Различные клиентские средства поддерживают изменение времени ожидания в рамках глобальных параметров или параметров подключения. Например, в Kusto. Обозреватель выберите Параметры инструментов>*>Время ожидания сервера запросов подключений>.
  • Программными средствами пакеты SDK поддерживают настройку времени ожидания с помощью servertimeout свойства . Например, в пакете SDK для .NET это делается с помощью свойства запроса клиента, задавая значение типа System.TimeSpan.

Примечания о времени ожидания

  • На стороне клиента временем ожидания считается время с момента создания запроса до момента получения ответа на клиенте. Время на считывание полезных данных на клиенте не учитывается во времени ожидания. Оно зависит от того, как быстро вызывающая сторона получает данные из потока.
  • Кроме того, на стороне клиента фактическое значение времени ожидания будет немного превышать значение времени ожидания сервера, запрашиваемое пользователем. Такая разница позволяет компенсировать задержку в сети.
  • Чтобы автоматически использовать максимально разрешенное время ожидания для запросов, задайте для свойства клиентского запроса norequesttimeout значение true.

Примечание

Пошаговые инструкции по настройке времени ожидания в пользовательском веб-интерфейсе Azure Data Explorer, Kusto.Обозреватель, Kusto.Cli, Power BI и при использовании пакета SDK см. в статье Установка ограничений времени ожидания.

Ограничение на использование запросом ресурсов ЦП

Kusto позволяет при выполнении запросов использовать все ресурсы ЦП в кластере. Kusto применяет циклический перебор со справедливым распределением ресурсов между запросами, если выполняется несколько запросов. Этот метод обеспечивает наилучшую производительность для определяемых запросом функций. В других случаях вам может потребоваться ограничить объем ресурсов ЦП, используемый определенным запросом. Например, при выполнении фонового задания система может допускать более высокие задержки, чтобы предоставить параллельным встроенным запросам высокий приоритет.

Kusto поддерживает указание двух свойств запроса при выполнении запроса. query_fanout_threads_percent и query_fanout_nodes_percent. Оба этих свойства являются целыми числами, которые по умолчанию принимают максимальное значение (100 %), но могут быть изменены на более низкое значение для определенного запроса.

Первое свойство, query_fanout_threads_percent, управляет коэффициентом разветвления для использования потоков. Если установить для свойства значение 100 %, кластер назначит для выполнения запросов все ЦП в каждом узле, например 16 ЦП в кластере, развернутом на узлах Azure D14. Если установить для этого свойства значение 50 %, будет использоваться половина ЦП, и т. д. Числа округляются до целых, поэтому для ЦП свойству можно присвоить значение 0.

Второе свойство, query_fanout_nodes_percent, управляет тем, сколько узлов запросов в кластере необходимо использовать для каждой операции распределения вложенных запросов. Она действует аналогичным образом.

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

Ограничение на сложность запросов

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

В следующих примерах показаны распространенные шаблоны запросов, которые могут привести к превышению этого предела и сбою запроса

  • длинный список бинарных операторов, которые связаны друг с другом. Пример:
T 
| where Column == "value1" or 
        Column == "value2" or 
        .... or
        Column == "valueN"

В таком случае мы рекомендуем переписать запрос с использованием оператора in().

T 
| where Column in ("value1", "value2".... "valueN")
  • Запрос, в котором есть оператор объединения, который выполняет слишком широкий анализ схемы, особенно если по умолчанию объединение возвращает «внешнюю» схему объединения (это означает, что вывод будет включать все столбцы базовой таблицы).

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