ククログ

株式会社クリアコード > ククログ > PassengerでRroongaを使ったWebアプリケーションを動かすときにチューニングのコツ

PassengerでRroongaを使ったWebアプリケーションを動かすときにチューニングのコツ

RroongaはSQLite3のような手軽さで使えるRuby用の全文検索ライブラリーです。Webアプリケーションに全文検索機能をつけたいときにも便利です。Rubyのリファレンスマニュアルの検索サービスであるるりまサーチもRroongaを使っています。

そんなRroongaをPassengerで動かすときのチューニング方法を紹介します。チューニングすることにより少ないリソースでも高速に動作するようになります。例として、docs.ruby-lang.orgにデプロイされている、るりまサーチを使います。

環境

docs.ruby-lang.orgの環境は次の通りです。

  • OS: CentOS 6
  • (/proc/cpuinfoで見える)CPU: Intel(R) Xeon(R) CPU L5630 @ 2.13GHz
  • (/proc/cpuinfoで見える)CPU数: 2つ
  • メモリー: 1GB
  • スワップ: 1GB
  • Ruby: 2.1.2
  • Passenger(nginxバージョン): 4.0.48

このマシン上で、Rubyのリファレンスマニュアル(HTML)とるりまサーチが動いています。

チューニング前の状態

まず、チューニング前の状態を説明します。当時のシステムの統計情報をグラフ化したものを見てください。

チューニング前のCPU使用率

チューニング前のロードアベレージ

CPU使用率がほぼ0%になっているときはるりまサーチが落ちている状態です。動いているときはCPU使用率50%から100%くらいの状態がほとんどで、そのうちの半分いかないくらいがiowaitです。ロードアベレージは1から5の間なので、常に数プロセス待っている状態です。

チューニング前のメモリー使用量

メモリー使用量は常にほぼ100%です。スワップも半分いかないくらい使っています。なお、メモリ使用量がガクンと減っているときはサービスが落ちているときです。

グラフからもわかる通り、この頃は慢性的なメモリー不足で数十分に1回OOM Killerが動いている状態でした1

チューニング後の状態

この状態をチューニングした後の統計情報のグラフを見てみましょう。グラフの真ん中あたりがチューニングを始めた頃です。左半分を見るとチューニング前の状態、右半分を見るとチューニング後の状態がわかります。

チューニング後のCPU使用率

チューニング後のロードアベレージ

CPU使用率は20%くらい下がっています。それもよいことですが、それよりも特筆すべきはiowaitがほとんどなくなっているところです。ロードアベレージは常に1より小さくなりました。処理待ちのプロセスはほとんどいないということです。

チューニング後のメモリー使用率

メモリー使用率は半分くらいになりました。もちろん、スワップも使わなくなっています。iowaitがほとんどなくなっているのはスワップを使わなくなったからです。メモリーに余裕ができたのでOOM Killerも動いていません。

だいぶよくなりましたね。

チューニング方法

この改善のためにはPassengerの設定を2つ追加しただけです。それは次の設定です。

  • passenger_max_pool_size 2
  • passenger_max_requests 100

それぞれのパラメーターについて何をするものか、どういう効果があるものかを説明します。

passenger_max_pool_size

passenger_max_pool_sizeはRackアプリケーションのプロセスを最大でいくつ起動するかを制御するパラメーターです。デフォルトは最大で6プロセスです。

1つのPassengerで1つのRackアプリケーションしか扱っていないケース(今回のケース)は、このパラメーターの値は多くてもCPU数と同じにするのが適切です。プロセス数がCPU数よりも多くても、CPU数以上同時に実行できないのでそれほど性能はあがりません。

一方、プロセスを起動すればするほど使用メモリー量は増えます。今回のケースのようにそれほどメモリーがない環境では、使用メモリー量が増えてスワップを使うようになるとiowaitが発生し一気にパフォーマンスが落ちます。

このようにプロセス数を増やす方が遅くなることがあります。チューニング前の状態はまさにこの状態でした。

そのため、このpassenger_max_pool_sizeというパラメーターをCPU数と同じ2にするだけでチューニング後のグラフの状態になりました。メモリーが少ない環境では重要なパラメーターです。

特に、Rroongaを使ったアプリケーションはプロセス内でデータベースを開くため、メモリー使用量が大きめになります2。そのため、このパラメーターは重要です。

passenger_max_requests

passenger_max_requestsは、指定した数だけリクエストを処理したらそのRackアプリケーションプロセスを終了し、新しいRackアプリケーションプロセスを起動するようにするパラメーターです。デフォルトは0で、この機能は無効になっています。

このパラメーターはリクエストを処理するごとにメモリー使用量が増えていくRackアプリケーションに有効なパラメーターです。passenger_max_pool_sizeでベースのメモリー使用量を削減できます。passenger_max_requestsは継続して動作したときのメモリー使用量を削減できます。

チューニングを開始した時点のるりまサーチはリクエストを処理するごとにメモリー使用量が増えているようでした。そのため、passenger_max_requests 100として100リクエスト処理するごとにプロセスを再起動するようにしました。

ただし、passenger_max_requests 100は回避策であり、根本的な解決ではありません。根本的に解決した方が助かる人が増えます。そのため、根本的な解決にも取り組みました。

Rroongaのメモリー使用量削減

るりまサーチが使っているライブラリーは主に全文検索ライブラリーのRroongaです。そのため、るりまサーチのメモリー使用量がリクエストごとに増えているなら次のどれかのコンポーネントが問題です。

  • Ruby
  • Passenger
  • Rroonga
  • るりまサーチ

RubyとPassengerは多くの環境で使わているので見逃されているメモリーリークに遭遇する可能性は低いです。そのため、Rroongaとるりまサーチを調べました。

詳細は省略しますが、Rroongaの一部がRubyのGCと相性の悪い実装になっていました。長生きしているオブジェクトが一時オブジェクトを参照しているため、RubyのGCが回収できていませんでした。

やはり、詳細は省略しますが、Rroonga本体を修正し、RubyのGCが動いたときに一時オブジェクトが回収されるようにしました。この修正は次回リリースのRroonga 4.0.4に含まれる予定です。

docs.ruby-lang.orgのるりまサーチはmasterのRroongaを使うようにして、passenger_max_requests 100という設定は無効にしています。この状態で1週間ほど動いていますが、メモリー使用量は170MBほどで安定しています。

% sudo -H ~rurema/.rbenv/versions/2.1.2/bin/passenger-status
Version : 4.0.48
Date    : 2014-08-26 17:30:35 +0900
Instance: 7756
----------- General information -----------
Max pool size : 2
Processes     : 2
Requests in top-level queue : 0

----------- Application groups -----------
/var/rubydoc/rurema-search/current#default:
  App root: /var/rubydoc/rurema-search/current
  Requests in queue: 0
  * PID: 26038   Sessions: 0       Processed: 691258   Uptime: 6d 14h 51m 7s
    CPU: 20%     Memory  : 167M    Last used: 0s a
  * PID: 26045   Sessions: 0       Processed: 685916   Uptime: 6d 14h 51m 6s
    CPU: 19%     Memory  : 166M    Last used: 0s a

Rroongaを使っていてメモリー使用量が徐々に増えていくというケースがある場合は、Rroonga 4.0.4がリリースされたらぜひ試してみてください。

まとめ

PassengerでRroongaを使ったWebアプリケーションを動かすときのチューニングのコツを紹介しました。ポイントはpassenger_max_pool_sizeです。まずは、CPU数と同じにして様子を見てみてください。メモリー使用量が大きくなるようならCPU数よりも少なくしましょう。

そろそろリリースされる予定のRroonga 4.0.4ではGCフレンドリーになっています。長時間動き続けるRroongaを使ったプロセスを持っている人は楽しみにしていてください。すぐにアップデートできない人はpassenger_max_pool_sizeの使用も検討してみてください。

ただ、Rroongaに限りませんが、回避策を使うよりも、根本的な解決をする方が助かる人が増えることは事実です。ぜひ、根本的な解決にもチャレンジしてみてください。自分で直すことが難しい場合でも、問題を報告する、デバッグに協力するなどで根本的な解決につながる活動をできるかもしれません。

  1. /var/log/messages調べ。

  2. データベースファイルはmmapでマップしてアクセスしているので複数プロセスでデータベース用のメモリー領域を共有します。そのため、データベースのサイズ分のメモリーは複数プロセスで共有します。