しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure WebJobs のスケーリング方法を考える

効率よく WebJob を使って大量の処理を実行させたいと思ったので、スケーリングさせる方法を簡単に考えました。本当は Service Fabric が向いている気がしますが、プレビューなので WebJob を使います。

Web Apps をスケーリングさせる

App Service Plan のインスタンスサイズを変えたり、インスタンス数を 10 まで拡大させることで、1 つの WebJob が実行可能な処理数を増やすことができます。当たり前の話ですが。

Azure ビデオ | Microsoft Azure

とはいえ、1 つの WebJob のためにインスタンス数を 10 まで拡大というのも、リソースと課金の無駄使いという感じがするので、もっと高密度に WebJob を載せていく必要があるのではないかと思います。

1 サイトに複数の WebJob をデプロイする

単純に 1 サイトにデプロイした 1 つの WebJob がリソースを使いきれているのかというと、実際にはスカスカということが多いかと思います。なので、同じ WebJob を複数デプロイする方法を考えました。

仕組みとしては簡単で、デプロイスクリプトを使って WebJob をコピーして増やします。

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

echo Handling .NET Console Application deployment.

:: 1. Restore NuGet packages
IF /I "BatchWorkerJob.sln" NEQ "" (
  call :ExecuteCmd nuget restore "%DEPLOYMENT_SOURCE%\BatchWorkerJob.sln"
  IF !ERRORLEVEL! NEQ 0 goto error
)

:: 2. Build to the temporary path
call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\BatchWorkerJob\BatchWorkerJob.csproj" /nologo /verbosity:m /t:Build /p:Configuration=Release;OutputPath="%DEPLOYMENT_TEMP%\app_data\jobs\continuous\deployedJob";UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\.\\" %SCM_BUILD_ARGS%
IF !ERRORLEVEL! NEQ 0 goto error

:: 3. Copy WebJobs
FOR /L %%i in (1, 1, 20) do xcopy "%DEPLOYMENT_TEMP%\app_data\jobs\continuous\deployedJob" "%DEPLOYMENT_TEMP%\app_data\jobs\continuous\batchworker-%%i" /D /S /R /Y /I /K /Q
rd /s /q "%DEPLOYMENT_TEMP%\app_data\jobs\continuous\deployedJob"

:: 4. KuduSync
call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
IF !ERRORLEVEL! NEQ 0 goto error

このデプロイスクリプトを使って Web Apps にデプロイすると、指定した数だけ追加されます。

実際にデプロイする数は、App Service Plan のインスタンスサイズで適切に調整する必要があります。

WebJob SDK を使って並列動作させる

Azure WebJob SDK を使っている場合には、デフォルトで並列実行を行ってくれるようになっています。

並列実行

異なるキューをリッスンする複数の関数を使用している場合、複数のメッセージを同時に受信したとき、SDK では並行してそれらを呼び出します。

1 つのキューに対して複数のメッセージが受信される場合も同様に処理されます。既定では、SDK は一度にキュー メッセージ 16 個のバッチを取得し、それらを並列処理する関数を実行します。バッチ サイズの設定は変更可能です。処理中のメッセージの数がバッチ サイズの半分まで減少すると、SDK は別のバッチを取得し、そのメッセージの処理を開始します。そのため、1 つの関数につき同時に処理されるメッセージの最大数は、バッチ サイズの 1.5 倍です。この制限は、QueueTrigger 属性を持つ各関数に個別に適用されます。

Home · Azure/azure-webjobs-sdk Wiki · GitHub

1 つの WebJob で並列実行してくれるので、とても簡単に使えます。内部ではスレッドが使われるので、プロセスを起動させるときのコストがかからないのがメリットです。

まとめ

最後に簡単にこれまでの内容をまとめておきます。といっても適切に組み合わせましょうという感じです。

  • WebJob SDK を使っている場合には BatchSize を適切に設定して並列実行させる
  • 使っていない場合は WebJob を複数デプロイする
  • それでもリソースが足りない場合に App Service Plan をスケーリングさせる

個人的には WebJob SDK が提供する並列実行と、WebJob の複数デプロイを組み合わせようかなと思っています。1 つのプロセスだけで実行していると、不具合があった場合に全体が落ちる可能性があるので。