🦁

Azure の API には throttling がある

2023/05/28に公開

Azure の API には throttling がある

Azure の API には throttling があり、ほとんどの環境では問題になることはないかもしれませんが、大規模な環境を扱う場合は考慮が必要です。
この記事ではその中で 2 種類の throttling について説明してみます。

1 つめの throttling - サブスクリプションとテナントの制限

docs としてはここら辺に記載があります。

https://learn.microsoft.com/azure/azure-resource-manager/management/request-limits-and-throttling

そして、この docs にも記載があるとおり、この制限自体は複数のアカウントを作成することで比較的簡単に超えることができます。

これらの制限は、要求を行うセキュリティ プリンシパル (ユーザーまたはアプリケーション) と、サブスクリプション ID またはテナント ID の範囲に設定されます。 複数のセキュリティ プリンシパルから要求が発信されると、サブスクリプションまたはテナント全体の制限は、1 時間あたり 12,000 件および 1,200 件を超えます。

2 つめの throttling - リソース プロバイダーの制限

こちらの制限は、複数のアカウントを作成しても超えることができないため、注意が必要です。
docs としてはこちらに記載があります。

https://learn.microsoft.com/troubleshoot/azure/virtual-machines/troubleshooting-throttling-errors

制限値を確認する方法はいくつかありますが、例えば Start-AzVM-Debug option を付けて実行する方法があります。
-Debug option を付けて実行することで、実際に送受信している HTTP request/response の内容が出力され、その中に含まれている HTTP header を見ることで確認できます。
throttling に関係ない部分を省いた、具体的な実行例を以下に示して説明してきます。
まず最初に、Start-AzVM を実行直後には HTTP Accepted (Status code としては 202) が返ってきます。

PS C:\Users\kasakemi\Downloads\bicep-templates> Start-AzVM -ResourceGroupName vwan-0508 -Name vm100 -Debug
<snip>
DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
POST

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vwan-0508/providers/Microsoft.Compute/virtualMachines/vm100/start?api-version=2022-08-01

Headers:
Accept-Language               : en-US
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
Accepted

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Location                      : https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&monitor=true&api-version=2022-08-01
Retry-After                   : 10
Azure-AsyncOperation          : https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01
Azure-AsyncNotification       : Enabled
x-ms-ratelimit-remaining-resource: Microsoft.Compute/UpdateVM3Min;239,Microsoft.Compute/UpdateVM30Min;1199
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : a22d78bd-71eb-4034-8d75-dde9eacdf965
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-writes: 1199
x-ms-correlation-request-id   : e8cabd22-3206-48d3-85f2-c4fdefda6c9d
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085048Z:e8cabd22-3206-48d3-85f2-c4fdefda6c9d
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:50:47 GMT

Body:

この HTTP response には Location header があり、次にこの URL に対して次にアクセスするかと思っていたのですが、次の request を見るに Location ではなく Azure-AsyncOperation という header に示される URL に対して次にアクセスするようです。

少し長いのでしまっておきます
DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Retry-After                   : 10
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14999,Microsoft.Compute/GetOperation30Min;29999
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 79040b18-f149-443c-a177-75d8818f095f
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11999
x-ms-correlation-request-id   : d8a0b72a-ddd5-420c-9ce5-eb24530f75a8
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085058Z:d8a0b72a-ddd5-420c-9ce5-eb24530f75a8
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:50:57 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "status": "InProgress",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Retry-After                   : 10
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14998,Microsoft.Compute/GetOperation30Min;29998
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 06b02361-425e-419b-add0-c74964f73664
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11998
x-ms-correlation-request-id   : 5f5ce5af-576d-485f-a5f0-42e29f15429d
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085109Z:5f5ce5af-576d-485f-a5f0-42e29f15429d
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:51:09 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "status": "InProgress",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Retry-After                   : 10
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14997,Microsoft.Compute/GetOperation30Min;29997
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 292ded68-4ec6-4ee8-87f1-6096dd14afd1
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11997
x-ms-correlation-request-id   : 98e8a428-57d8-4767-b26e-b0f8810939ca
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085119Z:98e8a428-57d8-4767-b26e-b0f8810939ca
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:51:19 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "status": "InProgress",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Retry-After                   : 10
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14996,Microsoft.Compute/GetOperation30Min;29996
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 12285284-aac5-4bf9-9046-25a2e956f01c
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11996
x-ms-correlation-request-id   : e8db35ec-eae2-4d76-883f-725344652a3f
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085129Z:e8db35ec-eae2-4d76-883f-725344652a3f
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:51:29 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "status": "InProgress",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Retry-After                   : 10
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14995,Microsoft.Compute/GetOperation30Min;29995
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 03ebc2d7-3b99-4621-9a48-b47e6cdb7247
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11995
x-ms-correlation-request-id   : ae7bd85c-72de-4c79-b54d-f039aa45e76d
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085140Z:ae7bd85c-72de-4c79-b54d-f039aa45e76d
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:51:39 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "status": "InProgress",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
Retry-After                   : 10
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14994,Microsoft.Compute/GetOperation30Min;29994
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 0bec75e7-6e81-4b72-8882-7fe043f60da1
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11994
x-ms-correlation-request-id   : 71ed521b-5941-4703-9362-d1258816c67b
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085150Z:71ed521b-5941-4703-9362-d1258816c67b
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:51:50 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "status": "InProgress",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14992,Microsoft.Compute/GetOperation30Min;29992
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 1fc339da-6c7d-4a73-8be3-f6cdb1f86eda
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11993
x-ms-correlation-request-id   : 53bc6a8f-f542-4bbb-979c-56da40393fcb
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085200Z:53bc6a8f-f542-4bbb-979c-56da40393fcb
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:52:00 GMT

Body:
{
  "startTime": "2023-05-26T17:50:48.3776345+09:00",
  "endTime": "2023-05-26T17:51:53.706798+09:00",
  "status": "Succeeded",
  "name": "a22d78bd-71eb-4034-8d75-dde9eacdf965"
}


DEBUG: ============================ HTTP REQUEST ============================

HTTP Method:
GET

Absolute Uri:
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Compute/locations/japaneast/operations/a22d78bd-71eb-4034-8d75-dde9eacdf965?p=f763a675-a1b3-434d-8101-6a755c087456&monitor=true&api-version=2022-08-01

Headers:
x-ms-client-request-id        : 14409f42-e97b-4c24-8365-47ca7540768f

Body:



DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
OK

Headers:
Cache-Control                 : no-cache
Pragma                        : no-cache
x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14991,Microsoft.Compute/GetOperation30Min;29991
Strict-Transport-Security     : max-age=31536000; includeSubDomains
x-ms-request-id               : 5fe3867b-106d-47a6-8dc2-32d214603325
Server                        : Microsoft-HTTPAPI/2.0,Microsoft-HTTPAPI/2.0
x-ms-ratelimit-remaining-subscription-reads: 11992
x-ms-correlation-request-id   : b17789a2-a39b-4c16-8b32-c458e6bb3427
x-ms-routing-request-id       : SOUTHEASTASIA:20230526T085201Z:b17789a2-a39b-4c16-8b32-c458e6bb3427
X-Content-Type-Options        : nosniff
Date                          : Fri, 26 May 2023 08:52:00 GMT

Body:




OperationId : a22d78bd-71eb-4034-8d75-dde9eacdf965
Status      : Succeeded
StartTime   : 2023/05/26 Fri 5:50:47 PM
EndTime     : 2023/05/26 Fri 5:52:01 PM
Error       :

動作としては、Azure-AsyncOperation に示された URL に対して GET request を送り、応答に含まれる JSON の Status が Succeeded になるまで繰り返し GET request を送っています。
Status が Succeeded になった後に、Location header に書かれていた URL にも念のためなのかアクセスしている様子です。
また、GET request の送信間隔は Retry-After header に書かれている値を使っており、10 が指定されていることから大体 10 秒間隔でアクセスしていることも確認できます。

そして、一番この記事で伝えたいのは x-ms-ratelimit-remaining-resource header の内容です。
この値は以下のように遷移しています。

  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14999,Microsoft.Compute/GetOperation30Min;29999
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14998,Microsoft.Compute/GetOperation30Min;29998
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14997,Microsoft.Compute/GetOperation30Min;29997
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14996,Microsoft.Compute/GetOperation30Min;29996
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14995,Microsoft.Compute/GetOperation30Min;29995
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14994,Microsoft.Compute/GetOperation30Min;29994
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14992,Microsoft.Compute/GetOperation30Min;29992
  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/GetOperation3Min;14991,Microsoft.Compute/GetOperation30Min;29991

Microsoft.Compute/GetOperation3Min の後ろに書かれている値が 1 ずつ減っており、Microsoft.Compute/GetOperation30Min の後ろに書かれている値についても同様です。
つまりこれが 3 分あたり、30 分あたりの API の実行回数制限となります。
制限を超えた場合には、Cosmos DB などでよく見る 429 Too Many Requests という HTTP response が返され、こちらも Retry-After header に書かれた値の秒数だけ待ってから再度リクエストを送る必要があります。

具体的に問題となりうるケース

この throttling がどのようなケースで問題になるかというと、Azure VM を一気に 1,000 台作成する、とか、起動させる、といったケースでは具体的にこれに引っかかることがあります。
実行例の最初の x-ms-ratelimit-remaining-resource は以下のようになっていました。

  • x-ms-ratelimit-remaining-resource: Microsoft.Compute/UpdateVM3Min;239,Microsoft.Compute/UpdateVM30Min;1199

つまり、3 分あたり 240 台程度しか VM を作成できない、もしくは、起動できない、ということになります。
この 240 という値は実際には環境によるため、それぞれの環境で確認いただければと思います。
また、Microsoft.Compute/GetOperation3Min は 15,000 程度、Microsoft.Compute/UpdateVM3Min は 240 程度、ということで、それぞれの API の重さというか、内部的な負荷の差に応じて制限値も異なっている様子がわかります。
ざっくり、読み取り系は緩く、書き込み系は厳しい、ということになります。

まとめ

1 つの subscription で Azure VM を 1,000 台扱うほどの大規模な環境においては、Azure の API 実行制限に引っかかることがあります。
特に、リソース プロバイダーの制限に関しては実質、回避方法がありません。
制限の確認方法をもとに、実際の運用においてどのように影響があるかを検討いただく一助となればと思います。

参考

  • Resource Manager の要求のスロットル

https://learn.microsoft.com/azure/azure-resource-manager/management/request-limits-and-throttling

  • API の調整エラーのトラブルシューティング

https://learn.microsoft.com/troubleshoot/azure/virtual-machines/troubleshooting-throttling-errors

Microsoft (有志)

Discussion