Поделиться через


Рекомендации по работе с регулируемыми запросами в Azure Resource Graph

При программной работе с данными из Azure Resource Graph важно учитывать, как ограничение ресурсов влияет на результаты запросов. Изменение способа запроса данных может помочь вам и вашей организации избежать проблем регулирования и поддерживать поток своевременных данных о ресурсах Azure.

В этой статье рассматриваются четыре области и шаблона, связанных с созданием запросов к Azure Resource Graph:

  • Общие сведения о регулировании заголовков.
  • Группирование запросов.
  • Ошеломляющие запросы.
  • Эффект разбиения на страницы.

Общие сведения о заголовках регулирования

Azure Resource Graph выделяет количественную квоту для каждого пользователя с учетом временного окна. Например, пользователь не может отправить более 15 запросов в течение 5 секунд, иначе применяется регулирование. Значение квоты определяется множеством факторов и может изменяться.

В каждый ответ на запрос Azure Resource Graph добавляет следующие два заголовка регулирования:

  • x-ms-user-quota-remaining (int): оставшаяся квота ресурсов для пользователя. Это значение соответствует количеству запросов.
  • x-ms-user-quota-resets-after (hh:mm:ss): длительность до сброса квоты пользователя.

Если субъект безопасности имеет доступ к более чем 10 000 подписок в области запроса клиента или группы управления, ответ ограничен первым 10 000 подписками, а x-ms-tenant-subscription-limit-hit заголовок возвращается как true.

Чтобы продемонстрировать работу этих заголовков, давайте рассмотрим ответ на запрос со следующими значениями заголовков: x-ms-user-quota-remaining: 10 и x-ms-user-quota-resets-after: 00:00:03.

  • В течение следующих 3 секунд можно отправлять не более 10 запросов без регулирования.
  • Через 3 секунды значения x-ms-user-quota-remaining и сбрасываются соответственно x-ms-user-quota-resets-after15.00:00:05

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

Группирование запросов

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

  • Пример плохо оптимизированного подхода.

    // NOT RECOMMENDED
    var header = /* your request header */
    var subscriptionIds = /* A big list of subscriptionIds */
    
    foreach (var subscriptionId in subscriptionIds)
    {
        var userQueryRequest = new QueryRequest(
            subscriptions: new[] { subscriptionId },
            query: "Resources | project name, type");
    
        var azureOperationResponse = await this.resourceGraphClient
            .ResourcesWithHttpMessagesAsync(userQueryRequest, header)
            .ConfigureAwait(false);
    
    // ...
    }
    
  • Пример оптимизированного подхода к группировке.

    // RECOMMENDED
    var header = /* your request header */
    var subscriptionIds = /* A big list of subscriptionIds */
    
    const int groupSize = 100;
    for (var i = 0; i <= subscriptionIds.Count / groupSize; ++i)
    {
        var currSubscriptionGroup = subscriptionIds.Skip(i * groupSize).Take(groupSize).ToList();
        var userQueryRequest = new QueryRequest(
            subscriptions: currSubscriptionGroup,
            query: "Resources | project name, type");
    
        var azureOperationResponse = await this.resourceGraphClient
            .ResourcesWithHttpMessagesAsync(userQueryRequest, header)
            .ConfigureAwait(false);
    
      // ...
    }
    
  • Пример оптимизированного подхода к группировке для получения нескольких ресурсов в одном запросе.

    Resources | where id in~ ({resourceIdGroup}) | project name, type
    
    // RECOMMENDED
    var header = /* your request header */
    var resourceIds = /* A big list of resourceIds */
    
    const int groupSize = 100;
    for (var i = 0; i <= resourceIds.Count / groupSize; ++i)
    {
        var resourceIdGroup = string.Join(",",
            resourceIds.Skip(i * groupSize).Take(groupSize).Select(id => string.Format("'{0}'", id)));
        var userQueryRequest = new QueryRequest(
            subscriptions: subscriptionList,
            query: $"Resources | where id in~ ({resourceIdGroup}) | project name, type");
    
        var azureOperationResponse = await this.resourceGraphClient
            .ResourcesWithHttpMessagesAsync(userQueryRequest, header)
            .ConfigureAwait(false);
    
      // ...
    }
    

Поочередная отправка запросов

С учетом того, как применяется регулирование, есть смысл отправлять запросы поочередно. Например, вместо отправки 60 запросов одновременно ошеломляйте запросы в четыре 5-секундные окна.

  • Расписание запросов без тегов.

    Число запросов шестьдесят 0 0 0
    Интервал времени (с) 0-5 5-10 10-15 15–20
  • Расписание ошеломляемых запросов.

    Число запросов 15 15 15 15
    Интервал времени (с) 0-5 5-10 10-15 15–20

Следующий код является примером уважения заголовков регулирования при запросе Azure Resource Graph.

while (/* Need to query more? */)
{
    var userQueryRequest = /* ... */
    // Send post request to Azure Resource Graph
    var azureOperationResponse = await this.resourceGraphClient
        .ResourcesWithHttpMessagesAsync(userQueryRequest, header)
        .ConfigureAwait(false);

    var responseHeaders = azureOperationResponse.response.Headers;
    int remainingQuota = /* read and parse x-ms-user-quota-remaining from responseHeaders */
    TimeSpan resetAfter = /* read and parse x-ms-user-quota-resets-after from responseHeaders */
    if (remainingQuota == 0)
    {
        // Need to wait until new quota is allocated
        await Task.Delay(resetAfter).ConfigureAwait(false);
    }
}

Параллельное выполнение запросов

Хотя мы рекомендуем чаще применять группирование, чем распараллеливание, в некоторых случаях группирование выполнить сложно. В таких случаях может потребоваться запросить Azure Resource Graph, отправив несколько запросов параллельно. В следующем примере показано, как выполнять откат на основе заголовков регулирования.

IEnumerable<IEnumerable<string>> queryGroup = /* Groups of queries  */
// Run groups in parallel.
await Task.WhenAll(queryGroup.Select(ExecuteQueries)).ConfigureAwait(false);

async Task ExecuteQueries(IEnumerable<string> queries)
{
    foreach (var query in queries)
    {
        var userQueryRequest = new QueryRequest(
            subscriptions: subscriptionList,
            query: query);
        // Send post request to Azure Resource Graph.
        var azureOperationResponse = await this.resourceGraphClient
            .ResourcesWithHttpMessagesAsync(userQueryRequest, header)
            .ConfigureAwait(false);

        var responseHeaders = azureOperationResponse.response.Headers;
        int remainingQuota = /* read and parse x-ms-user-quota-remaining from responseHeaders */
        TimeSpan resetAfter = /* read and parse x-ms-user-quota-resets-after from responseHeaders */
        if (remainingQuota == 0)
        {
            // Delay by a random period to avoid bursting when the quota is reset.
            var delay = (new Random()).Next(1, 5) * resetAfter;
            await Task.Delay(delay).ConfigureAwait(false);
        }
    }
}

Разбиение на страницы

Так как Azure Resource Graph возвращает не более 1000 записей в одном ответе запроса, может потребоваться разместить запросы на страницы, чтобы получить полный набор данных. Но некоторые клиенты Azure Resource Graph обрабатывают разбиение на страницы по-разному, чем другие.

При использовании пакета SDK ResourceGraph для поддержки разбиения на страницы нужно передавать в запросе маркер пропуска, полученный в ответе на предыдущий запрос. Такой механизм означает, что вам придется самостоятельно объединять результаты из всех вызовов, получающих страницы одного набора. В этом случае каждый отправляемый запрос с разбивкой на страницы принимает одну квоту запроса.

var results = new List<object>();
var queryRequest = new QueryRequest(
  subscriptions: new[] { mySubscriptionId },
  query: "Resources | project id, name, type");
var azureOperationResponse = await this.resourceGraphClient
  .ResourcesWithHttpMessagesAsync(queryRequest, header)
  .ConfigureAwait(false);
while (!string.IsNullOrEmpty(azureOperationResponse.Body.SkipToken))
{
  queryRequest.Options ??= new QueryRequestOptions();
  queryRequest.Options.SkipToken = azureOperationResponse.Body.SkipToken;
  var azureOperationResponse = await this.resourceGraphClient
      .ResourcesWithHttpMessagesAsync(queryRequest, header)
      .ConfigureAwait(false);
  results.Add(azureOperationResponse.Body.Data.Rows);

// Inspect throttling headers in query response and delay the next call if needed.
}

Различие между запросами регулирования для ARG и ARM

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

  • Регулирование API ARG: ограничения, применяемые Azure Resource Graph.
  • Регулирование ARM: ограничения, применяемые Azure Resource Manager.

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

Ниже приведен пример ошибки регулирования ARG :

{
    "error": {
        "code": "RateLimiting",
        "message": "Please provide below info when asking for support: timestamp = 2025-10-16T18:06:54.4721412Z, correlationId = a90921ec-4649-431a-9c92-7a4394a15883.",
        "details": [
            {
                "code": "RateLimiting",
                "message": "Client application has been throttled and should not attempt to repeat the request until an amount of time has elapsed. Please see https://aka.ms/resourcegraph-throttling for help."
            }
        ]
    }
}

С другой стороны, ниже приведен пример ошибки регулирования ARM :

Замечание

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

<value>
Number of 'read' requests for subscription '{1}' actor '{2}' exceeded. Please try again after '{3}' seconds after additional tokens are available. Refer to https://aka.ms/arm-throttling for additional information.
</value>

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

ARG GET/LIST API

ARG представляет альтернативный подход к существующим вызовам API уровня управления Azure GET и List, которые повышают масштабируемость и производительность, устраняя проблемы регулирования для клиентов Azure. Этот API в настоящее время поддерживается только для ресурсов в resources таблице и computeresources таблице.

API ARG GET/LIST предназначен для решения сценариев, в которых требуется поиск одного ресурса по идентификатору, или вы перечисляете ресурсы в той же области и в определенной области (подписка, группа ресурсов или родительский ресурс).

Рекомендуется использовать API ARG GET/LIST, если служба соответствует одной или нескольким из следующих категорий:

  • Высокий объем вызовов GET в одной области: Служба выдает большое количество запросов GET, предназначенных для ресурсов в одной подписке или группе ресурсов, без необходимости выполнять запросы между подписками, сложные фильтры или соединения.

  • Риск ограничения пропускной способности или конкуренции за квоты: Ваша служба создает большой объем запросов и может столкнуться с такими проблемами, как:

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

  • Вам требуется полный набор instanceView виртуальных машин и виртуальных машин VMSS в универсальном режиме, а также в режиме оркестрации Flex.

    Замечание

    API ARG GET/LIST не поддерживает состояние работоспособности виртуальных машин (VM и VMSS), а также статус запуска расширений в instanceView. Дополнительные сведения об ограничениях API ARG GET/LIST см. в известных ограничениях.

Если нужный ресурс находится в resources таблице или computeresources таблице, и он попадает в одну из указанных выше категорий, а затем используйте API ARG GET/LIST.

Все еще регулируется?

Если вы следовали рекомендациям этой статьи, пробовали решение API GET/LIST в Azure Resource Graph и ваши запросы в Azure Resource Graph по-прежнему ограничиваются, обратитесь к группе Azure Resource Graph. Команда поддерживает Azure Resource Graph, но не поддерживает регулирование Microsoft Graph.

Укажите эти сведения при обращении к группе Azure Resource Graph:

  • Подробности о вашем варианте использования и бизнес-обоснование для повышения предела регулирования.
  • К какому объему ресурсов у вас есть доступ? Сколько из них возвращаются из одного запроса?
  • Какие типы ресурсов вас интересуют?
  • Какой шаблон запросов вы используете? Данные о числе выполненных запросов в секунду и т. п.

Следующие шаги