Orientação para solicitações limitadas no Azure Resource Graph
Ao criar o uso programático e frequente de dados do Azure Resource Graph, deve-se considerar como a limitação afeta os resultados das consultas. Alterar a maneira como os dados são solicitados pode ajudar você e sua organização a evitar ser limitado e manter o fluxo de dados oportunos sobre seus recursos do Azure.
Este artigo aborda quatro áreas e padrões relacionados à criação de consultas no Azure Resource Graph:
- Entenda os cabeçalhos de limitação.
- Agrupamento de consultas.
- Consultas escalonadas.
- O efeito da paginação.
Compreender os cabeçalhos de limitação
O Azure Resource Graph aloca um número de quota para cada utilizador com base numa janela temporal. Por exemplo, um usuário pode enviar no máximo 15 consultas a cada janela de 5 segundos sem ser limitado. O valor da quota é determinado por muitos fatores e está sujeito a alterações.
Em cada resposta de consulta, o Azure Resource Graph adiciona dois cabeçalhos de limitação:
x-ms-user-quota-remaining
(int): A cota de recursos restante para o usuário. Esse valor é mapeado para a contagem de consultas.x-ms-user-quota-resets-after
(hh:mm:ss): A duração do tempo até que o consumo de cota de um usuário seja redefinido.
Quando uma entidade de segurança tem acesso a mais de 10.000 assinaturas dentro do escopo de consulta do locatário ou do grupo de gerenciamento, a resposta é limitada às primeiras 10.000 assinaturas e o x-ms-tenant-subscription-limit-hit
cabeçalho é retornado como true
.
Para ilustrar como os cabeçalhos funcionam, vamos examinar uma resposta de consulta que tenha o cabeçalho e os valores de x-ms-user-quota-remaining: 10
e x-ms-user-quota-resets-after: 00:00:03
.
- Nos próximos 3 segundos, no máximo 10 consultas podem ser enviadas sem serem limitadas.
- Em 3 segundos, os valores de
x-ms-user-quota-remaining
ex-ms-user-quota-resets-after
são redefinidos para15
e00:00:05
respectivamente.
Para ver um exemplo de como usar os cabeçalhos para recuar em solicitações de consulta, consulte o exemplo em Consulta em paralelo.
Agrupamento de consultas
Agrupar consultas pela assinatura, grupo de recursos ou recurso individual é mais eficiente do que paralelizar consultas. O custo de quota de uma consulta maior é muitas vezes inferior ao custo de quota de inúmeras consultas pequenas e direcionadas. Recomenda-se que o tamanho do grupo seja inferior a 300.
Exemplo de uma abordagem mal otimizada.
// 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); // ... }
Exemplo de uma abordagem de agrupamento otimizada.
// 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); // ... }
Exemplo de uma abordagem de agrupamento otimizada para obter vários recursos em uma consulta.
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); // ... }
Escalonamento de consultas
Devido à forma como a limitação é aplicada, recomendamos que as consultas sejam escalonadas. Por exemplo, em vez de enviar 60 consultas ao mesmo tempo, escalone as consultas em quatro janelas de 5 segundos.
Agenda de consulta não escalonada.
Contagem de consultas 60 0 0 0 Intervalo de tempo (seg) 0-5 5-10 10-15 15-20 Agenda de consulta escalonada.
Contagem de consultas 15 15 15 15 Intervalo de tempo (seg) 0-5 5-10 10-15 15-20
O código a seguir é um exemplo de respeito à limitação de cabeçalhos ao consultar o 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);
}
}
Consulta em paralelo
Embora o agrupamento seja recomendado em vez da paralelização, há momentos em que as consultas não podem ser facilmente agrupadas. Nesses casos, talvez você queira consultar o Gráfico de Recursos do Azure enviando várias consultas de forma paralela. O exemplo a seguir mostra como recuar com base em cabeçalhos de limitação.
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);
}
}
}
Paginação
Como o Azure Resource Graph retorna um máximo de 1.000 entradas em uma única resposta de consulta, talvez seja necessário paginar suas consultas para obter o conjunto de dados completo desejado. Mas alguns clientes do Azure Resource Graph lidam com a paginação de forma diferente de outros.
Ao usar o SDK do ResourceGraph, você precisa manipular a paginação passando o token de pulo que está sendo retornado da resposta de consulta anterior para a próxima consulta paginada. Esse design significa que você precisa coletar resultados de todas as chamadas paginadas e combiná-los no final. Nesse caso, cada consulta paginada enviada leva uma cota de consulta.
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.
}
Ainda está sendo estrangulado?
Se você usou as recomendações deste artigo e suas consultas do Azure Resource Graph ainda estão sendo limitadas, entre em contato com a equipe do Azure Resource Graph. A equipa suporta o Azure Resource Graph, mas não suporta a limitação do Microsoft Graph.
Forneça estes detalhes ao entrar em contato com a equipe do Azure Resource Graph:
- Seu caso de uso específico e driver de negócios precisa de um limite de limitação mais alto.
- A quantos recursos tem acesso? Quantos deles são retornados de uma única consulta?
- Em que tipos de recursos está interessado?
- Qual é o seu padrão de consulta? X consultas por Y segundos, e assim por diante.
Próximos passos
- Veja o idioma em uso nas consultas do Starter.
- Consulte Utilizações avançadas em Consultas avançadas.
- Saiba mais sobre como explorar recursos.