Edited at

Nginx, Puma, Rails, MySQLのパラメータ設定/チューニング


概要

Nginx, Puma, Rails, MySQLのチューニングを行ったときの知見を載せておきます。

ただし、チューニングは色々な要素に依存するため、最終的には自分たちの作っているアプリケーションにあった値を見つけてください。

以下の図のような動きを内部的にしています。では早速、各サービスの設定項目を詳しく見ていきましょう。

スクリーンショット 2019-06-02 23.00.06.png


Nginx


worker数

今回自分はNginxがボトルネックにはならなかったので、Nginxの知見はあまり習得していないですが、色々な人のブログを見ていると auto にしていることが多そうなので、特に理由がない場合以外は auto でいいかと思います。


/etc/nginx.conf

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の場合は以下の通りに書いてください。


config/puma.rb

# 環境変数 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 が発生してしまいます。なので、 poolpuma 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!というものがありません。これがチューニングの難しいところです。自社にあった設定値を地道に探していきましょう。その中で、この記事の内容がお役に立てれば幸いです。

スクリーンショット 2019-06-02 23.00.06.png

※上記画像のthread数を5にしているのは矢印線を16本引くのが大変だったので5にしているだけで推奨値とかではありません