Intégration simple de RabbitMQ et Spring Boot

Une traduction de l'article a été préparée avant le début du cours "Developer on the Spring Framework" .




Bonjour à tous!

Je voudrais partager avec vous une bibliothèque open source qui facilite l'intégration de RabbitMQ avec des applications sur Spring Boot. De plus, cette bibliothèque propose un nouveau concept amélioré de nouvelles tentatives (par rapport à l'approche Spring AMQP standard).
Simplifie? Mais comment?


Autoconfiguration


Supposons que nous voulons implémenter une interaction (par exemple, en utilisant SSL) avec RabbitMQ en utilisant Spring AMQP. Nous devons créer quelques haricots, comme ConnectionFactory, RabbitAdmin, RabbitTemplateet AbstractRabbitListenerContainerFactory.

Mais imaginez qu'il existe plusieurs hôtes virtuels dans RabbitMQ. Par défaut, dans Spring AMQP, vous devez créer un tel écosystème pour chaque hôte virtuel avec une configuration manuelle de RabbitTemplateet RabbitListener.



Comme vous pouvez le voir, toute cette configuration prend du temps et peut être un casse-tête.

Consciente de ce problème, la bibliothèque proposée configure automatiquement tous ces beans pour vous. La seule chose que vous devez faire est de déterminer la configuration application.propertieset la magie se produira!
Wow, mais à quoi ressemble la configuration application.properties?

Tout est très simple. Premièrement, il y a un préfixe pour les propriétés - ceci spring.rabbitmq.custom.

Après cela, vous devez spécifier le nom de l'événement. Il s'agit d'une partie très importante, car tous les paramètres définis par la bibliothèque sont basés sur ce nom.

Après le nom de l'événement, vous pouvez spécifier la propriété et la valeur. Toutes les propriétés sont décrites dans la documentation .

Ainsi, le modèle est le suivant: Voici un exemple de configuration pour deux connexions différentes.

spring.rabbitmq.custom.<YOUR_EVENT>.<PROPERTY>=<VALUE>




spring.rabbitmq.custom.some-event.host=localhost
spring.rabbitmq.custom.some-event.port=5672
spring.rabbitmq.custom.some-event.ttlRetryMessage=5000
spring.rabbitmq.custom.some-event.maxRetriesAttempts=5
spring.rabbitmq.custom.some-event.ttlMultiply=2
spring.rabbitmq.custom.some-event.queueRoutingKey=ROUTING.KEY.TEST
spring.rabbitmq.custom.some-event.exchange=ex.custom.direct
spring.rabbitmq.custom.some-event.exchangeType=direct
spring.rabbitmq.custom.some-event.queue=queue.custom.test
spring.rabbitmq.custom.some-event.autoCreate=true
spring.rabbitmq.custom.some-event.concurrentConsumers=1
spring.rabbitmq.custom.some-event.maxConcurrentConsumers=1
spring.rabbitmq.custom.some-event.virtualHost=tradeshift
spring.rabbitmq.custom.some-event.primary=true
spring.rabbitmq.custom.some-event.sslConnection=true
spring.rabbitmq.custom.some-event.tlsKeystoreLocation=file:///etc/tradeshift/your-service/tls-keystore.pkcs12
spring.rabbitmq.custom.some-event.tlsKeystorePassword=${RABBITMQ_PASS_CERT}

spring.rabbitmq.custom.another-event.host=localhost
spring.rabbitmq.custom.another-event.port=5672
spring.rabbitmq.custom.another-event.ttlRetryMessage=5000
spring.rabbitmq.custom.another-event.maxRetriesAttempts=5
spring.rabbitmq.custom.another-event.queueRoutingKey=TEST.QUEUE
spring.rabbitmq.custom.another-event.exchange=ex_test_1
spring.rabbitmq.custom.another-event.exchangeType=direct
spring.rabbitmq.custom.another-event.queue=queue_test_1
spring.rabbitmq.custom.another-event.autoCreate=true
spring.rabbitmq.custom.another-event.concurrentConsumers=1
spring.rabbitmq.custom.another-event.maxConcurrentConsumers=1
spring.rabbitmq.custom.another-event.username=guest
spring.rabbitmq.custom.another-event.password=${RABBITMQ_PASS}

Comme vous pouvez le voir, nous n'avons pas écrit une seule ligne de code !!!
Bien, mais vous disiez quelque chose sur la nouvelle stratégie de rejeu, non?

Oui, mon ami a dit!

Mais avant d'expliquer cette nouvelle stratégie, examinons le comportement par défaut de RabbitMQ et Spring AMQP.

Par défaut, RabbitMQ ne fournit pas de traitement de nouvelle tentative qui vous permettrait de contrôler le cycle de vie complet du message.

Par exemple, avant RabbitMQ 3.8 , l'en-tête du message n'avait pas de propriété pour contrôler le nombre de tentatives effectuées.

Comportement par défaut de RabbitMQ:

  • Si vous n'avez pas défini de temps à vivre (TTL, durée de vie), puis RabbitMQ essayera constamment de la file d' attente de votre message.
  • Si vous avez défini TTL mais n'avez pas défini dlx , après TTL, le message sera supprimé de la file d'attente et vous le perdrez.
  • Si vous avez défini TTL et dlx , après TTL, le message sera envoyé à l' échangeur défini dans dlx.


Comportement par défaut de RabbitMQ

Mais que se passe-t-il si nous voulons une TTL croissante (par exemple, en cas de fonctionnement instable) et contrôler le nombre de tentatives?

Grande question!

Il est temps d'expliquer comment fonctionnent la bibliothèque Spring AQMP et Spring Rabbit Tuning!

Stratégies de nouvelle tentative


Spring AMQP par défaut


Lorsque vous utilisez Spring AMQP par défaut, vous pouvez définir des options de nouvelle tentative à l'aide des propriétés ci-dessous.

Mais cette approche a des problèmes. Par défaut, Spring AMQP bloquera votre file d'attente lorsque vous essayez de remettre à nouveau un message.

Ce problème peut être résolu de manière détournée: utilisez le parallélisme. Mais de cette façon, nous chargeons la JVM, et ce n'est pas la meilleure approche. Si vous avez cinq messages problématiques (comme dans l'exemple), alors un goulot d'étranglement se produira à nouveau, et nous devons encore déterminer manuellement les beans dans le @Configurationbac - pour chaque connexion et conteneur.

spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.initial-interval=2000
spring.rabbitmq.listener.simple.retry.max-attempts=5
spring.rabbitmq.listener.simple.retry.multiplier=2
spring.rabbitmq.listener.simple.max-concurrency=5
spring.rabbitmq.listener.simple.concurrency=5


Spring RabbitMQ Tuning


Cette bibliothèque adopte une approche différente avec une file d'attente distincte pour les tentatives. De cette façon, nous pouvons contrôler TTL en utilisant le paramètre de message d'expiration et le paramètre x-death pour contrôler le nombre de tentatives.
Mais comment?

Nous utilisons le concept dlx dans la file d'attente de nouvelle tentative pour renvoyer le message à la file d'attente principale. Ainsi, nous avons accès au paramètre x-death et nous pouvons déterminer par programmation la durée de vie du message.

Remarque. Étant donné que cette bibliothèque est une extension de Spring AMQP, vous pouvez utiliser la stratégie de nouvelle tentative par défaut et utiliser cette bibliothèque uniquement pour la configuration automatique des beans.


Spring RabbitMQ Tuning Retry
Puis-je utiliser votre stratégie de nouvelle tentative sans autoconfiguration? J'ai déjà beaucoup de beans et je n'ai pas le temps de les réécrire.

Nous savons que le monde n'est pas parfait, et pour cette situation, nous avons un indicateur qui vous permet de désactiver la configuration automatique et d'utiliser uniquement notre approche du traitement de répétition et d'autres avantages, tels que la gestion des bacs.

Vous pouvez désactiver la configuration automatique à l'aide de la propriété suivante:

spring.rabbitmq.enable.custom.autoconfiguration=false

Mais j'ai deux connexions différentes, que dois-je faire dans ce cas?

Si vous disposez de plusieurs connexions et que vous souhaitez désactiver la configuration automatique, vous devez spécifier le nom du bean RabbitTemplatepour chaque connexion. Ceci est décrit ici . Vous pouvez toujours utiliser notre bean pour faciliter le travail avec Spring AMQP.

spring.rabbitmq.custom.<YOUR_EVENT>.rabbitTemplateBeanName= <RABBITTEMPLATE_BEAN_NAME>

RabbitTemplateHandler
Très bien! Donc, je veux l'utiliser. Comment puis-je faire ceci? Avez-vous un exemple ou une documentation?
Oui!

Nous avons un exemple de projet dans ce référentiel , où vous pouvez voir comment utiliser cette bibliothèque pour les éditeurs et les abonnés.

Mais c'est tellement simple que je vais donner l'exemple ici!

Éditeur


Il y a une classe dans la bibliothèque RabbitTemplateHandleret elle est très facile à utiliser. Vous devez appeler la méthode getRabbitTemplateet passer l'hôte virtuel en paramètre pour obtenir le bean RabbitTemplate. Après cela, vous pouvez appeler la méthode convertAndSend et la transmettre dans les paramètres de clé d'échange et de routage.

Remarque : la clé d'échange et de routage peut être obtenue à l'aide d'annotationsValeur.

Un exemple :

@Value("${spring.rabbitmq.custom.some-event.exchange}")
private String exchangeSomeEvent;

@Value("${spring.rabbitmq.custom.some-event.queueRoutingKey}")
private String routingKeySomeEvent;

@Autowired
private final RabbitTemplateHandler rabbitTemplateHandler;

public void sendMessage(final String message) {
   rabbitTemplateHandler.getRabbitTemplate("some-event").convertAndSend(exchangeSomeEvent, routingKeySomeEvent, message);
}

Abonné


Les abonnés sont également très simples. La seule chose que vous devez faire est d'ajouter une annotation à la méthode RabbitListener(annotation Spring AMQP par défaut) et de passer le nom containerFactory.
Comment trouver le nom de containerFactory correct pour un hôte virtuel?

Vous n'avez pas besoin de le savoir, passez simplement le nom de l'événement, et la bibliothèque fera toute la magie pour vous! Cette bibliothèque a également la possibilité d'inclure des tentatives et dlq, qui sont recommandés.

Les activer est très simple. Vous devez ajouter une annotation à la méthode EnableRabbitRetryAndDlqet passer le nom de la propriété en argument.

Remarque : vous pouvez également spécifier les exceptions à gérer avec les tentatives et dlq. Il est traité par défaut Exception.class, ce qui signifie gérer toutes les exceptions.

Exemple:

@RabbitListener(containerFactory = "some-event", queues = "${spring.rabbitmq.custom.some-event.queue}")
@EnableRabbitRetryAndDlq(event = "some-event", exceptions = { IllegalArgumentException.class, RuntimeException.class })
public void onMessage(Message message) {
   ...
}

C'est tout! J'espère que vous apprécierez cette bibliothèque autant que nous!

Et, plus important encore: n'hésitez pas à contribuer ou à envoyer des commentaires!

Remerciement spécial à


Andre Luis Gomes
Rogerio Bueno
Leonardo Ferreira



Inscrivez-vous à une leçon gratuite.


All Articles