2012-05-09 6 views
9

私はNginx/Thin(1.3.1)に移動したばかりのNginx/Passengerのレール3アプリを持っていました。しかし、私のアプリは現在、Passengerよりもはるかに遅いです。多くのリクエストもタイムアウトします。Thin server underperforming /イベントを起こしたWebサーバーはどのように機能しますか?

シンはイベントが発生したウェブサーバーです。私は、Webサーバーのイベントについて読んだところから、労働者という概念を持っていません。 1人の「ワーカー」がすべてを処理します。したがって、1つのリクエストがIOで待機している場合、thinは次のリクエストに移動します。私が遭遇したサーバーについて読んだところ、遭遇したサーバーは、システムリソースだけに縛られているため、ワーカーベースのサーバーよりも優れたパフォーマンスを発揮するはずです。

ただし、私のCPU使用量はごくわずかです。私のメモリ使用量はごくわずかであり、IOもあまり起こりません。私のアプリはちょうどいくつかのMySQLのクエリを行います。

ボトルネックは何ですか? CPUが100%になるまで、シン・サーバは要求を処理してはいけませんか?イベントが発生したサーバーでパフォーマンスを向上させるためには、アプリで別のことを行う必要がありますか?

答えて

13

セルジオが正しいです。あなたのアプリは、現時点では、おそらく従来のApache/Passengerモデルの方が優れています。特にRubyのようなシングルスレッドプラットフォームでは、DB、キャッシュサーバー、その他のHTTPリクエストなど何でもブロックすることはできません。

これは、非同期(イベント)プログラミングを難しくするものです。通常、同期ディスクのI/OまたはDNS解決の形で、ブロックするのは簡単です。 nodejのようなノンブロッキング(イベント)されたフレームワークは、(ほとんど)コールバック(DBクエリを含む)を使用して処理されるフレームワーク関数呼び出しをブロックしないことに注意しています。

あなたはシングルスレッドノン・ブロッキングサーバーの心を見ればこれは視覚化しやすいかもしれません:

イベントループと呼ばれるあなたが上記を参照
while(wait_on_sockets(/* list<socket> */ &$sockets, /* event */ &$what, $timeout)) { 
    foreach($socketsThatHaveActivity as $fd in $sockets) { 
     if($what == READ) { // There is data availabe to read from this socket 
      $data = readFromSocket($fd); 
      processDataQuicklyWithoutBlocking($data); 
     } 
     elseif ($what == WRITE && $data = dataToWrite($fd)) { // This socket is ready to be written to (if we have any data) 
      writeToSocket($fd, $data);  
     } 
    } 
} 

wait_on_socketsは通常、select、poll、epoll、kqueueなどのシステムコールの形でOSによって提供されます。 processDataQuicklyWithoutBlockingに時間がかかりすぎると、OSによって保持されているアプリケーションのネットワークバッファ(新しい要求や着信データなど)が最終的にいっぱいになり、$ socketsThatHaveActivityが十分に速く処理されないため、新しい接続を拒否し、 。これはスレッド化されたサーバー(典型的なApacheのインストール)とは異なり、各接続は別々のスレッド/プロセスを使って提供されるため、到着するとすぐに受信データがアプリケーションに読み込まれ、送信データは遅滞なく送信されます。

nodejのようなノンブロッキングフレームワークは、DBクエリを(例えば)監視するソケットのリスト($ソケット)にDBサーバーのソケット接続を追加することですしばらくして、あなたの(唯一の)スレッドはそのソケットでブロックされません。むしろ彼らは、コールバック提供:あなたが上見ることができるように

$db.query("...sql...", function($result) { ..handle result ..}); 

を、db.queryは絶対に無い全くDBサーバー上でブロックするとすぐに戻ります。また、これは、プログラミング言語自体は(新しいC#のような)非同期機能をサポートしていない限り、あなたが頻繁に、このようなコードを記述しなければならないことを意味:

$db.query("...sql...", function($result) { $httpResponse.write($result); $connection.close(); }); 

あなたは多くのプロセスを持っている場合は、決して、常にブロックルールが多少緩和することができますイベントループ(通常はノードクラスタを実行する方法)を実行するか、スレッドプールを使用してイベントループを維持します(javaのjetty、nettyなど、C/C++で独自に記述できます)。 1つのスレッドが何かでブロックされている間も、他のスレッドは引き続きイベントループを実行できます。しかし、十分に重い負荷の下では、これらは実行することができません。したがって、イベントが発生したサーバーでは決してブロックしないでください。

このように、イベントが発生したサーバーは一般的に、さまざまな問題を解決しようとします。開いている接続の数が非常に多いことがあります。彼らが優秀なところでは、軽い計算(例えば、彗星サーバ、memcached、ワニス、nginx、squidなどのプロキシのようなキャッシュ)を使ってバイトをプッシュするだけです。彼らのスケーラビリティは向上しますが、応答時間は一般的に増加する傾向があります(接続のスレッド全体を予約するよりも優れているわけではありません)。もちろん、同時接続数と同じ数のスレッドを実行することは、経済的に/計算上では実現できない可能性があります。

あなたの問題に戻って - Nginxを接続管理(イベントベース)に優れているので、あなたはまだNginxを守っておくことをお勧めします - 一般にHTTPキープアライブやSSLなどを処理することを意味します。 FastCGIを使ってあなたのRailsアプリケーションに、ワーカーを実行する必要がありますが、完全にイベントが発生するようにアプリケーションを書き直す必要はありません。また、Nginxに静的なコンテンツを提供させるべきです.Railsの作業者がNginxが通常より良くできることに縛られることはありません。このアプローチは一般にApache/Passengerよりもはるかに優れています。特にトラフィックの多いWebサイトを使用している場合は特にそうです。

あなたのアプリケーション全体をイベントとして書くことができれば、素晴らしいですが、Rubyでどのように簡単か難しいかはわかりません。

+0

ワウ..詳細な応答Tejasのおかげで。だから、私がネットから読んだベンチマークは、まったく異なるアプリケーションジャンルのものですか? Thin自身のサイトは、薄型のサンプルアプリケーションとしてレールアプリを提供しています。 http://code.macournoyer.com/thin/。私は乗客を薄いものに置き換えることができたと思っていましたが、すべてが大変なことになりました。 –

+0

どこでもブロックしない限り、それらのベンチマークを再作成できるはずです。 – tejas

3

はい、ThinはI/Oを発生させますが、HTTP部分のみを対象とします。これは、要求を処理している間に受信HTTPデータを受信できることを意味します。ただし、処理中にブロックするすべてのI/Oは、まだブロックしています。 MySQLの応答が遅い場合、Thin要求キューがいっぱいになります。

「より多くの」イベントが発生したウェブサーバーの場合は、Rainbowsを確認する必要があります。

+0

こんにちはSergio。私の歩行者はこれらの概念を理解しています。私はレールのためのmysql2の宝石はあまりにもIOを催したことを読んだ。 また、その場合、ワーカーベースのサーバーは常に優れていないでしょうか?私は前回走っていた25人の乗客とは対照的に、薄​​い2人のインスタンスのようにしか走っていない。 –

+0

@CoffeeBite:*** ***は非同期呼び出しを行うことができますが、それは自動ではないので、コードを書く必要があります。デフォルトでは同期しています。 –

+0

@CoffeeBite:「労働者はいつもより良くないだろう」 - わからない。私は自分でnginxの背後にある[Unicorn](http://unicorn.bogomips.org/)を使います。 NginxはHTTP I/Oを処理し、ユニコーンは要求を迅速に処理します。 –

関連する問題