Lorsqu'un producteur envoie un message au broker ApsaraMQ for RocketMQ, la requête peut échouer en raison de problèmes réseau, de redémarrages du broker ou de limites de capacité. Le SDK client gère ces échecs grâce à deux mécanismes intégrés :
Les nouvelles tentatives d'envoi renvoient automatiquement les messages ayant échoué jusqu'à ce que l'envoi aboutisse ou que la limite de tentatives soit atteinte.
La limitation de débit protège le broker contre la surcharge en rejetant les requêtes lorsque la capacité est insuffisante.
Ces deux mécanismes fonctionnent conjointement : lorsque la limitation de débit entraîne un rejet, le mécanisme de nouvelle tentative utilise un backoff exponentiel pour renvoyer le message sans surcharger davantage le broker.
Nouvelles tentatives d'envoi
Processus de nouvelle tentative
Le SDK client intègre une logique de nouvelle tentative. Lorsqu'une requête d'envoi échoue, le SDK renvoie automatiquement le message ; aucun code de nouvelle tentative au niveau de l'application n'est nécessaire.
Définissez le nombre maximal de tentatives lors de l'initialisation du producteur. En cas d'échec d'une requête, le SDK effectue des tentatives jusqu'à la livraison du message ou jusqu'à l'atteinte de la limite de tentatives. Si la dernière tentative échoue, le SDK renvoie une erreur à votre application.
Le comportement des nouvelles tentatives varie selon le mode d'envoi :
| Mode d'envoi | Comportement des threads | En cas d'échec final |
|---|---|---|
| Synchrone | Le thread appelant est bloqué pendant toute la séquence de nouvelles tentatives | Le SDK lève une exception |
| Asynchrone | Le thread appelant n'est pas bloqué | Le SDK déclenche un événement de rappel d'échec |
Déclencheurs de nouvelles tentatives
Les nouvelles tentatives sont déclenchées par deux catégories d'échecs :
Échecs côté client
Une exception réseau provoque un échec de connexion ou un délai d'expiration de la requête.
Le broker redémarre ou fait l'objet d'un déploiement annulé, ce qui entraîne des échecs de connexion.
Le broker fonctionne lentement, provoquant des délais d'expiration des requêtes.
Erreurs côté broker
Erreur de logique système : une erreur de traitement interne sur le broker.
Erreur de limitation de débit du système : le broker rejette la requête car il a dépassé sa capacité. Consultez la section Limitation de débit.
Les messages transactionnels prennent uniquement en charge les nouvelles tentatives transparentes. Le SDK ne tente pas de renvoyer les messages transactionnels en cas d'exceptions réseau ou de délais d'expiration.
Intervalle de nouvelle tentative
L'intervalle entre les nouvelles tentatives dépend du type d'erreur :
| Type d'erreur | Intervalle de nouvelle tentative |
|---|---|
| Toutes les erreurs sauf la limitation de débit | Immédiat (aucun délai) |
| Erreur de limitation de débit du système | Backoff exponentiel avec jitter |
Pour les erreurs de limitation de débit, le SDK utilise un backoff exponentiel avec les paramètres suivants :
| Paramètre | Description | Valeur par défaut |
|---|---|---|
INITIAL_BACKOFF |
Délai avant la première nouvelle tentative | 1 seconde |
MULTIPLIER |
Facteur d'augmentation du délai après chaque nouvelle tentative | 1,6 |
JITTER |
Facteur de randomisation appliqué à chaque délai | 0,2 |
MAX_BACKOFF |
Délai maximal entre les nouvelles tentatives | 120 secondes |
MIN_CONNECT_TIMEOUT |
Délai d'expiration de connexion minimal | 20 secondes |
L'algorithme de backoff fonctionne comme suit :
ConnectWithBackoff()
current_backoff = INITIAL_BACKOFF
current_deadline = now() + INITIAL_BACKOFF
while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT)) != SUCCESS)
SleepUntil(current_deadline)
current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
current_deadline = now() + current_backoff +
UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
Pour la spécification complète, consultez la documentation relative au backoff de connexion gRPC.
Comprendre le budget total de temps de nouvelle tentative
Le SDK expose une seule commande de nouvelle tentative : le nombre maximal de tentatives. En mode synchrone, le thread appelant reste bloqué pendant toute la séquence de nouvelles tentatives. Par conséquent, le temps de blocage total dépend de la relation entre le délai d'expiration par requête et le nombre maximal de tentatives :
Total blocking time (worst case) = max_retries x per_request_timeout + sum_of_backoff_delays
Pour les erreurs autres que la limitation de débit (nouvelle tentative immédiate), le délai de backoff est nul :
Total blocking time = max_retries x per_request_timeout
Pour les erreurs de limitation de débit, les délais de backoff s'accumulent de manière exponentielle. Par exemple, avec les paramètres par défaut et 5 nouvelles tentatives :
| Nouvelle tentative | Délai de backoff (approximatif) | Délai cumulé |
|---|---|---|
| 1 | 1 s | 1 s |
| 2 | 1,6 s | 2,6 s |
| 3 | 2,56 s | 5,16 s |
| 4 | 4,1 s | 9,26 s |
| 5 | 6,55 s | 15,81 s |
Évaluez conjointement votre délai d'expiration par requête et le nombre maximal de nouvelles tentatives afin d'éviter un blocage excessivement long du thread appelant en mode synchrone.
Gérer les messages ayant échoué après épuisement des nouvelles tentatives
Les nouvelles tentatives intégrées ne garantissent pas la livraison. Si toutes les tentatives échouent, le SDK renvoie une erreur. Interceptez cette erreur dans votre application et mettez en œuvre une stratégie de secours :
Enregistrez le message ayant échoué dans un journal local ou un magasin de lettres mortes pour un retraitement ultérieur.
Avertissez votre système de surveillance afin que vous puissiez enquêter sur la cause racine.
Gérer les messages en double résultant des nouvelles tentatives
Lorsqu'une requête d'envoi expire, le SDK ne peut pas déterminer si le broker a déjà reçu et stocké le message. Une nouvelle tentative peut générer un doublon sur le broker. Il s'agit d'un compromis fondamental inhérent aux systèmes de livraison « au moins une fois ».
Pour gérer les doublons, concevez vos consommateurs pour un traitement idempotent :
Attribuez à chaque message une clé métier unique (telle qu'un ID de commande ou un ID de transaction).
Avant le traitement, vérifiez si la clé a déjà été traitée.
Utilisez des contraintes de base de données ou des caches de déduplication pour garantir l'unicité.
Limitation de débit
La limitation de débit est un mécanisme opérationnel normal dans les systèmes de messagerie cloud. Lorsque la capacité du système est insuffisante ou que l'utilisation dépasse un seuil prédéfini, le broker ApsaraMQ for RocketMQ rejette immédiatement la requête et renvoie une erreur de limitation de débit du système. La logique de nouvelle tentative intégrée au SDK gère ensuite la requête rejetée en utilisant un backoff exponentiel.
Déclencheurs de limitation de débit
La limitation de débit est déclenchée dans les scénarios suivants :
Pic de pression de stockage : un groupe de consommateurs commence à consommer à partir du décalage maximal d'une file d'attente. Dans des scénarios tels que les déploiements commerciaux où un groupe de consommateurs doit commencer à consommer à un moment précis, la pression de stockage sur la file d'attente augmente brusquement. Pour plus d'informations, consultez Gestion de la progression des consommateurs.
Accumulation de messages : lorsque les consommateurs ne peuvent pas suivre le rythme des messages entrants, les messages non consommés s'accumulent dans la file d'attente. Si l'accumulation dépasse le seuil, le broker déclenche la limitation de débit pour réduire la pression sur le système en aval.
Codes d'erreur et comportement de nouvelle tentative par type de client
Lorsque la limitation de débit est déclenchée, le code d'erreur et le comportement de nouvelle tentative dépendent du protocole de votre client.
Clients gRPC
| Élément | Valeur |
|---|---|
| Code d'erreur | 530 |
| Mot-clé du message d'erreur | TOO_MANY_REQUESTS |
| Comportement de nouvelle tentative | Nouvelle tentative automatique avec backoff exponentiel |
Clients Remoting
| Élément | Valeur |
|---|---|
| Code d'erreur | 215 |
| Mot-clé du message d'erreur | messages flow control |
Le comportement de nouvelle tentative pour les clients Remoting varie selon la version du SDK :
| SDK | Comportement de nouvelle tentative en cas de limitation de débit |
|---|---|
| SDK client TCP ApsaraMQ for RocketMQ pour Java < 1.9.0.Final | Aucune nouvelle tentative |
| SDK client TCP ApsaraMQ for RocketMQ pour Java >= 1.9.0.Final | Nouvelle tentative automatique avec backoff exponentiel |
| SDK Apache RocketMQ open source (producteur) | Aucune nouvelle tentative |
| SDK Apache RocketMQ open source (consommateur) | Nouvelle tentative automatique avec backoff exponentiel |
Si votre version du SDK n'effectue pas automatiquement de nouvelles tentatives en cas d'erreurs de limitation de débit, implémentez une logique de nouvelle tentative avec backoff exponentiel dans le code de votre application.
Pour connaître les versions de clients prises en charge, consultez la section Compatibilité des SDK.
Prévenir et gérer la limitation de débit
Surveiller la capacité avant les pics de trafic
Utilisez les fonctionnalités d'observabilité d'ApsaraMQ for RocketMQ pour surveiller l'utilisation et la capacité du système. Avant les déploiements commerciaux ou les pics de trafic anticipés :
Vérifiez que votre instance dispose de ressources suffisantes pour le trafic attendu.
Contrôlez le retard des groupes de consommateurs pour identifier les risques d'accumulation.
Mettez à l'échelle votre instance ou optimisez le débit des consommateurs si nécessaire.
Gérer la limitation de débit inattendue au moment de l'exécution
Si une limitation de débit survient de manière inattendue et que les nouvelles tentatives intégrées au SDK ne permettent pas de récupérer la situation :
Routerez les requêtes vers un système de secours jusqu'à ce que la condition de limitation de débit soit levée.
Enregistrez les événements de limitation de débit (recherchez le code d'erreur
530/TOO_MANY_REQUESTSpour gRPC ou215/messages flow controlpour Remoting) afin d'aider à diagnostiquer la cause racine.