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のデプロイ設定に関してはこちらでまとめていますので、よろしければ御覧ください。

 

参考

page_footer_300rect




page_footer_300rect




-BackEnd
-,

執筆者:


comment

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

CAPTCHA


関連記事

rails

RailsでAjax処理で画面を更新する

1 はじめに2 View(遷移元)の設定3 Controllerの実装4 View(遷移先)の実装5 参考6 さいごに はじめに RailsでAjax処理で画面を更新する方法を簡単に紹介します。 Vi ...

RSpecの個人的Tips集〜その1〜

1 はじめに2 テストコードの実行をスキップする3 共通のテストコードを用意する4 外部APIの返却値をスタブにする5 さいごに はじめに みなさん、テストコードは書かれているでしょうか? 私も極力書 ...

rails

Railsの低レベルキャッシュを使ってみた

1 はじめに1.1 環境2 ドキュメント3 準備3.1 configの確認3.2 キャッシュストア4 使ってみる4.1 #read、#write、#delete4.2 #fetch4.3 オプション4 ...

PHPerだけどKotlinを勉強したって良いよね その1〜クラス編〜

1 はじめに2 インターフェース2.1 基本2.2 デフォルト実装付メソッド2.3 同じメソッド名を持つ複数のインターフェース3 修飾子3.1 open3.2 abstract4 可視性修飾子5 さい ...

rails

半年ぶりにRails Tutorialをやったメモ

はじめに Railsを触り始めて半年ほどたちました、tonnyです。 復習もかねてRails Tutorialを実施したので、そのメモを残します。 やはり2回目でも気づくことは多いので、非常に勉強にな ...

AppLink

page_side_300rect

アプリ情報

私たちは、目標を達成したい方を応援する、TODOアプリもリリースしております。
下記のアイコンから無料でダウンロードできます。

フォロー

follow us in feedly
2018年8月
« 7月  
 1234
567891011
12131415161718
19202122232425
262728293031 

Web版MyCoach

私たちはより広い方にコーチングを知ってもらいたいと考えています。 下記のサイトにて、コーチの方々を紹介しておりますので、よろしければご覧ください。