Implémentation d'un service distribué n-Producers / 1-Consumer pour un système à mission critique
J'essaie d'implémenter une version distribuée de multi-producteur / 1-consommateur pour un système à mission critique. Je recherche de bonnes alternatives à l'approche actuelle basée sur le SGBDR.
Le problème
Le système se compose de plusieurs (50+) producteurs qui produisent en continu des milliers d'instances par seconde. Chaque instance est une structure plate bien définie, horodatée. Chaque instance est stockée dans une seule file d'attente par les producteurs.
De l'autre côté, j'ai un consommateur qui consomme les instances de manière FIFO.
Les producteurs et le consommateur fonctionnent sur différentes machines connectées par un réseau privé TCP / IP.
Par souci d'exhaustivité, il existe deux exigences fortes
- Le consommateur ne peut pas consommer deux fois la même ressource. C'est une erreur.
- Chaque ressource doit être consommée par le consommateur. Si une ressource est manquée, c'est une perte
De plus, la solution doit s'exécuter sur des serveurs Linux et Windows.
Approche actuelle
Dans la version actuelle, le système implémente cette solution en utilisant une base de données relationnelle comme bus de données.
Il existe un serveur de base de données qui prend en charge tous les producteurs et le consommateur. Les producteurs insèrent des ressources dans une table déterminée et le consommateur consomme les ressources de cette table comme représenté dans l'image ci-dessus.
Le modèle de transaction serveur de base de données / JDBC permet de contrôler les insertions / suppressions afin d'éviter la corruption de la file d'attente.
Cette approche actuelle fonctionne bien mais:
- Introduit la surcharge de maintenance d'un serveur de base de données relationnelle complet pour une tâche où aucune relation de données n'est requise;
- Le serveur de base de données relationnelle doit s'adapter aux exigences de la mission critique, ce qui est difficile à réaliser sur certains paramètres réels lorsque l'instance du serveur de base de données n'est pas dédiée
Alternatives
Ici, je liste quelques alternatives à l'approche actuelle du bus de données du serveur de base de données relationnelle:
Serveur de base de données relationnelle léger dédié
Cela semble être l'approche la plus simple: utiliser un serveur de base de données relationnel léger dédié comme HSQLDB, Apache Derby ou H2.
Avantages
Ils ont considérablement moins de frais généraux à maintenir par rapport à un SGBDR tel que MS SQL Server, Oracle DB Server ou même MySQL. De plus, moins de changements de code et de tests sont nécessaires car il s'agit essentiellement de moteurs SQL comme ceux utilisés dans la solution actuelle.
Les inconvénients
Ce sont des serveurs de bases de données relationnelles, il s'avère donc qu'il existe encore un certain niveau de surcharge pour effectuer une tâche sans relation. Un autre point est l'aspect de la mission critique. Nous utilisons Derby DB en interne depuis des lustres pour la surveillance du système en temps réel dans les modes embarqués et réseau. Cela fonctionne très bien, ni crash ni corruption de données. Cependant, le volume de transactions / s pour cette nouvelle utilisation est plus élevé.
Serveur Redis
À première vue, Redis semble parfait pour ce cas d'utilisation. En mémoire, rapide, sans overhad pour la relation de données, simple. Largement utilisé comme bus de données et signalé comme fiable. Mais pas pour Windows. Comme indiqué dans la documentation, Redis sur Windows n'est pas recommandé . Le port Microsoft Windows n'est plus maintenu , la dernière version date de 2016, donc attacher Redis au système ne semble pas prometteur.
Mettre en œuvre une solution à partir de zéro
En dernier lieu, c'est un problème producteur-consommateur. L'implémentation d'un service réseau utilisant TCP ou quelque chose de plus élégant comme Camel et l'utilisation de la file d'attente simultanée en interne plus un moteur de persistance local sera coûteux en temps, réinventer la roue mais c'est toujours une option.
Ce sont les alternatives que nous envisageons jusqu'à présent. J'apprécie si quelqu'un peut fournir un aperçu ou une recommandation.
Réponses
On dirait que vous recherchez une file d'attente de messages. En fonction de votre pile technologique, il existe différentes implémentations de file d'attente distribuée qui pourraient vous intéresser, par exemple ZeroMQ ou RabbitMQ.
Certaines approches comme ZeroMQ peuvent s'exécuter sans courtier de messages, ce qui signifie que les producteurs et les consommateurs parlent directement sans avoir besoin d'un autre service ou d'une base de données pour orchestrer / courtier la file d'attente. Être sans courtier a l'avantage d'être beaucoup plus simple à gérer opérationnellement que les files d'attente de messages négociées, et d'être plus simple à comprendre, à mettre à l'échelle et à personnaliser, mais le principal inconvénient est qu'il ne dispose pas des services habituellement fournis par les courtiers, donc si un participant est hors ligne, les messages peuvent être perdus. Si vous avez besoin que le message soit traité de manière fiable, vous devrez concevoir vos producteurs pour qu'ils soient en mesure de gérer l'envoi de nouvelles tentatives si le consommateur n'est pas disponible, vous devrez ajouter un mécanisme de confirmation de la livraison réussie, et le consommateur a besoin. être conçu pour être idempotent (être capable de détecter les messages en double et de les supprimer). Le principal avantage d'être sans courtier est que vous êtes libre de mettre en œuvre autant ou aussi peu de comportement de courtier que votre application a besoin, de sorte que vous n'êtes pas lié à un comportement de courtier spécifique.
Une file d'attente de messages négociée comme RabbitMQ est un peu plus simple lors de l'utilisation, car le courtier ajoute une couche de persistance et de fiabilité de la messagerie à la structure du système de file d'attente plutôt que d'exiger du producteur et des consommateurs qu'ils les implémentent, mais cela ajoute la complexité et la surcharge de gestion du courtier. , et le courtier ajoute une latence, il peut donc ne pas convenir aux scénarios où les millisecondes comptent ou où votre niveau d'évolutivité cible dépasse ce qui peut être réalisé dans un système négocié.
il existe encore un certain niveau de frais généraux pour effectuer une tâche sans relation
Je vous suggère de profiler votre application pour savoir si cela compte réellement ou non. Si une base de données SQL en cours de traitement n'est pas suffisante pour une application non simultanée, il est fort probable que vous l'utilisiez de manière inefficace, plutôt qu'en raison de problèmes de performances dans la gestion des relations elle-même.