23

PHPはシェアードナッシング環境で実行されます。つまり、このコンテキストでは、すべてのWebリクエストがクリーンな環境で実行されます。別の永続層(ファイルシステム、データベースなど)を経由しない限り、別のリクエストのデータにアクセスすることはできません。

Ruby on Railsはどうですか?別々のリクエストが同じクラス変数にアクセスする可能性があると述べているブログ投稿を読んだばかりです。

これはおそらくWebサーバーに依存していると思いました。 MongrelのFAQには、Mongrelはリクエストごとに1つのスレッドを使用すると記載されており、シェアードナッシング環境を示唆しています。FAQには、RoRはスレッドセーフではないと記載されています。これは、新しいリクエストが前のリクエストから作成されたメモリ内オブジェクトを再利用しない限り、RoRが共有環境に存在しないことをさらに示唆しています。

明らかに、これにはセキュリティに大きな影響があります。だから私は2つの質問があります:

  1. RoR環境は共有されていますか?何もありませんか?
  2. RoRが共有環境で実行されている(または状況によっては実行される可能性がある)場合、どの変数やその他のデータストレージについて心配する必要がありますか?

更新:さらに明確にします。 Javaサーブレットコンテナでは、複数のリクエストにまたがって存続するオブジェクトを持つことができます。これは通常、複数のユーザーがアクセスできるデータのキャッシュ、データベース接続などのために行われます。PHPでは、これはアプリケーションレイヤーでは実行できず、Memcachedなどの別の永続レイヤーで実行する必要があります。したがって、2つの質問は次のとおりです。RoRはどのシナリオ(PHPまたはJava)に似ていますか、Javaのように、どのデータ型が複数の要求にわたって持続しますか?

4

4 に答える 4

35

要するに:

  1. いいえ、Railsはシェアードナッシング環境で実行されることはありません。
  2. クラス変数クラスインスタンス変数については妄想してください。

長いバージョン:

Railsプロセスは、フレームワークとアプリケーションをロードすることでライフサイクルを開始します。これらは通常、単一のスレッドのみを実行し、その存続期間中に多くの要求を処理します。したがって、リクエストは厳密に順番にディスパッチされます。

それにもかかわらず、すべてのクラスはリクエスト間で存続します。これは、クラスおよびメタクラス(クラス変数やクラスインスタンス変数など)から参照されるすべてのオブジェクトがリクエスト間で共有されることを意味します。これは、たとえば、クラス@var ||= expensive_calculationメソッドのメソッド( )をメモ化しようとした場合に、現在のリクエスト中にのみ持続することを期待して、あなたを噛む可能性があります。実際には、計算は最初のリクエストでのみ実行されます。

表面的には、キャッシュ、またはリクエスト間の永続性に依存するその他の動作を実装するのが良いように思われるかもしれません。通常、そうではありません。これは、ほとんどのデプロイメント戦略が、独自のシングルスレッドの性質に対抗するために複数のRailsプロセスを使用するためです。遅いデータベースクエリを待っている間にすべてのリクエストをブロックするのはクールではないので、簡単な方法はより多くのプロセスを生成することです。当然、これらのプロセスは何も共有しません(おそらく、気付かないメモリを除いて)。リクエスト中にクラス変数またはクラスインスタンス変数にデータを保存すると、これに悩まされる可能性があります。そして、どういうわけか、ものが存在しているように見えることもあれば、なくなっているように見えることもあります。(実際には、もちろん、データは一部に存在する場合と存在しない場合がありますプロセス、および他の人には存在しません)。

一部のデプロイメント構成(特にJRuby + Glassfish)、実際にはマルチスレッドです。Railsはスレッドセーフなので、処理できます。ただし、アプリケーションはスレッドセーフではない可能性があります。すべてのコントローラーインスタンスは、各リクエストの後に破棄されますが、ご存知のとおり、クラスは共有されます。これは、クラス変数またはクラスインスタンス変数で情報を渡す場合に問題になる可能性があります。同期方法を適切に使用しないと、競合状態に陥る可能性があります。


補足として:Rubyのスレッド実装は不完全であるため、Railsは通常シングルスレッドプロセスで実行されます。幸い、Ruby1.9の方が少し良くなっています。そして、JRubyの方がはるかに優れています。

これらのRuby実装の人気が高まるにつれ、マルチスレッドRailsデプロイメント戦略の人気と数も増える可能性があります。マルチスレッドのリクエストディスパッチをすでに念頭に置いてアプリケーションを作成することをお勧めします。

于 2009-06-22T22:51:50.743 に答える
6

これは、共有オブジェクトの変更に注意しないとどうなるかを示す比較的単純な例です。

  1. 新しいRailsプロジェクトを作成します。rails test

  2. 新しいファイルlib/misc.rbを作成し、次のように配置します。

    class Misc
      @xxx = 'Hello'
      def Misc.contents()
        return @xxx
      end
    end
    
  3. 新しいコントローラーを作成します。ruby script/generate controller Posts index
  4. app/views/posts/index.html.erbこのコードを含むように変更します。

    <%
      require 'misc'; y = Misc.contents() ; y << ' (goodbye) '
    %>
    <pre><%= y %></pre>
    

    (これは、暗黙的に共有されるオブジェクトを変更する場所です。)

  5. RESTfulルートをに追加しconfig/routes.rbます。
  6. サーバーを起動し、ページを数回ruby script/serverロードします。/posts連続するページをリロードするたびに、文字列の数が( goodbye)1つずつ増えていきます。
于 2010-02-08T18:08:00.363 に答える
3

Passengerを使用した平均的なデプロイでは、複数のアプリプロセスがあり、それらの間で何も共有していませんが、各プロセス内のクラスは、リクエスト間で(静的)状態を維持しています。ただし、リクエストごとに、コントローラーの新しいインスタンスが作成されます。

これを、別個の共有状態環境のクラスターと呼ぶことができます。

Javaの例えを使用するには、キャッシングを実行して、要求ごとに機能させることができます。すべての要求で使用可能になるとは限りません。

于 2009-06-22T23:22:38.653 に答える
2

シェアード-何も良い考えではない場合があります。ただし、大規模なアプリケーションフレームワーク、大規模なドメインモデル、およびすべてのリクエストで大量の構成をロードする必要がある場合はそうではありません。

効率を上げるために、Railsは一部のデータをメモリ内で利用できるようにして、アプリケーションの存続期間中、すべてのリクエスト間で共有できるようにします。このデータのほとんどは読み取り専用であるため、心配する必要はありません。

アプリを作成するときは、共有オブジェクト(たとえば、同時実行制御が優れた状態ですぐに使用できるデータベースを除く)への書き込みを避けてください。問題はありません。

于 2009-06-22T04:35:19.647 に答える