初めまして。ソフトウェア開発部の辻です。 Nginxと、Play2.0でのAkkaのパフォーマンスチューニングを行いました!
パフォーマンスチューニングを行った経緯
弊社のPlay2.0+Nginxを使ったWebアプリで、CPU使用率が10%に満たないにも関わらず、Akkaのタイムアウト(akka.pattern.AskTimeoutException)が頻発していました。 Play2.0では、並列処理行うために内部でAkka Actorを使用しており、このAkkaのタイムアウトは、このAkka Actorが長時間ブロックされたときに発生します。
そこで、テスト環境にてAkkaのタイムアウト設定を変更してみました。 タイムアウト設定はconf/application.confの以下の部分を編集することで変更できます。
play.akka.actor.retrieveBodyParserTimeout = 5 second
タイムアウト設定を5秒にして負荷をかけてみたところCPU使用率が上がりましたが、2秒にして負荷をかけなおすとAkkaのタイムアウトが発生するようになりCPU使用率が下がりました。 このことから、タイムアウト設定を延ばせば、CPUに負荷をかけタイムアウトを減らすことができると分かりました。
ところが、弊社Webアプリは5秒以内にレスポンスを返さないといけないという制約があり、タイムアウト設定をこれ以上延ばすことはできません。 タイムアウト設定は延ばさずに、アプリケーションのレスポンス速度をあげる(レスポンス速度を上げるためにCPUを使うようにする)ために以下のような負荷試験を実施し、チューニングを行いました。
テスト環境
- Amazon EC2 m1.large (4コア)
- Play 2.0.2
- Nginx 1.2.0
- Akkaのタイムアウト設定は4秒とする
負荷設定
JMeterで、アクセスが多いと思われるページに以下の設定で負荷をかけました。 チューニング前の状態でAskTimeoutExceptionが頻発するように調整しました。
アクセス先 | 秒間アクセス数 | ループ回数 |
---|---|---|
ページA | 30 | 100 |
ページB | 30 | 100 |
ページC | 20 | 100 |
上記の負荷をかけた時のタイムアウト回数(AskTimeoutException発生回数)をカウントし、このアクセスに対してレスポンスを返しきるまでの所要時間を計測します。
Playの設定
conf/application.confに以下の設定を記述することで、Play内部のAkkaの設定を上書きできます。 今回設定したのは以下の3つです。
項目名 | 説明 | デフォルトの値 |
---|---|---|
nr-of-instances | ルータに登録するActorの数。 | 24 |
parallelism-factor | CPU数*この値=Akkaで使用されるスレッド数 | 1.0 |
parallelism-max | Akkaで使用される最大スレッド数 | 24 |
以下のページを参考にしました。
Scala/Akka Actor
【意訳】データベース駆動アプリのための、Play2最適化について
Nginxの設定
conf/nginx.confに以下の設定をします。
項目名 | 説明 | デフォルトの値 |
---|---|---|
worker_processes | Nginxのworkerプロセス数。CPU数に合わせる。 | 1 |
以下のページを参考にしました。
hnginx設定 | 楽しく情報処理技術者試験
nginx連載3回目: nginxの設定、その1
チューニング
- チューニング前の設定のまま
- Nginxのworker_processesをCPU数に合わせる
- Akkaのスレッド数を増やす (上記までの参考ページから、とりあえず400がmaxになるように設定してみました。)
- 2,3両方を適用する
という順で設定してみました。
| | Play | Nginx | 計測結果 | 結果 |
| - | ------------------------------------------------------------------------ | ------------------ | ------------------------------------- | ----------------------------------------- |
| 1 | nr-of-instances = 24
parallelism-factor = 1.0
parallelism-max = 48 | worker_processes 1 | AskTimeoutException:490回
所要時間:3分12秒 | |
| 2 | nr-of-instances = 24
parallelism-factor = 1.0
parallelism-max = 48 | worker_processes 4 | AskTimeoutException:454回
所要時間:3分17秒 | タイムアウトの発生回数が
減っていることから、
アプリの処理速度が上がった |
| 3 | nr-of-instances = 400
parallelism-factor = 100
parallelism-max = 400 | worker_processes 1 | AskTimeoutException:7回
所要時間:3分9秒 | タイムアウトの発生回数が
減っていることから、
アプリの処理速度が上がった |
| 4 | nr-of-instances = 400
parallelism-factor = 100
parallelism-max = 400 | worker_processes 4 | AskTimeoutException:1回
所要時間:3分8秒 | タイムアウトの発生回数が
減っていることから、
アプリの処理速度が上がった |
所要時間が延びることなく、AskTimeoutExceptionの発生回数が減少しているので、 Nginxのworker_processesをCPU数に合わせ、Akkaのスレッド数を増やすことでアプリの処理速度を上げることができると分かりました。
まとめ
- Akkaのタイムアウト時間を延ばせばCPUに負荷がかかります。弊社のWebアプリの制約上タイムアウト時間を短く設定していたので、CPUに負荷がかかる前にタイムアウトになっていました。
- Nginxのworkerを増やし、Playのスレッド数を増やすことでタイムアウトになる前にCPUに負荷をかけてアプリの処理速度をあげることができました。
- Akkaのスレッド数はまだこの値が適切かどうかはわかりません。今後のアクセス状況やタイムアウトの発生頻度などを見て再度チューニングする必要があります。
以上です。