Je viens de lire cet article , et je suis confus.
Imaginons une application Web et une application distincte agissant en tant que "travailleur", les deux partageant la même base de données .
Oh, j'ai dit "partager" ... mais de quoi cet article met-il en garde? :
Quatrièmement, le partage d'une base de données entre applications (ou services) est une mauvaise chose. Il est simplement trop tentant d'y placer un état partagé amorphe et avant de vous en rendre compte, vous aurez un monstre énormément couplé.
=> pas d'accord. Dans certains cas, des applications distinctes font toujours partie de la même unité et, par conséquent, la notion de "problème de couplage" n’a aucun sens dans ce cas.
Continuons: la webapp gère les requêtes HTTP du client et peut mettre à jour à tout moment certains agrégats (terme DDD), générant les événements de domaine correspondants.
L'objectif du travailleur serait de gérer ces événements de domaine en traitant les travaux nécessaires.
Le point est:
Comment les données d'événements doivent-elles être transmises au travailleur?
La première solution, comme le dit l'article, consiste à utiliser RabbitMQ, un excellent middleware orienté message.
Le flux de travail serait simple:
Chaque fois que le dyno Web génère un événement, il le publie via RabbitMQ, qui alimente le travailleur.
L'inconvénient serait que rien ne garantit la cohérence immédiate entre la validation de la mise à jour globale et la publication de l'événement, sans s'occuper des éventuels problèmes d'échec d'envoi ... ou de matériel; c'est un autre problème majeur.
Exemple: il serait possible qu'un événement soit publié sans succès de la mise à jour globale ... entraînant un événement représentant une fausse représentation du modèle de domaine.
Vous pourriez soutenir que le XA global (validation en deux phases) existe, mais que ce n'est pas une solution qui convient à toutes les bases de données ou middlewares.
Alors, quelle pourrait être une bonne solution pour assurer cette cohérence immédiate? :
IMO, stockant l'événement dans la base de données, dans la même transaction locale que la mise à jour globale.
Un simple planificateur asynchrone serait créé et chargé d'interroger les événements en cours non publiés de la base de données et de les envoyer à RabbitMQ, qui à son tour renseignerait l'agent de travail.
Mais pourquoi avoir besoin d'un planificateur supplémentaire à côté de Webapp et d'ailleurs: pourquoi avoir besoin de RabbitMQ dans ce cas?
Par cette solution, il apparaît logiquement que le RabbitMQ pourrait être inutile, notamment parce que la base de données est partagée.
En effet, quel que soit le cas, nous avons vu que la cohérence immédiate implique une interrogation à partir de la base de données.
Ainsi, pourquoi le travailleur ne serait-il pas directement responsable de ce scrutin?
Par conséquent, je me demande pourquoi tant d'articles sur le Web critiquent difficilement la mise en file d'attente de bases de données, tout en promouvant un middleware orienté message.
Extrait de l'article:
Simple, utilisez le bon outil pour ce travail: ce scénario nécessite un système de messagerie. Il résout tous les problèmes décrits ci-dessus; plus d'interrogation, remise efficace des messages, plus besoin d'effacer les messages terminés des files d'attente, ni d'état partagé.
Et une cohérence immédiate, ignorée?
En résumé, il semble vraiment que, quel que soit le cas, qu'il s'agisse d'une base de données partagée ou non, nous avons besoin d'une interrogation de la base de données .
Ai-je oublié certaines notions critiques?
Merci
Réponses:
Si vous construisez une application simple avec un trafic faible, il y a quelque chose à dire sur le maintien d'un autre composant hors de votre système. Il est très probable que ne pas utiliser de bus de messages constitue la bonne réponse pour vous. Cependant, je suggérerais de construire votre système de manière à pouvoir remplacer le système de file d'attente basé sur une base de données par une solution middleware. Je suis d'accord avec l'article. Une base de données n'est pas le bon outil pour un système basé sur une file d'attente, mais elle peut vous suffire.
Les systèmes basés sur la file d'attente comme RabbitMq sont construits autour d'une échelle massive sur un matériel modéré. Leur architecture est capable d'y parvenir en évitant les processus qui ralentissent par nature le système de base de données conforme à ACID . Puisqu'un bus de messages doit seulement s'assurer qu'un message est stocké et traité avec succès, il n'a pas besoin de se soucier de verrouiller et d'écrire des journaux de transactions. Ces deux concepts sont absolument nécessaires pour un système ACID mais sont souvent une cause de conflit.
En termes de performances, cela revient à: vous avez une table SQL. Beaucoup de lectures et beaucoup d'écritures. Les deux nécessitent une sorte de verrouillage pour mettre à jour les lignes, les pages et les index. Votre mécanisme d'interrogation verrouille en permanence un index pour y effectuer des recherches. Cela empêche les écritures de se produire; au mieux, ils sont mis en file d'attente. Le code effectuant le traitement se verrouille également pour mettre à jour le statut de la file d'attente à la fin ou à l'échec. Oui, vous pouvez effectuer l'optimisation des requêtes après l'optimisation pour que cela fonctionne, ou vous pouvez utiliser un système spécialement conçu pour la charge de travail que vous demandez. Un RabbitMq mange ce type de travail sans même transpirer; En plus de cela, vous devez enregistrer votre base de données de la charge de travail, ce qui lui donne plus d'espace pour faire d'autres tâches.
Une autre chose à considérer est que la plupart des systèmes de file d'attente n'utilisent généralement pas de technique d'interrogation (certains autorisent HTTP, mais il est recommandé d'éviter l'utilisation du côté réception). RabbitMq utilise des protocoles réseau spécialement conçus pour les bus de messages tels que AMPQ .
Edit: Ajouter un cas d'utilisation.
La façon dont j'ai utilisé Rabbit est que j'ai un point de terminaison API qui accepte une modification nécessitant une table de base de données très utilisée. Cette table est constamment en conflit et ne sera parfois pas en mesure d'enregistrer une modification à temps de l'API. Ce que je fais à la place, c’est d’écrire la demande de changement dans une file d’attente, puis d’avoir un service qui gère ces messages dans la mesure de leurs moyens. En cas de conflit de base de données, la file d'attente augmente simplement et le traitement des messages est retardé. En règle générale, le temps de traitement est de l'ordre de 14 ms, mais en cas de conflit intense, nous obtenons jusqu'à 2-3 secondes.
la source