web-dev-qa-db-ja.com

Ruby on Railsスケーラビリティ/パフォーマンス?

私はしばらくPHPを使用し、素晴らしいフレームワークであるCodeIgniterでそれをうまく使用しました。私は新しい個人プロジェクトを始めており、前回使用するものを考えていましたROR)PHPを使用しました。これは、RORが聞いたスケーラビリティの問題のためです。特にTwitter開発者の意見を読んだ後です。それ?

新しい言語を学びたいのですが、RORは興味深いようです。 PHPは仕事をやり遂げますが、誰もが知っているように、その構文と組織はfuいものであり、1つの大きなハックのように感じます。

71
ryeguy

ライアン・ドハティの答えを少し拡大するには...

私は日々の仕事のために静的に型付けされた言語(.NET/C#)で仕事をしています。また、副業としてRuby。現在の仕事の前は、 Ruby New York Times Syndicationサービスの仕事をしている開発会社。その前に、私はPHPで働いていました(ただし、かなり前に))。

私は単にこれを言うために言います:私はRails(そしてより一般的にはRuby)のパフォーマンス問題を経験しました、そして他のいくつかの選択肢と同様に。あなたは行かないでしょう自動的にスケーリングできるようにするには、ボトルネックを見つけるのに多大な労力と忍耐が必要です。

私たちが他の人や自分自身からも見たパフォーマンスの問題の大部分は、ORMレイヤーでのパフォーマンスの遅いクエリを処理していました。 Rails/ActiveRecordからRails/DataMapperに行き、最後にMerb/DMに行きました。各反復は、基礎となるフレームワークのために、より高速になりました。

キャッシングは、パフォーマンスに関して驚くべき驚異をもたらします。残念ながら、データをキャッシュできませんでした。キャッシュは、せいぜい5分ごとに事実上無効になります。サイトのほぼすべての部分が動的でした。そのため、できない場合は、おそらく私たちの経験から学ぶことができます。

データベースインデックスを真剣に微調整し、クエリが非常に愚かなことをしていないことを確認し、絶対に必要な数を超えるクエリを実行していないことを確認しなければなりませんでした。 1 + Nクエリの問題を意味します...

#1 query
Dog.find(:all).each do |dog|
   #N queries
   dog.owner.siblings.each do |sibling|
      #N queries per above N query!!
      sibling.pets.each do |pet|
         #Do something here
      end
   end
end

DataMapperは、上記の問題を処理する優れた方法です(1 + Nの問題はありません)が、さらに良い方法は、脳を使用して、そのようなクエリの実行を停止することです:D生のパフォーマンスでは、ほとんどのORMレイヤーは極端にカスタムなクエリを簡単に処理できないため、同様に手書きすることもできます。

また、常識的なこともしました。私たちは成長しているデータベースのために強力なサーバーを購入し、専用のボックスに移しました。また、大量の処理とデータのインポートを常に行わなければなりませんでした。処理をits自分のボックスにも移しました。また、データインポートユーティリティのためだけに、フリークスタック全体のロードを停止しました。絶対に必要なものだけを上品にロードしました(したがって、メモリのオーバーヘッドが減少します!).

まだわからない場合は...一般的に、Ruby/Rails/merbに関しては、outをスケーリングして、問題にハードウェアを投げる必要があります。しかし、最終的には、ハードウェアは安価です。それは見掛け倒しのコードの言い訳ではありませんが! :D

そして、これらの困難があっても、私がそれを助けることができれば、私は個人的に別のフレームワークでプロジェクトを開始することはありません。私はこの言語が大好きで、毎日その言語について継続的に学んでいます。 C#は高速ですが、C#からは得られません。

また、オープンソースのツール、言語での作業を開始するための低コスト、市場に出回って市場に出回っているかどうかを確認するための低コストを楽しんでいます。 ...

結局のところ、フレームワークの選択に関しては、毎日、何日も生き、呼吸し、食べ、眠りたいものがすべてです。 Microsoftの考え方が気に入ったら、.NETにアクセスしてください。オープンソースが必要でありながら構造が必要な場合は、Javaを試してください。動的言語を使用したいが、Rubyよりも少し多くの構造が必要な場合は、pythonを試してください。そして、あなたが優雅を望むなら、Ruby(私は子供、私は子供...法案に合う他の多くのエレガントな言語があります。炎戦争を始めようとしないこと:D)

地獄、それらすべてを試してみてください!上記の答えに同意する傾向がありますが、最適化を早期に心配することはフレームワークを選択すべきまたは選択すべきではない理由ですが、これが彼らの唯一の答えであることに同意しません。

要するに、はい、あなたが克服しなければならない困難がありますが、言語の優雅さ、私見はそれらの欠点をはるかに上回っています。

小説はすみませんが、パフォーマンスの問題で私はそこに行って戻ってきました。それcan克服される。怖がらせないでください。

160
Keith Hanson

RoRは多くの巨大なWebサイトで使用されていますが、any言語またはフレームワークと同様に、多数のユーザーに合わせて拡張するには優れたアーキテクチャ(dbスケーリング、キャッシュ、チューニングなど)が必要です。

RoRには、スケーリングを容易にするためのマイナーな変更がいくつかありましたが、魔法のようにスケーリングされるとは思わないでください。すべてのWebサイトには異なるスケーリングの問題があるため、スケーリングするにはいくつかの作業を行う必要があります。

27
Ryan Doherty

プロジェクトを成功に導く最高のチャンスを提供するテクノロジーを開発します-迅速な開発、簡単なデバッグ、簡単な展開、優れたツール、裏返しになっていることを知っています(新しい言語を学ぶことが目的でない限り)など。

あなたが月に数千万のユニークな人を得るならば、あなたはいつでも数人で雇うことができて、あなたがそうする必要があるなら異なる技術で書き直すことができます...

... レイク --キャッシュになります(ごめん-抵抗できません!!)

16
RichH

まず、Rails上のRubyは完全なWebアプリケーションフレームワークであるため、RailsをSymfony、CodeIgniter、またはCakePHPと比較する方が合理的です。 PHPまたはPHPフレームワークと比較して、Railsアプリケーションには、小さくてクリーンで読みやすいという利点があります。 PHPは小さな個人用ページに最適です(元々は「Personal Home Page」の略でした)が、Railsは完全なMVCフレームワークであり、大規模なサイトの構築に使用できます。

Rails上のRuby ない同等のPHPフレームワークよりも大きなスケーラビリティの問題。 RailsとPHPの両方は、同じ数のオブジェクトを操作する中程度の数のユーザー(10,000〜100,000)しかいない場合にうまく拡張できます。数千人のユーザーにとっては、古典的なモノリシックアーキテクチャで十分です。少しのM&M(MemcachedおよびMySQL)を使用すると、何百万ものオブジェクトを処理することもできます。 M&Mアーキテクチャは、MySQLサーバーを使用して書き込みを処理し、Memcachedを使用して高い読み込み負荷を処理します。従来のストレージパターンである、正規化されたリレーショナルテーブルを使用した単一のSQLサーバー(またはせいぜいSQL Master/Multiple Read Slaveセットアップ)は、非常に大規模なサイトでは機能しなくなりました。

Google、Twitter、Facebookのような数十億人のユーザーがいる場合、おそらく分散アーキテクチャの方が良いでしょう。アプリケーションを無制限に拡張したい場合は、何らかの安価な汎用ハードウェアを基盤として使用し、アプリケーションをサービスのセットに分割し、各コンポーネントまたはサービス自体をスケーラブルに保ち(すべてのコンポーネントをスケーラブルなサービスとして設計し)、適応しますアプリケーションのアーキテクチャ。次に、NoSQLデータベースや分散ハッシュテーブル(DHT)などの適切なスケーラブルなデータストアが必要になり、それらを操作するには洗練されたmap-reduceアルゴリズムが必要になり、SOA、外部サービス、メッセージングに対処する必要があります。 PHPもRailsもここでは魔法の弾丸を提供しません。

14
0x4a6f4672

RoRの内訳は、Alexaのトップ100でなければ、スケーラビリティの問題は発生しないということです。 Phusion、Passenger、またはMongrelを絞り出せない限り、共有ホスティングの安定性に関してさらに問題が発生します。

6
phresus

Twitterの人々が対処しなければならなかった問題を少し見てから、アプリをそのレベルに拡張する必要があるかどうかを自問してください。

とにかくRails、それが理にかなっていることを知っているからです。Twitterレベルのボリュームに到達すれば、パフォーマンスの最適化オプションを検討することができます。素敵な言語でそれらを適用します!

5
Mike Woodhouse

PHPとRORを比較することはできません。PHPはRubyとしてのスクリプト言語であり、RailsはCakePHPとしてのフレームワークです。
と述べました。Railsを強くお勧めします。アプリケーションは厳密にMVCパターンで編成であり、これは[〜#〜] must [〜# 〜]スケーラビリティ要件。 (PHPを使用すると、プロジェクト組織を自分で管理する必要がありました)。
しかし、スケーラビリティについてはRailsそれはMVCだけではありません。たとえば、データベースを使用してアプリケーションの開発を開始し、手間をかけずに(ほとんどの場合、ケース)、したがって、Railsアプリケーションは(ほぼ)データベース独立であると述べることができます。これはORM(データベースクエリを回避できる)であるため、他の多くのことができますもの。
(このビデオをご覧ください http://www.youtube.com/watch?v=p5EIrSM8dCA

2
Joe

キース・ハンソンの1 + Nの問題に関するスマートポイントにさらに情報を追加したかっただけです。

DataMapperは上記の問題を処理するための優れた方法です(1 + Nの問題はありません)が、さらに良い方法は、脳を使用してそのようなクエリの実行を停止することです。D生のパフォーマンスが必要な場合、ほとんどのORMレイヤーは非常にカスタムなクエリを簡単に処理できないため、手書きすることもできます。

DoctrineはPHPで最も人気のあるORMの1つです。 Doctrine Query Language(DQL)と呼ばれる言語を提供することにより、ORM固有のこの1 + N複雑性の問題に対処します。これにより、既存のモデル関係を使用するSQLのようなステートメントを記述できます。

$ q = Doctrine_Query :: Create()-> select(*)-> from(ModelA m)-> leftJoin(m.ModelB)-> execute()

2
Aree Cohen

このスレッドから、RORのスケーラビリティの問題は主に子オブジェクトの読み込みに関してORMが抱えている混乱、つまり上記の「1 + N」の問題に起因するという印象を受けています。ライアンが犬と飼い主に与えた上記の例では:

Dog.find(:all).each do |dog|
   #N queries
   dog.owner.siblings.each do |sibling|
      #N queries per above N query!!
      sibling.pets.each do |pet|
         #Do something here
      end
   end
end

実際には、単一のsqlステートメントを記述してすべてのデータを取得できます。また、そのデータをカスタム作成オブジェクトのDog.Owner.Siblings.Petsオブジェクト階層に「ステッチ」することもできます。しかし、誰かがそれを自動的に行うORMを書いて、上記の例が数百の可能性ではなく、DBへの1回のラウンドトリップと1つのSQLステートメントを引き起こすことができるでしょうか?まったく。それらのテーブルを1つのデータセットに結合してから、ロジックを実行して結合します。そのロジックを汎用化して、オブジェクトのセットを処理できるが、世界の終わりを処理できないようにするのは少し難しいです。最後に、テーブルとオブジェクトは、3つのカテゴリ(1:1、1:many、many:many)のいずれかでのみ相互に関連しています。誰もそのORMを構築したことはありません。

この特定クエリに対してどの子をロードするかをシステムに事前に指示する構文が必要です。これを行うには、RORの一部ではないLinqToSql(C#)の「熱心な」ロードを使用しますが、DBへの1回のラウンドトリップが発生する場合でも、依然として数百の個別のSQLステートメントが存在します現在設定されています。それはORMの歴史に関するものです。彼らはそれで間違った道を歩み始めただけで、私の意見では決して回復しませんでした。 「遅延読み込み」はほとんどのORMのデフォルトの動作です。つまり、子オブジェクトの言及ごとに別のラウンドトリップが発生しますが、これはおかしいです。次に、「イーガー」ロード-事前に子をロードします。これは、LinqToSqlの外で知っているすべてのものに静的に設定されます。つまり、どの子が常に特定のオブジェクトでロードします-コレクションをロードするときに常に同じ子がロードされるように犬の。

今回はこれらの子と孫をロードしたいという強い型付けの構文が必要です。すなわち、次のようなもの:

Dog.Owners.Include()
Dog.Owners.Siblings.Include()
Dog.Owners.Siblings.Pets.Include()

次のコマンドを発行できます。

Dog.find(:all).each do |dog|

ORMシステムは、結合する必要があるテーブルを認識してから、結果のデータをOM階層につなぎます。現在の問題でハードウェアを投げることができるのは確かですが、私は一般的には賛成ですが、ORM(つまり、Hibernate、Entity Framework、Ruby ActiveRecord)が単にすべきではない理由はありませんハードウェアは、1回のラウンドトリップと1つのSQLステートメントであるはずの、8回のラウンドトリップ、100 SQLステートメントのクエリからあなたを救い出しません。

1
Jeff