BackEnd

【Puma】アプリサーバのチューニング

投稿日:

はじめに

みなさん、アプリサーバのチューニングはどのように行っていますか?
私の場合、使うサーバのスペックがだいたい同じくらいなので、過去の設定ファイルを使いまわしていました。

そんな中、先日本番環境で初めてPumaを使用しましたが時間の都合でチューニングが行えませんでしたので、今回Pumaのパフォーマンスチューニングについて調べてみました。

 

チューニングで注意する項目

アプリサーバのチューニングにおいて注意する項目は下記のとおりです。

  • 子プロセスの数
  • スレッドの数
  • Copy-on-write
  • サーバスペック(メモリ、CPU等)

これらの項目はPumaに限らずUnicornやPassengerなどの他のアプリサーバにも当てはまります。
それでは個別の設定を見ていきましょう。

 

子プロセスの数

Puma(UnicornとPassengerも同様)はforkを使う設計になっており、アプリのプロセス1つから複数のコピー(子プロセス)を作成します。
これにより、例えば2コア4スレッドのマシンなら4つの子プロセスを作成することで大幅にパフォーマンスを向上させることができます。
この子プロセスの数がチューニングにおける最も重要な設定です。

最低3つの子プロセスを割り当てる

1サーバあたり最低3つの子プロセスを割り当てるのとルーティングの効率が良いようで、それに合わせてサーバスペックを調整すると良いです。
最適な子プロセスの数については、CPU使用率や搭載するRAMに合わせて調整します。

最大子プロセス数

最低3つの子プロセスを割り当てれば良いことはわかりました。では、最大でいくつの子プロセスを割り当てることができるでしょうか。
これはRAMとCPUで決まります。

まず、RAMですがサーバのRAMがサポートできる個数を上回る子プロセスを割り当てるとパフォーマンスが低下します。
なので、メモリ使用量には余裕を保つ必要があります。
一つの目安として下記の式を見てください(多くのRubyアプリは1プロセスあたり200MBから400MBのメモリを使います)
(RAM / (プロセスあたりのメモリ使用量 * 1.2))

次にCPUですが、サーバの利用可能なCPUキャパシティを超えないようにする必要があります。
理想的には、CPU使用率100%になる総割り当て時間の5%を超えないことです。

CPUコア数と子プロセス数

一般に「CPUのコア数より多くの子プロセスを1サーバに割り当てるべきではない」と言われますが、多くのアプリケーションではプロセスの数は利用できるハイパースレッドの数の1.25倍から1.5倍に落ち着くようです。

なぜPumaの子プロセス数を増やす必要があるのか

Pumaはマルチスレッドに完全対応したアプリサーバなのに、なぜプロセス数を増やす必要があるのかと疑問を持つかもしれません。
たしかに、JRubyやRubiniusを使用しているのならば、理論上は1つのプロセスで処理することができます。
しかし、MRIにはグローバルVMロック(GVL)という仕組みがあり、一度に1つのRubyプロセスで実行できるスレッドは1つに制限されてしまうためです。

 

スレッド数

次にスレッド数について見ていきます。
並列化によってどの程度スピードが上がるかは、それぞれのアプリケーションの並列化度合いによります。

一般的にはスレッド数は”5”で良い

上述の通り、MRIではGVMの影響でIO待ちのみ並列化できるため、スレッド数を増やすことによる恩恵を受けにくいという特徴があります。
また、MRIではスレッド数を増やす事によりメモリを大幅に消費する場合があります。
スレッド数は現在の設定での測定値を定期的にチェックして設定するのが良いですが、一般的にはスレッド数を5に設定して放置してもたいてい大丈夫なようです。

 

Copy-on-write

あらゆるUnixベースのOSはメモリの挙動がCopy-on-writeで実装されています。
Copy-on-writeとは簡単に説明すると、プロセスがforkして子プロセスができた時点ではメモリを親プロセスと完全に共有していて、子プロセスに変更があった場合に初めてコピーされて子プロセス専用メモリになる方式です

効率を高めるために

Copy-on-writeはオフにできるものではありません。
Copy-on-writeの効率を高めるためにはforkの前にアプリを全て読み込む必要があります(設定に関しては後でまとめて記載します)

 

サーバスペック

一般的に、サーバで利用可能なCPUやメモリの使用率は70%から80%に留めるのが良いとされています。
子プロセスの数で書いたとおり、最低でも子プロセスは3つにしたほうが効率が良いため、これを考慮してスペックを決めると良いと思います。

また、ハイパースレッドの数に応じてプロセス数の上限が決まるため、コア数やハイパースレッディングをサポートしているのか等も確認しておくと良いでしょう。

 

設定サンプル

では、実際にPumaの設定ファイルを書いてみましょう。
Pumaの設定ファイルはconfig/puma/に作成します。

  • 子プロセスの数
  • スレッドの数
  • Copy-on-write

上記のポイントを考慮して作成した設定ファイルは下記の通りです。

デーモンとして起動

アプリケーションを長時間バックグラウンドに常駐させるために、デーモンとして起動します。

workerを定期的に再起動させる

Pumaのworkerは起動して暫く経つとメモリの消費が膨れ上がるため、定期的にworkerを立ち上げ直します。
これには、PumaWorkerKillerというGemを利用します。
https://github.com/schneems/puma_worker_killer

 

さいごに

今回いろいろ調べて見ましたが、改めてNginx+Unicornという構成は鉄板なんだなと思いました。
せめてMRIでもフルにスレッドを利用できれば良いのですが、今後に期待します。
Pumaのデプロイ設定に関してはこちらでまとめていますので、よろしければ御覧ください。

 

参考

blog-page_footer_336




blog-page_footer_336




-BackEnd
-,

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

laravel logo

Laravelでテストコードを書くには? Featureテスト/Unitテスト

1 はじめに2 FeatureとUnitの使い分け3 テスト用データベースの準備4 Featureテスト4.1 テスト対象のコード4.2 テストコードの実装4.3 テスト結果の検証4.3.1 ステータ ...

Stripe Connectでダイレクト支払い導入編

1 はじめに2 事前準備3 StripeConnectの導入3.1 stripeパッケージの導入3.2 envの実装4 店舗アカウントの登録4.1 Stripe Connectの設定4.2 Oauth ...

rails

ShrineでS3に画像をアップロードする

1 はじめに1.1 前提条件1.2 関連記事2 AWS側の準備2.1 S3バケットを作成する2.2 CORSを設定する2.3 アクセス用のユーザを作成する3 Rails側の設定3.1 Initiali ...

js

Moment Timezoneを使ってJavaScriptで日付を変換する

1 はじめに2 Moment Timezone2.1 セットアップ2.2 使用例3 Moment Timezoneの機能3.1 タイムゾーンの一覧を表示する3.2 現在のタイムゾーンを表示する3.3 ...

rails

Railsでの非同期処理とDelayed Job

1 はじめに2 Active Job2.1 Active Jobの役割2.2 ジョブを作成する2.3 ジョブをキューに登録する2.4 コールバック2.5 例外3 Delayed Job3.1 設定3. ...

フォロー

blog-page_side_responsive

2018年8月
 1234
567891011
12131415161718
19202122232425
262728293031  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。