• 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

 仕事でRailsを使うことになり、APサーバの選定にあたってPuma, Unicorn, Passenger の比較検討を行いました。方法としてはJMeterでAPサーバにデプロイしたRailsアプリケーションに対して負荷をかけられるだけかけるというやり方です。


試験環境


試験の環境としては下記の構成です。

  • Ruby2.0, Rails4
  • アプリケーションサーバ:1台(VM)
  • JMeterサーバ:3台(VM)
  • JMeterクライアント:1台(通常の作業PC)
    サーバ構成
    hostanameCPU仮想コア数(Per CPU)MemoryDisk用途
    loadtest01248192MB20GBAPサーバ
    loadtest02114096MB20GBJMeterサーバ
    loadtest03114096MB20GBJMeterサーバ
    loadtest04114096MB20GBJMeterサーバ


サーバアーキテクチャの比較


各APサーバのアーキテクチャの比較は下記の通りです。

各APサーバのアーキテクチャの比較
PumaUnicornPassenger
デプロイモデルReverse ProxyReverse ProxyNginx Module
Process/ThreadMulti Processes / Multi ThreadsMulti Processes / Single ThreadMulti Processes / Single Thread(OSS Edition)
Multi Processes / Multi Threads(Commercial Edition)
その他特徴Workerプロセスごとにスレッドを立ち上げるPull型(Workerプロセス側からキューのタスクを取得しにいく)トラフィックに応じてプロセス数を自動調整。商用Editionのみマルチスレッド利用可能


処理内容


処理内容としては、純粋にAPサーバの処理能力の比較にするため、DBアクセス等はせず、フィボナッチ数列を計算して返す処理を行います。ロジックは書きサイトを参考にしました。

Rubyでメモ化を使ってフィボナッチ数を求める

   1  class StaticPagesController < ApplicationController
   2  
   3    def fibonacci
   4      @fibonacci = calc_fibonacci(params[:n].to_i)
   5    end
   6  
   7    private
   8  
   9      def calc_fibonacci(n)
  10        if (n < 2)
  11          return n;
  12        else
  13          p2 = 0;
  14          p1 = 1;
  15          2.upto(n) { p2, p1 = p1, p2 + p1 }
  16          return p1;
  17        end 
  18      end
  19  
  20  end


JMeterシナリオ


JMeterのシナリオとしては、

  • JMeterスレッド数:100
  • Ramp up:0
  • ループ数:無限ループ
  • 継続時間:5分間

という内容です。
JMeterのシナリオファイルはこちらから取得できます。


APサーバごとの設定値による差の検証


まずは各APサーバごとに、設定値の変更による差を検証しました。


Puma

Puma検証
ワーカプロセス数スレッド数サンプル数平均値(msec)中間値(msec)90%LINE (msec)最小値(msec)最大値(msec)スループット(/sec)KB/secエラー数
1500430792090197823791292519141.68414.67多発
1008241811365571071646414799.432339.490
10032243620362601136616890805.372356.8332
64322428253655113557103157802.352347.941
3232241934366467606252504798.242335.890
1664237270373313396298546782.002288.340
1696231996382376446241748762.492231.260

  • ワーカプロセス数1のケースでは全くCPUを使い切れていませんが、他のケースではCPUを使い切った状態で動いていました。
  • スレッド数を増加させてもリソースの使用量はあまり変化しませんでしたが、プロセス数を増やすと使用量がかなり増えます。
  • メモリに余裕があってもCPUが振り切る方が早いです。


Unicorn

Unicorn検証
ワーカプロセス数サンプル数平均値(msec)中間値(msec)90%LINE (msec)最小値(msec)最大値(msec)スループット(/sec)KB/secエラー数
1429411345572505537717624711.7434.54433
886866026562137217714119322.1565.15389
32429431465325284451183552103.48304.38280
6419125444017037526115819498.541466.4648
962471913601702614982454773.582275.693
1282560503432524521320587836.002459.820
160254117347291537158825835.542458.540
192252158349302588135746833.942453.870
2242297233832755929299799697.122045.152

  • ワーカプロセス数が1の場合は1CPUしか使われない
  • ワーカプロセス数をコア数と同じ8にした場合でも、すべてのコアが使われるわけではない
  • ワーカプロセス数をコア数の4倍の64まで増やすとかなりCPUが使われるようになってきて、128まで増やすとCPUはほぼ使い切られて、メモリの使用率も高くなる。
  • ワーカプロセス数を192まで増やした時点でメモリもほぼ使い切られ、224まで増やすとメモリが足りなくなり、Swapが発生して遅くなる。


Passenger

Passenger検証
プロセス数サンプル数平均値(msec)中間値(msec)90%LINE (msec)最小値(msec)最大値(msec)スループット(/sec)KB/secエラー数
16518813761282132512248690215.15646.070
82451533603553682972441810.572433.990
162467373573533812792339815.772448.770
242411653663603912812414797.272392.300

  • プロセス数が1だと4コアしか使われていない
  • プロセス数をコア数と同じにするとどのコアもかなり使われるようになる。メモリは余裕あり。
  • プロセス数をコア数以上に増やしていってもCPU, メモリの使用率はあまり変化しない。CPUは80%まで使われることが多いが、アイドルが10%前後残っていて、使い切ることはない


各APサーバの最適値同士を比較


各APサーバの最適値同士を比較して、使用するAPサーバを決定する

総合
APサーバサンプル数平均値(msec)中間値(msec)90%LINE (msec)最小値(msec)最大値(msec)スループット(/sec)KB/sec
Puma241811365571071646414799.432339.49
Unicorn252158349302588135746833.942453.87
Passenger2467373573533812792339815.772448.77

  • Pumaはスループットが一番低いのに加えて最大値、90%LINEの遅さ、不安定さで候補から除外。
  • Passengerは安定しているが最小値が他の2つに比べて大きい。90%LINE、最大値は優秀。
  • Unicornはスループットが一番大きいのと、最小値、平均値も悪くない。最大値、90%LINEがPassengerと比 べると遅いのが懸念点。

定数スループットタイマを使って実際のアクセス数に近い負荷でUnicornとPassengerを比較
APサーバサンプル数平均値(msec)中間値(msec)90%LINE (msec)最小値(msec)最大値(msec)スループット(/sec)KB/sec
Unicorn23075121013411675.32221.50
Passenger2309211912511875.38226.67

  • UnicornとPassengerでほぼ差はなし
  • Passengerは最初の比較時に他と比べて最小値が遅いことが懸念だったが、実際の状況に近いアクセス数では 問題なく、Unicornが負荷が低い状態でもメモリリソースを消費するのに対してPassengerはリソースの消費が少ないこと から、Passengerを第一候補と考える。


検証時の問題点


検証時に発生した問題点を参考までに記載しておきます。


Passenger

  • デフォルトの状態で負荷をかけたところ、下記のようなエラーが多発してHTTPステータスコード 503が返される。

   1  [ 2013-11-20 12:21:13.0578 17419/7fbbbc9da700 Pool2/Group.h:331 ]: Request queue is full. Returning an error

リクエストのQueueがあふれたことによるもののようです。Queue のサイズのデフォルトは100なので、無制限にするために passenger_max_request_queue_size を0に設定したところ、エラーは出なくなりました。


Unicorn

  • Nginxとの連携をUnixドメインソケットで行う設定で負荷をかけたところ、下記エラーが多発。

   1  2013/11/20 11:32:35 [error] 27462#0: *622742 connect() to unix:///home/test_user/server-proto/unicorn.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 192.168.51.234, server: loadtest01.test.com, request: "GET /fibonacci?n=1000 HTTP/1.1", upstream: "http://unix:///home/test_user/server-proto/unicorn.sock:/fibonacci?n=1000", host: "loadtest01.test.com:3090"

下記サイトなどを参考に、TCPポートによる連携に変更しました。

http://www.faultserver.com/q/answers-need-to-increase-nginx-throughput-to-an-upstream-unix-soc ket-linux-kernel-tun-398972.html

変更後に負荷をかけたところ、エラーは概ね解消しました。負荷をかけ続けていると、件数は少なくなったもののエラーが発生しました。HTTPステータスコードは 502 Bad Gateway

   1  2013/11/20 14:45:29 [error] 25979#0: *254606 upstream prematurely closed connection while reading response header from upstream, client: 192.168.51.232, server: loadtest01.nubee.com, request: "GET /fibonacci?n=1000 HTTP/1.1", upstream: "http://127.0.0.1:3070/fibonacci?n=1000", host: "loadtest01.test.com:3090"

   1  [2013-11-20 14:44:09.109250] ERROR worker=114 PID:26737 timeout (31s > 30s),
   2        killing
   3        [2013-11-20 14:44:09.119595] ERROR reaped #<Process::Status: pid 26737 SIGKILL
   4        (signal 9)> worker=114
   5        [2013-11-20 14:44:10.140398]  INFO worker=114 ready

検証のためにUnicorn側のタイムアウト設定を大幅に増やしました。30秒 → 300秒に変更。Nginxの設定にも下記を追加しました。

   1  send_timeout 300;
   2  proxy_connect_timeout 300;
   3  proxy_read_timeout 300;

これでひとまずエラーは回避できました。。スループットの検証のためにタイムアウト値を大きくしていますが、実際の環境ではタイムアウト値は小さく設定する必要があります。

posted by Png akanuma on Sat 7 Dec 2013 at 23:14

Comments:

or Preview
Social Bookmarks
  • Delicious
  • B_entry2346
  • Clip_16_12_w
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ