2010-01-25 29 views
2

Je travaille sur une application Rails qui doit périodiquement effectuer un grand nombre d'opérations liées aux E/S. Ces opérations peuvent être effectuées de manière asynchrone. Par exemple, une fois par jour, pour chaque utilisateur, le système doit interroger Salesforce.com afin d'extraire la liste de comptes actuelle de l'utilisateur (entreprises) qu'il suit. Cela entraîne des nombres énormes (potentiellement> 100k) de petites requêtes.Exécution d'un grand nombre d'opérations asynchrones liées aux E/S dans Rails

Notre approche actuelle consiste à utiliser ActiveMQ avec ActiveMessaging. Chacun de nos utilisateurs est placé dans une file d'attente sous la forme d'un message différent. Ensuite, le consommateur extrait l'utilisateur de la file d'attente, interroge Salesforce.com et traite les résultats. Mais cette approche nous donne une performance horrible. Dans un processus de polling unique, nous ne pouvons traiter qu'un seul utilisateur à la fois. Ainsi, les requêtes Salesforce.com sont sérialisées. À moins d'exécuter littéralement des centaines de processus d'interrogation, nous ne pouvons pas arriver à saturer le serveur en cours d'exécution.

Nous examinons EventMachine comme alternative. Il a l'avantage de nous permettre de lancer simultanément un grand nombre de requêtes Salesforce.com dans un seul processus EventMachine. Ainsi, nous obtenons un grand parallélisme et l'utilisation de notre serveur.

Mais il y a deux problèmes avec EventMachine. 1) Nous perdons la livraison fiable des messages que nous avions avec ActiveMQ/ActiveMessaging. 2) Nous ne pouvons pas facilement redémarrer périodiquement notre EventMachine pour réduire l'impact de la croissance de la mémoire. Par exemple, avec ActiveMessaging, nous avons un travail cron qui redémarre le poller une fois par jour, ce qui peut être fait sans craindre de perdre des messages. Mais avec EventMachine, si nous recommençons le processus, nous pourrions littéralement perdre des centaines de messages en cours. La seule façon que je peux voir autour de ceci est de construire une couche de livraison de persistance/fiable sur EventMachine.

Est-ce que quelqu'un a une meilleure approche? Quel est le meilleur moyen d'exécuter de manière fiable un grand nombre d'opérations asynchrones liées aux E/S?

+0

La solution proposée doit-elle fonctionner sur plusieurs cœurs ou boîtiers? En d'autres termes, un seul thread serait-il lié à l'unité centrale? –

Répondre

2

Je maintiens ActiveMessaging, et je pensais aussi aux problèmes d'un poller multithread, mais peut-être pas à la même échelle que vous êtes. Je vais vous donner mes pensées ici, mais je suis également heureux de discuter plus loin de la liste de messagerie active, ou par e-mail si vous le souhaitez.

Une astuce est que l'interrogateur n'est pas la seule partie sérialisée de ceci. Les abonnements STOMP, si vous faites le client -> ack afin d'éviter de perdre des messages sur l'interruption, recevront seulement un nouveau message sur une connexion donnée quand le message précédent a été reçu. Fondamentalement, vous ne pouvez avoir qu'un seul message travaillé à la fois par connexion. Donc, pour continuer à utiliser un courtier, l'astuce consistera à ouvrir de nombreuses connexions/abonnements de courtier en même temps. Le poller actuel est assez lourd pour cela, car il charge un env de rails entier par poller, et un poller est une connexion. Mais il n'y a rien de magique dans le polling actuel, je pourrais imaginer écrire un poller en tant que client de machine événementielle qui est implémenté pour créer de nouvelles connexions au courtier et recevoir plusieurs messages à la fois. Dans mes propres expériences ces derniers temps, j'ai envisagé d'utiliser Ruby Enterprise Edition et d'avoir un thread maître qui forge de nombreux threads de travail de polling afin de bénéficier de l'empreinte mémoire réduite (tout comme le fait le passager), mais je pense que le tour EM pourrait fonctionner aussi bien. Je suis aussi un admirateur du projet Resque, bien que je ne sache pas qu'il serait mieux de passer à l'échelle pour de nombreux travailleurs - je pense que les travailleurs pourraient être plus légers.

http://github.com/defunkt/resque

2

Je l'ai utilisé avec AMQP RabbitMQ d'une manière qui fonctionne pour vous.Puisque ActiveMQ implémente AMQP, j'imagine que vous pouvez l'utiliser de la même manière. Je n'ai pas utilisé ActiveMessaging, qui, bien que cela semble être un paquet génial, peut ne pas convenir à ce cas d'utilisation.

Voilà comment vous pouvez le faire, en utilisant AMQP:

  • processus Rails Ayant envoyer un message disant « Obtenir des informations pour l'utilisateur i ».
  • Le consommateur retire ce message de la file d'attente de messages, en veillant à spécifier que le message nécessite qu'un 'ack' soit définitivement retiré de la file d'attente. Cela signifie que si le message n'est pas reconnu comme traité, il est finalement renvoyé dans la file d'attente pour un autre utilisateur.
  • Le worker renvoie ensuite le message dans les milliers de petites requêtes à SalesForce.
  • Lorsque toutes ces demandes ont été renvoyées avec succès, un autre rappel doit être déclenché pour récupérer le message d'origine et renvoyer un "message récapitulatif" contenant toute l'information pertinente à la demande d'origine. La clé utilise une file d'attente de messages qui vous permet de reconnaître le traitement réussi d'un message donné, et de vous assurer de le faire uniquement lorsque le traitement approprié est terminé.
  • Un autre opérateur extrait ce message de la file d'attente et effectue le travail synchrone approprié. Puisque tous les bits induisant de la latence ont déjà fonctionné, j'imagine que cela devrait être bon.

Si vous utilisez (C) Ruby, essayez de ne jamais combiner des éléments synchrones et asynchrones en un seul processus. Un processus doit soit faire tout via Eventmachine, sans bloquer le code, ou seulement parler à un processus Eventmachine via une file d'attente de messages. De plus, écrire du code asynchrone est incroyablement utile, mais aussi difficile à écrire, difficile à tester et sujet aux bogues. Faites attention. Enquêter sur l'utilisation d'une autre langue ou d'un autre outil, le cas échéant.

1

Existe aussi « crampe » et « haricot magique »

0

Quelqu'un m'a envoyé le lien suivant: http://github.com/mperham/evented/tree/master/qanat/. C'est un système similaire à ActiveMessaging, sauf qu'il est construit sur EventMachine. C'est presque exactement ce dont nous avons besoin. Le seul problème est qu'il semble fonctionner uniquement avec la file d'attente d'Amazon, pas ActiveMQ.