Rails est-il partagé-rien ou des requêtes distinctes peuvent-elles accéder aux mêmes variables d'exécution?

StackOverflow https://stackoverflow.com/questions/1025432

Question

PHP s'exécute dans un environnement sans partage, ce qui signifie que chaque requête Web est exécutée dans un environnement propre. Vous ne pouvez accéder aux données d'une autre demande que via une couche de persistance distincte (système de fichiers, base de données, etc.).

Qu'en est-il de Ruby on Rails? Je viens de lire un article de blog indiquant que des requêtes distinctes puissent accéder à la même variable de classe.

Il m'est apparu que cela dépend probablement du serveur Web. La la FAQ de Mongrel indique que Mongrel utilise un fil de discussion par demande, ce qui suggère un environnement sans partage. La FAQ ajoute que RoR n’est pas thread-safe, ce qui laisse supposer qu’il n’existerait pas dans un environnement partagé à moins qu’une nouvelle requête ne réutilise les objets en mémoire créés à partir de la requête précédente.

Évidemment, cela a d’énormes ramifications en matière de sécurité. J'ai donc deux questions:

  1. L'environnement RoR est-il partagé-rien?
  2. Si RoR est exécuté (ou peut être exécuté dans certaines circonstances) dans un environnement partagé, quelles variables et quel stockage de données dois-je être paranoïaque?

Mise à jour: je clarifierai davantage. Dans un conteneur de servlets Java, vous pouvez avoir des objets qui persistent dans plusieurs requêtes. Cela est généralement fait pour la mise en cache de données auxquelles plusieurs utilisateurs auraient accès, les connexions à la base de données, etc. En PHP, cela ne peut pas être fait au niveau de la couche application, cela doit être fait dans une couche de persistance séparée comme Memcached. La double question est donc la suivante: quel scénario ressemble à RoR (PHP ou Java) et si, comme Java, les types de données quels persistent-ils dans plusieurs requêtes?

Était-ce utile?

La solution

En bref:

  1. Non, Rails Never s'exécute dans un environnement sans partage.
  2. Soyez paranoïaque à propos des variables de classe et des variables d'instance de classe .

La version la plus longue:

Les processus Rails commencent leur cycle de vie en chargeant le framework et l’application. Ils n'exécutent généralement qu'un seul thread, ce qui traitera de nombreuses demandes au cours de sa vie. Les requêtes seront donc envoyées strictement en séquence .

Néanmoins, toutes les classes persistent dans les demandes. Cela signifie que tout objet référencé à partir de vos classes et métaclasses (telles que les variables de classe et les variables d'instance de classe) sera partagé entre les demandes. Cela risque de vous piquer , par exemple, si vous essayez de mémoriser des méthodes ( @var || =calcul coûtant ) dans vos méthodes de classe , dans l'attente de celles-ci. ne persistera que pendant la demande en cours. En réalité, le calcul ne sera effectué qu'à la première demande.

En apparence, il peut sembler intéressant d’implémenter la mise en cache ou tout autre comportement dépendant de la persistance d’une requête à l’autre. En règle générale, ce n'est pas. En effet, la plupart des stratégies de déploiement utilisent plusieurs processus Rails pour contrer leur propre nature à thread unique. Il n’est tout simplement pas cool de bloquer toutes les requêtes en attendant une requête de base de données lente. Le moyen le plus simple est donc de générer davantage de processus. Naturellement, ces processus ne partagent rien (excepté peut-être une mémoire que vous ne remarquerez pas). Vous risquez de vous faire mal si vous enregistrez des éléments dans vos variables de classe ou vos variables d'instance de classe lors de requêtes . Ensuite, d’une manière ou d’une autre, le matériel semble parfois être présent et parfois, il semble être parti. (En réalité, bien sûr, les données peuvent être présentes ou non dans certains processus , et absentes dans d’autres).

Certaines configurations de déploiement (notamment JRuby + Glassfish) sont en fait multithreads. Rails est thread-safe, il peut donc y faire face. Mais votre application peut ne pas être thread-safe. Toutes les instances de contrôleur sont supprimées après chaque demande, mais comme nous le savons, les classes sont partagées. Vous risquez de vous faire mal si vous transmettez des informations dans des variables de classe ou des variables d'instance de classe. Si vous n’utilisez pas correctement les méthodes de synchronisation, vous risquez de vous retrouver dans l’enfer.

Remarque secondaire: Rails est généralement exécuté dans des processus mono-threadés, car l'implémentation de threads de Ruby est très mauvaise. Heureusement, les choses vont un peu mieux dans Ruby 1.9. Et un lot meilleur à JRuby.

Avec la popularité croissante de ces deux implémentations de Ruby, il semble probable que les stratégies de déploiement multithreads de Rails gagneront également en popularité et en nombre. C'est une bonne idée d'écrire votre application en gardant déjà à l'esprit l'envoi de requêtes multithread.

Autres conseils

Voici un exemple relativement simple qui illustre ce qui peut arriver si vous ne faites pas attention à la modification d'objets partagés.

  1. Créez un nouveau projet Rails: test de rails

  2. Créez un nouveau fichier lib / misc.rb et mettez-y ceci:

    class Misc
      @xxx = 'Hello'
      def Misc.contents()
        return @xxx
      end
    end
    
  3. Créer un nouveau contrôleur: script ruby ??/ générer un contrôleur Messages index
  4. Modifiez app / views / posts / index.html.erb pour qu'il contienne ce code:

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

    (C'est ici que nous modifions l'objet implicitement partagé.)

  5. Ajoutez des routes RESTful à config / routes.rb .
  6. Démarrez le serveur ruby ??script / serveur et chargez la page / posts à plusieurs reprises. Vous verrez le nombre de chaînes (au revoir) augmenter d'une unité à chaque rechargement de page.

Dans votre déploiement moyen avec Passenger, vous avez probablement plusieurs processus d'application qui ne partagent rien entre eux, à l'exception des classes de chaque processus qui conservent leur état (statique) de requête en requête. Cependant, chaque requête crée une nouvelle instance de vos contrôleurs.

Vous pouvez appeler cela un cluster d'environnements à état partagé distincts.

Pour utiliser votre analogie Java, vous pouvez effectuer la mise en cache et la faire fonctionner de requête en requête. Vous ne pouvez pas en déduire qu'elle sera disponible sur toutes les requêtes.

Partagé-rien est parfois une bonne idée. Mais pas lorsque vous devez charger une infrastructure d'application volumineuse, un modèle de domaine étendu et une grande quantité de configuration à chaque demande.

Par souci d'efficacité, Rails conserve certaines données disponibles en mémoire à partager entre toutes les demandes pendant la durée de vie d'une application. La plupart de ces données sont en lecture seule. Ne vous inquiétez donc pas.

Lorsque vous écrivez votre application, évitez d'écrire dans les objets partagés (à l'exception de la base de données, par exemple, qui est prête à l'emploi avec un bon contrôle de la concurrence) et tout devrait bien se passer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top