概要
Nginx, Puma, Rails, MySQLのチューニングを行ったときの知見を載せておきます。
ただし、チューニングは色々な要素に依存するため、最終的には自分たちの作っているアプリケーションにあった値を見つけてください。
以下の図のような動きを内部的にしています。では早速、各サービスの設定項目を詳しく見ていきましょう。
Nginx
worker数
今回自分はNginxがボトルネックにはならなかったので、Nginxの知見はあまり習得していないですが、色々な人のブログを見ていると auto
にしていることが多そうなので、特に理由がない場合以外は auto
でいいかと思います。
worker_processes auto;
Puma
worker数
workerはCPUのコア数に依存する物理スレッドを示しています。ここで大事なのは、worker数を サーバーのCPUコア数より大きくはしないことです 。
Pumaのworker数は、次のthread数に関係してくるので次で述べます。
thread数
threadは1worker内での論理スレッド数を示しています。
- 1worker/16threadの場合、計16thread
- 2worker/16threadの場合、計32thread
1worker内の最大thread数は、ここにも書いてあるように 16 より大きくしないほうが良さそうです。
※workerとthreadの関係はこちらに記載
実際に設定ファイルに書くときは、2worker/16threadの計32threadの場合は以下の通りに書いてください。
# 環境変数 RAILS_MAX_THREADS に 16 をセット
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
...
# 環境変数 WEB_CONCURRENCY に 2 をセット
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
実験を行った結果、もちろんサーバーのリソース(今回はCPUコア数: 2)にもよりますが以下のようにサーバーが処理できるキャパシティが変わりました。thread数が少ないともちろんさばける処理数が減るため、サーバーのリソースが余っているにもかかわらず、unhealthyになります。つまり、レスポンスで過負荷を示す503 errorが返却されます。
- 1worker/5threadの場合、CPU15%ぐらいでunhealthyになる
- 1worker/10threadの場合、CPU30%ぐらいでunhealthyになる
- 1worker/16threadの場合、CPU45%ぐらいでunhealthyになる
- 2worker/16threadの場合、CPU90%ぐらいでunhealthyになる
ここで気をつけないといけないのは、アプリケーションサーバーのCPU使用率だけに目がいくとメモリを圧迫してメモリが原因で処理ができなくなる場合もあるので、メモリもしっかり監視してください。また、データベースに負荷のかかる処理を行うような場合はデータベースのCPUやメモリにも注意してベストな組み合わせを見つけてください。
上記の実験条件下で、かつメモリに余裕がある場合は、2worker/16threadがベストだと考えることができます(リソースを無駄なく使いきるという意味です)。
Rails
pool数
database.yml内の pool
は、MySQLとの接続数を示しています。
puma worker * puma thread > pool
になってしまうとActiveRecord::ConnectionTimeoutError
が発生してしまいます。なので、 pool
は puma worker * puma thread == pool
になるように設定しましょう。
その逆で、MySQLの最大コネクション数を超えるとMySQLの Too many connections
エラーが出ます(式で表すと: pool > max_connections
)。このコネクション数の最大は、 MySQLの設定に依存しますので、次で詳しく説明します。
MySQL
max_connections数
max_connections
は、MySQLの最大コネクション数になります。DBインスタンスの性能によって最大値を変えるのがいいと思いますが、AWSのRDSは初期値が以下の通りに設定されています(インスタンスによって異なります)。
t2.micro
: 66
t2.small
: 150
t2.medium
: 312
上記はRDSの推奨っぽいので、上限を上げることはできますが、あまりおすすめはしません。
最大コネクション数は、以下のSQLで確認可能です。
show variables like "%max_connections%";
まとめ
最初に貼りましたが最終的に以下のように内部的に動いていますので、先程紹介した設定値を参考にしてみてください。ただ、繰り返しにはなりますがサーバーのリソースやアプリケーションの処理する内容によってベストな設定値が変わります。なので、この数値にすればOK!というものがありません。これがチューニングの難しいところです。自社にあった設定値を地道に探していきましょう。その中で、この記事の内容がお役に立てれば幸いです。
※上記画像のthread数を5にしているのは矢印線を16本引くのが大変だったので5にしているだけで推奨値とかではありません