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


関連記事

js

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

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

軽量なAlpine Linuxイメージでgitbookのローカル環境を構築する

1 はじめに2 Alpine Linuxとは3 Docker本体のインストール4 サンプルリポジトリのダウンロード5 dockerイメージ作成6 Gitbook初期化&実行7 Dockerの ...

rails

Shrineを使って画像をアップロードする

1 はじめに2 Shrineとは2.1 簡単な説明2.2 作者2.3 特徴3 下準備3.1 Gemを追加3.2 初期設定3.3 テーブルを作成する4 実装4.1 Uploaderの実装4.2 Mode ...

Vue.js+TypeScriptな環境整備

1 はじめに2 vue-cliのインストール3 プロジェクトの作成3.1 機能の選択3.2 シンタックスの選択3.3 CSSプリプロセッサの設定3.4 Unit test3.5 E2E test3.6 ...

Go言語

Go言語でGinkgoを利用してBDDしてみた

1 はじめに2 BDDとは3 Ginkgoについて3.1 Ginkgoの概要3.1.1 Describe3.1.2 Context3.1.3 It3.1.4 JustBeforeEach3.1.5 B ...

フォロー

follow us in feedly

page_side_300rect

2018年8月
« 7月 9月 »
 1234
567891011
12131415161718
19202122232425
262728293031 

アプリ情報

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