App Service で Automatic Scaling の動作確認

# はじめに

この記事では Azure App Service における、Automatic Scaling(自動スケーリング)の動作を確認します。
https://learn.microsoft.com/ja-jp/azure/app-service/manage-automatic-scaling?tabs=azure-portal

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/7e9952a7-1b3c-4b8b-9612-7eba05adec41.png)

名前が分かりにくいですが、従来からある Azure Monitor でのAutoScale(自動スケーリング)とは異なり、App Service 独自の仕組みとなります。
どういった条件でスケーリングが発生しうるのかなどを確認していきます。

# どういった仕組か

ドキュメントには以下の記述があります。

> **自動スケーリングはバックグラウンドでどのように機能していますか?**
自動的にスケーリングするように設定されたアプリケーションは継続的に監視され、少なくとも数秒に 1 回は作業者の正常性を評価します。 システムがアプリケーションの負荷増加を検出すると、正常性チェックの頻度が高くなります。 作業者の正常性状態が悪化し、ペースダウンが要求された場合は、追加のインスタンスが要求されます。 インスタンスが追加される速度は、個々のアプリケーションの負荷パターンと起動時間によって異なります。 起動時間が短く、断続的に負荷が発生するアプリケーションでは、数秒から 1 分ごとに 1 台の仮想マシンが追加されるのを確認できます。
> 
> 負荷が落ち着くと、プラットフォームでスケーリングの可能性を確認し始めます。 このプロセスは通常、負荷の増加が止まってから約 5 - 10 分後に開始します。 スケールイン中、インスタンスは最大で数秒から 1 分に 1 つの割合で削除されます。

> **AppServiceHTTPLogs に 404 状態を含む "/admin/host/ping" のようなログ エントリがあるのはなぜですか?**
App Service の自動スケーリングは、プラットフォーム固有の他の正常性チェック メカニズムとともに、/admin/host/ping エンドポイントを定期的にチェックします。 これらのチェックは特別に実装された機能です。

# 検証

## 事前準備

用意した環境は以下の通り

 - OS : Linux
 - SKU : P0v3
 - 最大バースト: 4

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/a5858103-97f1-4c27-83a9-f894c8a5d494.png)

まずは、前述 Doc に記載の `/admin/host/ping` へのリクエストの状態を確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/99cdf4a3-370c-4ce5-a774-8f88955c43c6.png)

はい。`/admin/host/ping` へのリクエストはありません。
その代わり？ 13 秒毎に UserAgent `ElasticScaleControllerExtension/2.0.29.0` からの `/` に対するリクエストがAutomatic Scalingを有効にしたタイミングから始まっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/d02630d1-976f-4c3d-8524-4717b9ec4e32.png)

また、同一 App Service Plan にデプロイされているほかの App Service に対しても当該のリクエストが行われていることが確認できます。

# 実験 1 `/` を遅くしてみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/b522add9-affa-44c5-818d-16b68071abc3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/23fcd9c6-b91d-4894-8278-f3ddda3178fd.png)

他にアクセスがないからか、単純に `ElasticScaleControllerExtension/2.0.29.0` からのリクエストの応答速度だけをもとにスケールするわけではなさそうです。

# 実験 2 リクエスト数を増やす

`/` の応答遅延をなくしてリクエスト数を増やしてみます。
ベースとなるのは以下の k6 スクリプト。単純に1秒おきに `/` にアクセスを繰り返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/c00c0286-d7b4-464f-9f01-bcaf774770d1.png)

## 負荷1
まずは 10 vus（秒間10Req/s 600req/min）

```bash
k6 run -u 0 -s 30s:10 -s 120s:10 -s 30s:0 ./test.js

     http_reqs......................: 1272   7.023404/s
     iteration_duration.............: avg=1.18s    min=1.15s    med=1.16s    max=1.96s    p(90)=1.21s    p(95)=1.24s

     iterations.....................: 1272   7.023404/s
     vus............................: 1      min=0      max=10
     vus_max........................: 10     min=10     max=10


running (3m01.1s), 00/10 VUs, 1272 complete and 0 interrupted iterations
default ✓ [======================================] 00/10 VUs  3m0s
```
結果、変化なし

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/33c82ca0-1b5a-4e06-9d4c-6e6a4cfa94f2.png)

## 負荷2

負荷1の10倍で試してみる 100 vus（秒間100Req/s 6000req/min）

```bash
k6 run -u 0 -s 30s:100 -s 120s:100 -s 30s:0 ./test.js

     http_reqs......................: 12778  70.56061/s
     iteration_duration.............: avg=1.17s    min=1.15s    med=1.16s    max=2.67s    p(90)=1.18s    p(95)=1.22s

     iterations.....................: 12778  70.56061/s
     vus............................: 1      min=1      max=100
     vus_max........................: 100    min=100    max=100


running (3m01.1s), 000/100 VUs, 12778 complete and 0 interrupted iterations
default ✓ [======================================] 000/100 VUs  3m0s
```
結果、変化なし

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/3b9bb7f8-1f3d-4696-b309-59d39eb378ca.png)


## 負荷3

負荷の期間を長くしてみる

```bash
k6 run -u 0 -s 30s:100 -s 300s:100 -s 30s:0 ./test.js

http_reqs......................: 28315  78.533468/s
     iteration_duration.............: avg=1.16s    min=1.15s    med=1.16s    max=2.17s    p(90)=1.17s    p(95)=1.18s

     iterations.....................: 28315  78.533468/s
     vus............................: 3      min=3       max=100
     vus_max........................: 100    min=100     max=100


running (6m00.5s), 000/100 VUs, 28315 complete and 0 interrupted iterations
default ✓ [======================================] 000/100 VUs  6m0s
```
結果、変化なし

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/ac12dae7-b311-417d-aa71-219c33ad4e4a.png)

これはリクエスト数が増えてもそもそも応答が早く返せているからなのか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/fd31e81b-0a99-45e7-be8d-19bc464598be.png)

## 負荷4

負荷1の100倍にしてみる  1000 vus（秒間1000Req/s 60000req/min）

```bash
k6 run -u 0 -s 30s:1000 -s 120s:1000 -s 30s:0 ./test.js

     http_reqs......................: 107087 592.268191/s
     iteration_duration.............: avg=1.4s     min=1.15s      med=1.16s    max=28.18s   p(90)=1.67s    p(95)=2.08s
     iterations.....................: 107087 592.268191/s
     vus............................: 1      min=1        max=1000
     vus_max........................: 1000   min=1000     max=1000


running (3m00.8s), 0000/1000 VUs, 107087 complete and 0 interrupted iterations
default ✓ [======================================] 0000/1000 VUs  3m0s
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/91984e47-68cd-4f6b-94a6-cf4f5b6ce52f.png)

閾値に設定した4までスケールアウトしたことが確認できた。
スケールアウトできないといった問題があるというわけではなさそうなので、今後パターンを変えて様子を探っていきます。