2011-11-16 18 views
8

さまざまなバージョンのRubyとレールのスレッドの安全性とパフォーマンスについて、私はウェブ上で数多くの資料を読んできました。スレッドセーフな非同期Railsアプリケーションを配備するには?

実際に非同期Railsアプリケーションを配備する方法は、ディスカッションから奇妙に欠落しているようです。アプリ内のスレッドと同期の話をすると、人々は最適化する二つのものがあります。

  1. 以前の要求がIO上で待っている間に、最小限のRAMの使用量
  2. は、新しい要求にサービスを提供することができることで、すべてのCPUコアを利用することが

ポイント1は、人々が(正しく)JRubyについて興奮するところです。

TheController < ActionController::Base 
    def fast 
    render :text => "hello" 
    end 

    def slow 
    render :text => User.count.to_s 
    end 
end 

fastは何のIOを持っていないし、何百、何千も1秒あたりの要求、およびslowを提供することができます:この質問のために私は2

が、これは私のアプリで唯一のコントローラであると言う点を最適化しようとしていますネットワークを介して要求を送信し、作業が完了するのを待ってから、ネットワーク経由で応答を受信する必要があります。したがって、fastよりもはるかに遅いです。

したがって、slowへの要求がIOで待機している間に、fastへの何百もの要求を満たすことが理想的です。

ウェブ上での議論に欠けているように見えるのは、スタックのどのレイヤーがこの並行性を有効にするかということです。 thinは--threadedフラグを持っています。これは "Rackアプリケーションをスレッド[experimental]で呼び出します" - それは着信要求ごとに新しいスレッドを開始しますか?永続的なスレッド内にラックアプリケーションのインスタンスをスプールアップし、着信要求を待つか?

唯一の方法は薄いのですか他にはありますか?ルビランタイムはポイント2を最適化するために重要ですか?

+0

あなたのルビーバージョンがポイント2に関して多くの意見を持っているのではないかと疑いがあります。これは、サーバの並行処理の実装と、レール自体がどのように組み合わされているかによります。 – providence

答えて

6

適切なアプローチは、あなたのslowメソッドが何をしているかに大きく依存します。

完全な世界では、sinatra-synchrony宝石のようなものを使用して、ファイバ内の各要求を処理できます。ファイバーの最大数によってのみ制限されます。残念ながら、ファイバー上のスタックサイズはhardcodedであり、Railsアプリケーションではオーバーランするのは簡単です。さらに、私は、非同期IOが開始された後の自動降伏のために、ファイバのデバッグの難しさに関するいくつかのホラーストーリーを読んだ。繊維を使用する場合でも、競争条件は可能です。現在、ファイバー化されたRubyは、少なくともウェブアプリケーションのフロントエンドでは少しばかりのゲットーです。

コード変更を必要としない、より実用的な解決策は、Rainbowsなどのワーカースレッドのプールを持つRackサーバーを使用することです。またはプーマ。私はThinの--threadedフラグが新しいスレッドの各要求を処理すると信じていますが、ネイティブOSスレッドをスピンアップするのは安価ではありません。十分に高いプールサイズを設定したスレッドプールを使用する方がよいでしょう。 Railsでは、生産中にconfig.threadsafe!を設定することを忘れないでください。

コードを変更しても問題ない場合は、コンスタンチンハースの優れたtalk on real-time Rackをチェックできます。彼は、EventMachine::Deferrableクラスを使用して、Rackが構築されている従来の要求/応答サイクルの外で応答を生成する方法について説明します。これは本当にきれいですが、コードを非同期スタイルで書き直す必要があります。

CrampGoliathもご覧ください。これらは、slowメソッドを別のRackアプリに実装することができますが、Cramp/Goliathハンドラでも動作するようにコードを書き直す必要があります。

Rubyランタイムについてのご質問は、が行っている作業にもよります。 CPUが重い計算をしている場合、GILが問題を起こすリスクがあります。もしあなたがIOをしているのであれば、GIL になりません。 (私はGILをブロックしている古いmysql宝石の問題を読んだと信じているからです。)

個人的には、私はバックエンドのマッシュアップWebサービスでsinatra-synchronyを使って成功しました。私はいくつかの外部Webサービスへのリクエストを並行して発行し、それらのすべてが返るのを待つことができます。一方、フロントエンドのRailsサーバはスレッドプールを使用し、バックエンドに直接リクエストを行います。完璧ではありませんが、今は十分に機能しています。

関連する問題