分享方式:


Azure Resource Graph 中的節流要求指導方針

建立 Azure Resource Graph 資料的程式設計和頻繁使用時,應該考慮節流如何影響查詢結果。 變更要求資料的方式,可協助您和您的組織避免受到節流,並維護 Azure 資源的即時資料流量。

本文涵蓋了與在 Azure Resource Graph 中建立查詢相關的四個領域和模式:

  • 了解節流標頭。
  • 分組查詢。
  • 錯開查詢。
  • 分頁的效果。

了解節流標頭

Azure Resource Graph 會根據時間範圍,為每個使用者配置配額數字。 例如,使用者在每 5 秒的時間範圍內,最多可以傳送 15 個查詢而不會進行節流。 配額值是由許多因素所決定,而且可能會變更。

在每個查詢回應中,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: 10x-ms-user-quota-resets-after: 00:00:03 的查詢回應。

  • 在接下來的 3 秒內,最多可以提交 10 個查詢,而不會進行節流。
  • 在 3 秒內,x-ms-user-quota-remainingx-ms-user-quota-resets-after 的值會分別重設為 1500: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: "Resoures | 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 秒的間隔。

  • 非交錯查詢排程。

    查詢計數 60 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 在單一查詢回應中最多傳回 1,000 個項目,所以您可能需要將查詢分頁,以取得您想要的完整資料集。 但是,某些 Azure Resource Graph 的用戶端處理編頁的方式與其他用戶端不同。

使用 ResourceGraph SDK 時,您必須將先前查詢回應所傳回的跳過權杖傳遞至下一個編頁查詢,以處理編頁。 這種設計表示您需要從所有編頁呼叫中收集結果,並將其結合在一起。 在此情況下,您傳送的每個編頁查詢都會採用一個查詢配額。

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.
}

仍在進行節流?

如果您使用本文的建議,且 Azure Resource Graph 查詢仍在進行節流,請連絡 Azure Resource Graph 小組。 小組支援 Azure Resource Graph,但不支援 Microsoft Graph 節流

當您連絡 Azure Resource Graph 小組時,請提供下列詳細資料:

  • 您的特定使用案例和商務驅動程式需要更高的節流限制。
  • 您有多少資源可以存取? 從單一查詢傳回其中多少項目?
  • 您感興趣的資源類型為何?
  • 您的查詢模式是什麼? 每 Y 秒 X 個查詢,依此類推。

下一步