Azure Functionsのお勉強メモ(7)Blob Storage出力バインドを使ってBlobにファイルを出力する その2

最近、Azure Functionsのお勉強をチマチマと始めました。色々と分からないことが多かったのでお勉強メモをまとめて記します。

どこまで続くかわからないお勉強メモ。今日は7回目です。今回はBlob Storage出力バインドを使った実装の続きです。前回はローカル環境で試しましたが、今回は実際のAzure環境にデプロイしました。過去のものは以下を参照。

Azure環境へのデプロイ

前回作成したアプリケーションをAzure環境で動かすためには、アプリケーション以外に以下のものをデプロイ・設定する必要があります。事前に

gradlew azureFunctionsDeploy

でアプリケーションをデプロイした後に以下の設定を行います。

  • Azure Storageアカウント
  • Azure Functionsに環境変数OutputStorageを設定する

これらの設定はポータル画面から操作しても良いのですが、今回はAzure CLIBash)を使って操作してみます。

まずはAzure Storageアカウントの作成。

az storage account create --name 名前 --resource-group リソースグループ名 --location japaneast --sku Standard_LRS --encryption-services blob

docs.microsoft.com

Azure Storageアカウントに対する接続文字列を取得します。

az storage account show-connection-string -g リソースグループ名 -n 名前

docs.microsoft.com

接続文字列は長いので、変数に入れておきます。

connect_str=$(az storage account show-connection-string -g リソースグループ名 -n 名前 -o tsv)

docs.microsoft.com

環境変数を設定します。

az functionapp config appsettings set --name アプリ名 --resource-group リソースグループ名 --settings "OutputStorage=$connect_str"

docs.microsoft.com

ここまで設定しておくとアプリがAzure上で動くことを確認できました。

負荷をかけてみる

ブラウザで数回アクセスしても特に不具合は発生しなかったので、abコマンドでちょっと負荷をかけてみました。

ab -n 1000 -c 10 アプリのURL

すると、何件か例外を吐いている様子が確認できました。下の画像にあるException Rateが跳ね上がっている様子が確認できます。

f:id:miyohide:20210425165746p:plain

abコマンドのログでもFailed requestsが152と出力されていました。

(省略)
Concurrency Level:      10
Time taken for tests:   61.818 seconds
Complete requests:      1000
Failed requests:        152
   (Connect: 0, Receive: 0, Length: 152, Exceptions: 0)
Non-2xx responses:      152
(中略)
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       34  101 115.4     87    2332
Processing:    99  432 1265.4    220   21840
Waiting:       98  430 1265.4    219   21840
Total:        153  532 1267.4    319   21879

Application InsightsのExceptionテーブルを見ると

The specified block list is invalid.

というメッセージを大量に目にしました。

確実なことは言えませんが、アプリは同時に同じBlobに対して書き込み処理を行なっていることが原因にありそうです。そこで以下の対応を行ってみます。

対策

手っ取り早い対策は、同時に実行する数を1つにすることです。以下のドキュメントにあるようにAzure Functionsの従量課金プランでは最大200インスタンスまで自動でスケールアウトされるようです。実際、上の画像でもサーバーの台数は5台で実行されていました。

docs.microsoft.com

スケールアウトの条件を変更することはできず、またその条件も示されていませんでした。ただ最大スケールアウトの台数を制限することはAzure Portalから設定することができました。

f:id:miyohide:20210425171622p:plain

この画面でスケールアウト制限の上限を1にしておくと良さそうです。

また、合わせてアプリケーションのhost.jsonにおいてHTTPトリガーのmaxConcurrentRequests1に設定する必要があります。

docs.microsoft.com

確認

再度abコマンドで実行してみます。以下のようにFailed requestsは0でした。

(省略)
Concurrency Level:      10
Time taken for tests:   98.539 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      240000 bytes
HTML transferred:       33000 bytes
Requests per second:    10.15 [#/sec] (mean)
Time per request:       985.393 [ms] (mean)
Time per request:       98.539 [ms] (mean, across all concurrent requests)
Transfer rate:          2.38 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       31   74  70.4     47    1098
Processing:   305  903  97.4    892    1574
Waiting:      305  903  97.4    891    1574
Total:        439  977 113.1    948    2038

Application InsightsのライブメトリックスでもException Rateは下に張り付いたままでした。

f:id:miyohide:20210425173305p:plain

Application Insightsでインスタンス数の経緯をcloud_RoleInstanceを使って見てましたが、再実行時は1のままでした。

f:id:miyohide:20210425173603p:plain

ソースコード

ここまでのソースコードは以下に載せています。

github.com