最近、Azure Functionsのお勉強をチマチマと始めました。色々と分からないことが多かったのでお勉強メモをまとめて記します。
どこまで続くかわからないお勉強メモ。今日は7回目です。今回はBlob Storage出力バインドを使った実装の続きです。前回はローカル環境で試しましたが、今回は実際のAzure環境にデプロイしました。過去のものは以下を参照。
- Azure Functionsのお勉強メモ(1)TypeScriptでチュートリアルを実施する - miyohide's blog
- Azure Functionsのお勉強メモ(2)Spring Cloud FunctionでHTTP Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(3)Spring Cloud FunctionでTimer Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(4)RubyでHTTP Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(5)カスタムハンドラーを使ってRubyでTimer Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(6)Blob Storage出力バインドを使ってBlobにファイルを出力する - miyohide's blog
Azure環境へのデプロイ
前回作成したアプリケーションをAzure環境で動かすためには、アプリケーション以外に以下のものをデプロイ・設定する必要があります。事前に
gradlew azureFunctionsDeploy
でアプリケーションをデプロイした後に以下の設定を行います。
- Azure Storageアカウント
- Azure Functionsに環境変数
OutputStorage
を設定する
これらの設定はポータル画面から操作しても良いのですが、今回はAzure CLI(Bash)を使って操作してみます。
まずはAzure Storageアカウントの作成。
az storage account create --name 名前 --resource-group リソースグループ名 --location japaneast --sku Standard_LRS --encryption-services blob
Azure Storageアカウントに対する接続文字列を取得します。
az storage account show-connection-string -g リソースグループ名 -n 名前
接続文字列は長いので、変数に入れておきます。
connect_str=$(az storage account show-connection-string -g リソースグループ名 -n 名前 -o tsv)
環境変数を設定します。
az functionapp config appsettings set --name アプリ名 --resource-group リソースグループ名 --settings "OutputStorage=$connect_str"
ここまで設定しておくとアプリがAzure上で動くことを確認できました。
負荷をかけてみる
ブラウザで数回アクセスしても特に不具合は発生しなかったので、abコマンドでちょっと負荷をかけてみました。
ab -n 1000 -c 10 アプリのURL
すると、何件か例外を吐いている様子が確認できました。下の画像にあるException Rateが跳ね上がっている様子が確認できます。
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台で実行されていました。
スケールアウトの条件を変更することはできず、またその条件も示されていませんでした。ただ最大スケールアウトの台数を制限することはAzure Portalから設定することができました。
この画面でスケールアウト制限の上限を1にしておくと良さそうです。
また、合わせてアプリケーションのhost.jsonにおいてHTTPトリガーのmaxConcurrentRequests
を1
に設定する必要があります。
確認
再度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は下に張り付いたままでした。
Application Insightsでインスタンス数の経緯をcloud_RoleInstanceを使って見てましたが、再実行時は1のままでした。
ソースコード
ここまでのソースコードは以下に載せています。