Azure Resource Graph のスロットルされた要求に関するガイダンスGuidance for throttled requests in Azure Resource Graph

Azure Resource Graph データのプログラムによる頻繁な使用を作成するときは、スロットリングがクエリの結果にどのように影響するかを検討する必要があります。When creating programmatic and frequent use of Azure Resource Graph data, consideration should be made for how throttling impacts the results of the queries. データの要求方法を変更することで、ユーザーと組織でのスロットルが回避され、Azure リソースに関するタイムリーなデータのフローを維持することができます。Changing the way data is requested can help you and your organization avoid being throttled and maintain the flow of timely data about your Azure resources.

この記事では、Azure Resource Graph でのクエリの作成に関連する 4 つの領域とパターンについて説明します。This article covers four areas and patterns related to the creation of queries in Azure Resource Graph:

  • スロットリング ヘッダーを理解するUnderstand throttling headers
  • クエリのグループ化Grouping queries
  • クエリの時間差処理Staggering queries
  • 改ページ位置の自動修正の影響The impact of pagination

スロットリング ヘッダーを理解するUnderstand throttling headers

Azure Resource Graph では、タイム ウィンドウに基づいて各ユーザーにクォータ数が割り当てられます。Azure Resource Graph allocates a quota number for each user based on a time window. たとえば、ユーザーは、5 秒間のウィンドウごとに最大 15 のクエリをスロットルなしで送信できます。For example, a user can send at most 15 queries within every 5-second window without being throttled. クォータ値は多数の要因によって決定され、変更される可能性があります。The quota value is determined by many factors and is subject to change.

すべてのクエリ応答で、Azure Resource Graph によって、2 つのスロットリング ヘッダーが追加されます。In every query response, Azure Resource Graph adds two throttling headers:

  • x-ms-user-quota-remaining (int):ユーザーの残りリソース クォータ。x-ms-user-quota-remaining (int): The remaining resource quota for the user. この値はクエリ カウントにマップされます。This value maps to query count.
  • x-ms-user-quota-resets-after (hh:mm:ss):ユーザーのクォータ消費量がリセットされるまでの期間。x-ms-user-quota-resets-after (hh:mm:ss): The time duration until a user's quota consumption is reset.

ヘッダーの働きを示すために、ヘッダーと、値 x-ms-user-quota-remaining: 10x-ms-user-quota-resets-after: 00:00:03 が含まれているクエリ応答を検討してみましょう。To illustrate how the headers work, let's look at a query response that has the header and values of x-ms-user-quota-remaining: 10 and x-ms-user-quota-resets-after: 00:00:03.

  • 次の 3 秒以内に、最大 10 個のクエリをスロットルなしで送信できます。Within the next 3 seconds, at most 10 queries may be submitted without being throttled.
  • 3 秒後に、x-ms-user-quota-remainingx-ms-user-quota-resets-after の値が、それぞれ 1500:00:05 にリセットされます。In 3 seconds, the values of x-ms-user-quota-remaining and x-ms-user-quota-resets-after will be reset to 15 and 00:00:05 respectively.

これらのヘッダーを使用したクエリ要求の "バックオフ" の例については、「並行で処理されるクエリ」を参照してください。To see an example of using the headers to backoff on query requests, see the sample in Query in Parallel.

クエリのグループ化Grouping queries

サブスクリプション、リソース グループ、または個々のリソースによるクエリのグループ化は、クエリの並列化よりも効率的です。Grouping queries by the subscription, resource group, or individual resource is more efficient than parallelizing queries. 大規模なクエリのクォータ コストは、多くの場合、多数の小規模なターゲット クエリのクォータ コストよりも小さくなります。The quota cost of a larger query is often less than the quota cost of many small and targeted queries. グループ サイズを 300 未満にすることが推奨されています。The group size is recommended to be less than 300.

  • 最適化が不足しているアプローチの例Example of a poorly optimized approach

    // 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: "Resoures | project name, type");
    
        var azureOperationResponse = await this.resourceGraphClient
            .ResourcesWithHttpMessagesAsync(userQueryRequest, header)
            .ConfigureAwait(false);
    
    // ...
    }
    
  • 最適化されたグループ化アプローチの例 1Example #1 of an optimized grouping approach

    // 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);
    
      // ...
    }
    
  • 1 つのクエリで複数のリソースを取得するための最適化されたグループ化アプローチの例 2Example #2 of an optimized grouping approach for getting multiple resources in one query

    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);
    
      // ...
    }
    

クエリの時間差処理Staggering queries

スロットリングの実行方法のため、クエリを時間差で実行することをお勧めします。Because of the way throttling is enforced, we recommend queries to be staggered. つまり、60 のクエリを同時に送信する代わりに、クエリを 4 つの 5 秒間のウィンドウで時間差で送信します。That is, instead of sending 60 queries at the same time, stagger the queries into four 5-second windows:

  • 時間差を使用しないクエリのスケジュールNon-staggered query schedule

    クエリ数Query Count 6060 00 00 00
    期間 (秒)Time Interval (sec) 0-50-5 5-105-10 10-1510-15 15-2015-20
  • 時間差を使用するクエリのスケジュールStaggered query schedule

    クエリ数Query Count 1515 1515 1515 1515
    期間 (秒)Time Interval (sec) 0-50-5 5-105-10 10-1510-15 15-2015-20

次に示すのは、Azure Resource Graph をクエリするときのスロットリング ヘッダーに関する例です。Below is an example of respecting throttling headers when querying 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);
    }
}

並行で処理されるクエリQuery in Parallel

並列処理よりもグループ化が推奨されますが、クエリを簡単にグループ化できない場合があります。Even though grouping is recommended over parallelization, there are times where queries can't be easily grouped. このような場合は、複数のクエリを並列で送信することによって、Azure Resource Graph をクエリします。In these cases, you may want to query Azure Resource Graph by sending multiple queries in a parallel fashion. このようなシナリオで、スロットリング ヘッダーに基づいて "バックオフ" する方法の例を次に示します。Below is an example of how to backoff based on throttling headers in such scenarios:

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);
        }
    }
}

改ページ位置の自動修正Pagination

Azure Resource Graph では、単一のクエリ応答で最大 1,000 のエントリが返されるため、探している完全なデータセットを取得するには、クエリの改ページ調整が必要な場合があります。Since Azure Resource Graph returns at most 1000 entries in a single query response, you may need to paginate your queries to get the complete dataset you're looking for. ただし、一部の Azure Resource Graph クライアントでは、他とは異なる改ページ位置の自動修正処理が行われます。However, some Azure Resource Graph clients handle pagination differently than others.

  • C# SDKC# SDK

    ResourceGraph SDK を使用する場合は、前のクエリ応答から返されるスキップ トークンを次の改ページ調整されるクエリに渡すことで、改ページ位置の自動修正を処理する必要があります。When using ResourceGraph SDK, you need to handle pagination by passing the skip token being returned from the previous query response to the next paginated query. この設計が意味しているのは、すべての改ページ調整された呼び出しの結果を収集し、それらを最後に結合する必要があることです。This design means you need to collect results from all paginated calls and combine them together at the end. この場合、改ページ調整された各クエリの送信によって、1 つのクエリ クォータが消費されます。In this case, each paginated query you send takes one query quota:

    var results = new List<object>();
    var queryRequest = new QueryRequest(
        subscriptions: new[] { mySubscriptionId },
        query: "Resources | project id, name, type | top 5000");
    var azureOperationResponse = await this.resourceGraphClient
        .ResourcesWithHttpMessagesAsync(queryRequest, header)
        .ConfigureAwait(false);
    while (!string.Empty(azureOperationResponse.Body.SkipToken))
    {
        queryRequest.SkipToken = azureOperationResponse.Body.SkipToken;
        // Each post call to ResourceGraph consumes one query quota
        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.
    }
    
  • Azure CLI/Azure PowerShellAzure CLI / Azure PowerShell

    Azure CLI または Azure PowerShell の使用では、Azure Resource Graph に対するクエリは、自動的に最大 5,000 のエントリをフェッチするように改ページ調整されます。When using either Azure CLI or Azure PowerShell, queries to Azure Resource Graph are automatically paginated to fetch at most 5000 entries. クエリの結果では、すべての改ページ調整された呼び出しが結合されたエントリの一覧が返されます。The query results return a combined list of entries from all paginated calls. この場合、クエリの結果に含まれるエントリ数によっては、単一の改ページ調整されたクエリで、複数のクエリのクォータが消費される可能性があります。In this case, depending on the number of entries in the query result, a single paginated query may consume more than one query quota. たとえば、次の例では、クエリの 1 回の実行で、最大 5 のクエリのクォータが消費される可能性があります。For example, in the example below, a single run of the query may consume up to five query quota:

    az graph query -q 'Resources | project id, name, type' --first 5000
    
    Search-AzGraph -Query 'Resources | project id, name, type' -First 5000
    

スロットルが解消されない場合Still get throttled?

上記の推奨事項を実行してもスロットルされる場合は、チームにお問い合わせください (resourcegraphsupport@microsoft.com)。If you're getting throttled after exercising the above recommendations, contact the team at resourcegraphsupport@microsoft.com.

次の詳細情報を提供してください。Provide these details:

  • スロットリング制限が高い具体的なユース ケースとビジネス推進ニーズ。Your specific use-case and business driver needs for a higher throttling limit.
  • アクセスするリソースの数。How many resources do you have access to? 単一のクエリで返されるエントリの数。How many of the are returned from a single query?
  • 関心のあるリソースの種類。What types of resources are you interested in?
  • お使いのクエリ パターン。What's your query pattern? Y 秒あたり X 回のクエリなど。X queries per Y seconds, and so on.

次のステップNext steps