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

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

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

rails

Railsで複合主キーのテーブルを扱う

1 はじめに1.1 前提条件2 実装例2.1 config2.2 マイグレーション2.3 モデル3 さいごに はじめに RailsでWebサービスを開発する際のDB設計では基本的にidが主キーになると ...

rails

Rails Developer Meetup に参加してきました【2日目】

1 はじめに2 Rails Developer Meetup3 テストのないレガシーなRailsアプリをリファクタした話3.1 なぜリファクタリングしたのか3.2 コードを3種類に分類する3.3 モデ ...

rails

RailsでSidekiqを使ってみた

1 はじめに1.1 実行環境2 前準備2.1 Redisのインストール3 Railsの準備3.1 プロジェクト作成3.2 新規登録時にAPIを叩く4 Sidekiqの準備4.1 Workerを作る5 ...

rails

Ruby2.4でCookieを手動で復号する際に発生したエラーの対処

1 はじめに1.1 前提条件2 発生したエラー2.1 実際のコード2.2 エラー詳細2.3 原因3 どう対処したか3.1 修正後のコード はじめに こんにちは、onoです。 現在開発中のアプリケーショ ...

フォロー

follow us in feedly

AppLink

英語

page_side_300rect

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

アプリ情報

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

Web版MyCoach

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