web-dev-qa-db-fra.com

Ruby on Rails scalabilité / performance?

J'ai utilisé PHP depuis un certain temps maintenant et je l'ai bien utilisé avec CodeIgniter, qui est un excellent cadre. Je commence un nouveau projet personnel et la dernière fois, je me demandais quoi utiliser (PHP vs ROR) J'ai utilisé PHP à cause des problèmes d'évolutivité que j'ai entendu ROR avoir, en particulier après avoir lu ce que les développeurs de Twitter avaient à dire à ce sujet. L'évolutivité est-elle toujours un problème dans ROR ou y a-t-il eu des améliorations à il?

Je voudrais apprendre une nouvelle langue et ROR semble intéressant. PHP fait le travail, mais comme tout le monde le sait, sa syntaxe et son organisation sont énormes et cela ressemble à un gros hack.

71
ryeguy

Pour développer un peu la réponse de Ryan Doherty ...

Je travaille dans un langage tapé de façon statique pour mon travail de jour (.NET/C #), ainsi que Ruby comme accessoire. Avant mon travail de jour actuel, j'étais le programmeur principal d'un Ruby travaillant pour le service de syndication du New York Times. Avant cela, je travaillais également en PHP aussi (bien qu'il y a très longtemps)).

Je dis cela simplement pour dire ceci: j'ai rencontré des problèmes de performances Rails (et plus généralement Ruby) de première main, ainsi que quelques autres alternatives. Comme Ryan le dit, vous n'allez pas pour le faire évoluer automatiquement pour vous. Il faut beaucoup de travail et de patience pour trouver vos goulots d'étranglement.

Une grande majorité des problèmes de performances que nous avons vus des autres et même de nous-mêmes traitaient de requêtes à exécution lente dans notre couche ORM. Nous sommes passés de Rails/ActiveRecord à Rails/DataMapper et enfin à Merb/DM, chaque itération obtenant plus de vitesse simplement en raison des frameworks sous-jacents.

La mise en cache fait des merveilles étonnantes pour les performances. Malheureusement, nous n'avons pas pu mettre nos données en cache. Notre cache serait effectivement invalidé toutes les cinq minutes au plus. Presque chaque bit de notre site était dynamique. Donc, si/quand vous ne pouvez pas faire cela, vous pouvez peut-être apprendre de notre expérience.

Nous avons dû finir par affiner sérieusement nos index de base de données, nous assurer que nos requêtes ne faisaient pas des choses très stupides, nous assurer que nous n'exécutions pas plus de requêtes que ce qui était absolument nécessaire, etc. Quand je dis "choses très stupides", je signifie le problème de requête 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 est un excellent moyen de gérer le problème ci-dessus (il n'y a pas de problème 1 + N avec ), mais une meilleure façon est d'utiliser votre cerveau et arrêtez de faire des requêtes comme celle-ci: D Lorsque vous avez besoin de performances brutes, la plupart des couches ORM ne gèrent pas facilement les requêtes extrêmement personnalisées, vous pouvez donc aussi bien les écrire à la main.

Nous avons également fait des choses sensées. Nous avons acheté un serveur costaud pour notre base de données en pleine croissance et l'avons déplacé dans sa propre boîte dédiée. Nous avons également dû faire des TONNES de traitement et d'importation de données en permanence. Nous avons également déplacé notre traitement sur sa propre boîte . Nous avons également arrêté de charger l'intégralité de notre pile de panique uniquement pour nos utilitaires d'importation de données. Nous avons chargé avec goût uniquement ce dont nous avions absolument besoin (réduisant ainsi la surcharge de mémoire!).

Si vous ne pouvez pas déjà le dire ... généralement, en ce qui concerne Ruby/Rails/merb, vous devez mettre à l'échelle , en jetant du matériel au problème. Mais au final, le matériel est bon marché; bien que ce ne soit pas une excuse pour du code de mauvaise qualité! :RÉ

Et même avec ces difficultés, je ne commencerais jamais personnellement des projets dans un autre cadre si je pouvais l'aider. Je suis amoureux de la langue et j'en apprends continuellement chaque jour. C'est quelque chose que je n'obtiens pas de C #, bien que C # soit plus rapide.

J'apprécie également les outils open source, le faible coût pour commencer à travailler dans la langue, le faible coût pour simplement sortir quelque chose et essayer de voir s'il est commercialisable, tout en travaillant dans une langue qui souvent peut être élégante et belle ...

En fin de compte, tout dépend de ce que vous voulez vivre, respirer, manger et dormir au jour le jour quand il s'agit de choisir votre cadre. Si vous aimez la façon de penser de Microsoft, allez .NET. Si vous voulez de l'open source mais que vous voulez toujours une structure, essayez Java. Si vous voulez avoir un langage dynamique et avoir encore un peu plus de structure que Ruby, essayez python. Et si vous voulez de l'élégance, essayez Ruby (I kid, I kid ... il existe de nombreuses autres langues élégantes qui conviennent). N'essayez pas de déclencher une guerre des flammes: D)

Enfer, essayez-les tous! J'ai tendance à être d'accord avec les réponses ci-dessus que s'inquiéter des optimisations au début n'est pas la raison pour laquelle vous devriez ou ne devriez pas choisir un cadre, mais je ne suis pas d'accord pour dire que c'est leur seule réponse.

Donc, en bref, oui, il y a des difficultés que vous devez surmonter, mais l'élégance de la langue, à mon humble avis, l'emporte de loin sur ces lacunes.

Désolé pour le roman, mais j'y suis allé avec des problèmes de performances. Il peut être surmonté. Alors ne vous laissez pas effrayer.

160
Keith Hanson

RoR est utilisé avec de nombreux sites Web énormes, mais comme avec le langage ou le framework any, il faut une bonne architecture (mise à l'échelle de la base de données, mise en cache, réglage, etc.) pour s'adapter à un grand nombre d'utilisateurs.

Il y a eu quelques changements mineurs au RoR pour le rendre plus facile à évoluer, mais ne vous attendez pas à ce qu'il évolue comme par magie pour vous. Chaque site Web a des problèmes de mise à l'échelle différents, vous devrez donc travailler pour le faire évoluer.

27
Ryan Doherty

Développez la technologie qui donnera à votre projet les meilleures chances de succès - développement rapide, débogage facile, déploiement facile, bons outils, vous le savez à fond (sauf s'il s'agit d'apprendre une nouvelle langue), etc.

Si vous obtenez des dizaines de millions d'uniques par mois, vous pouvez toujours embaucher quelques personnes et réécrire dans une technologie différente si vous en avez besoin ...

... vous serez râtea - ing dans le cache (désolé - je n'ai pas pu résister !!)

16
RichH

Tout d'abord, il serait peut-être plus logique de comparer Rails à Symfony, CodeIgniter ou CakePHP, car Ruby on Rails = est un framework d'application web complet. Comparé à PHP ou PHP, Rails offrent les avantages qu'elles sont petit, propre et lisible. PHP est parfait pour les petites pages personnelles (à l'origine, il signifiait "Personal Home Page"), tandis que Rails est un Structure MVC qui peut être utilisée pour construire de grands sites.

Ruby on Rails n'a pas un problème d'évolutivité plus grand que les frameworks comparables PHP. Les deux Rails et PHP évoluera bien si vous n'avez qu'un nombre modéré d'utilisateurs (10 000 à 100 000) qui opèrent sur un nombre similaire d'objets. Pour quelques milliers d'utilisateurs, une architecture monolithique classique sera suffisante. Avec un peu de M&M (Memcached et MySQL), vous pouvez également gérer des millions d'objets. L'architecture M&M utilise un serveur MySQL pour gérer les écritures et Memcached pour gérer les charges de lecture élevées. Le modèle de stockage traditionnel, un seul serveur SQL utilisant des tables relationnelles normalisées ( ou au mieux une configuration SQL Master/Multiple Read Slave), ne fonctionne plus pour les très grands sites.

Si vous avez des milliards d'utilisateurs comme Google, Twitter et Facebook, alors une architecture distribuée sera probablement meilleure. Si vous voulez vraiment faire évoluer votre application sans limite, utilisez une sorte de matériel de base bon marché comme base, divisez votre application en un ensemble de services, gardez chaque composant ou service évolutif lui-même (concevez chaque composant comme un service évolutif) et adaptez l'architecture de votre application. Ensuite, vous aurez besoin de banques de données évolutives appropriées comme les bases de données NoSQL et les tables de hachage distribuées (DHT), vous aurez besoin d'algorithmes de réduction de carte sophistiqués pour travailler avec eux, vous devrez traiter avec SOA, les services externes et la messagerie. Ni PHP ni Rails n'offre pas de solution magique ici).

14
0x4a6f4672

Ce qui se décompose avec RoR, c'est que si vous n'êtes pas dans le top 100 d'Alexa, vous n'aurez aucun problème d'évolutivité. Vous aurez plus de problèmes de stabilité sur l'hébergement partagé, sauf si vous pouvez éliminer Phusion, Passenger ou Mongrel.

6
phresus

Prenez un peu de temps pour examiner les problèmes auxquels les utilisateurs de Twitter ont dû faire face, puis demandez-vous si votre application devra évoluer à ce niveau.

Ensuite, construisez-le dans Rails de toute façon, parce que vous savez que cela a du sens. Si vous accédez à des volumes au niveau de Twitter, vous serez en mesure de considérer les options d'optimisation des performances. Au moins vous ' Je vais les appliquer dans une belle langue!

5
Mike Woodhouse

Vous ne pouvez pas comparer PHP et ROR, PHP est un langage de script comme Ruby et Rails est un cadre comme CakePHP.
A déclaré que, je vous suggère fortement Rails, car vous aurez une application strictement organisée en modèle MVC , et ceci est un [~ # ~] doit [~ # ~] pour vos besoins d'évolutivité. (En utilisant PHP vous deviez vous occuper de l'organisation du projet par vous-même).
Mais pour ce qui est de l'évolutivité, Rails ce n'est pas seulement MVC: Par exemple, vous pouvez commencer à développer votre application avec une base de données, en la modifiant sur la route sans effort (dans le la plupart des cas), nous pouvons donc affirmer qu'une application Rails est (presque) indépendante de la base de données parce que c'est ORM (qui vous permet d'éviter les requêtes de base de données), vous pouvez faire beaucoup d'autres choses.
(regardez cette vidéo http://www.youtube.com/watch?v=p5EIrSM8dCA )

2
Joe

Je voulais juste ajouter plus d'informations au point intelligent de Keith Hanson sur le problème 1 + N où il déclare:

DataMapper est un excellent moyen de gérer le problème ci-dessus (il n'y a pas de problèmes 1 + N avec lui), mais un meilleur moyen est d'utiliser votre cerveau et d'arrêter de faire des requêtes comme ça: D Lorsque vous avez besoin de performances brutes, la plupart des ORM les couches ne géreront pas facilement les requêtes extrêmement personnalisées, vous pouvez donc aussi bien les écrire à la main.

La doctrine est l'un des ORM les plus populaires pour PHP. Il résout ce problème de complexité 1 + N intrinsèque aux ORM en fournissant un langage appelé Doctrine Query Language (DQL). Cela vous permet d'écrire des instructions de type SQL qui utilisent vos relations de modèle existantes.

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

2
Aree Cohen

J'ai l'impression de ce fil que les problèmes d'évolutivité de ROR se résument principalement au désordre dans lequel les ORM sont en ce qui concerne le chargement des objets enfants - c'est-à-dire le problème "1 + N" mentionné ci-dessus. Dans l'exemple ci-dessus que Ryan a donné avec des chiens et des propriétaires:

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

Vous pouvez en fait écrire une seule instruction SQL pour obtenir toutes ces données, et vous pouvez également `` assembler '' ces données dans la hiérarchie d'objet Dog.Owner.Siblings.Pets de vos objets écrits sur mesure. Mais quelqu'un pourrait-il écrire un ORM qui l'a fait automatiquement, afin que l'exemple ci-dessus entraîne un aller-retour unique vers la base de données et une seule instruction SQL, au lieu de potentiellement des centaines? Totalement. Joignez simplement ces tables en un seul ensemble de données, puis faites un peu de logique pour les assembler. Il est un peu difficile de rendre cette logique générique afin qu'elle puisse gérer n'importe quel ensemble d'objets, mais pas la fin du monde. En fin de compte, les tableaux et les objets ne sont liés les uns aux autres que dans l'une des trois catégories (1: 1, 1: plusieurs, plusieurs: plusieurs). C'est juste que personne n'a jamais construit cet ORM.

Vous avez besoin d'une syntaxe qui indique au système à l'avance quels enfants vous voulez charger pour cette requête particulière. Vous pouvez en quelque sorte le faire avec le chargement `` impatient '' de LinqToSql (C #), qui ne fait pas partie de ROR, mais même si cela se traduit par un aller-retour vers la base de données, il s'agit toujours de centaines d'instructions SQL distinctes comme il l'a fait. actuellement mis en place. C'est vraiment plus sur l'histoire des ORM. Ils ont juste commencé sur le mauvais chemin avec cela et ne se sont jamais vraiment remis de mon opinion. Le "chargement paresseux" est le comportement par défaut de la plupart des ORM, c'est-à-dire qu'il entraîne un autre aller-retour pour chaque mention d'un objet enfant, ce qui est fou. Ensuite, avec un chargement "désireux" - charger les enfants à l'avance, qui est configuré de manière statique dans tout ce que je connais en dehors de LinqToSql - c'est-à-dire quels enfants chargent toujours avec certains objets - comme si vous auriez toujours besoin des mêmes enfants chargés lorsque vous chargez une collection des chiens.

Vous avez besoin d'une sorte de syntaxe fortement typée disant que cette fois, je veux charger ces enfants et petits-enfants. C'est-à-dire quelque chose comme:

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

alors vous pouvez lancer cette commande:

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

Le système ORM saurait quelles tables il doit joindre, puis assemblerait les données résultantes dans la hiérarchie OM. Il est vrai que vous pouvez jeter du matériel sur le problème actuel, ce que je suis généralement en faveur, mais ce n'est pas une raison pour laquelle l'ORM (c.-à-d. Hibernate, Entity Framework, Ruby ActiveRecord) ne devrait pas simplement Le matériel ne vous libère vraiment pas d'une requête d'instruction de 100 aller-retour et 100 SQL qui aurait dû être un aller-retour et une instruction SQL.

1
Jeff