La latence de queue est un défi persistant pour les services réseau, avec des pics imprévisibles dans les temps de réponse dus à des facteurs tels que les temps d’attente du processeur et la congestion du réseau. Alors que la rentabilité est souvent obtenue grâce à l’utilisation de ressources partagées, cela peut conduire à un compromis dans l’expérience utilisateur.
Dans cet article de blog, nous examinons la technique de couverture des demandes comme solution à ce problème. En comprenant ses avantages et ses limites, nous visons à fournir des informations sur quand et comment cette technique peut être utilisée efficacement pour créer des services plus prévisibles.
Améliorer la latence de queue avec la couverture des demandes
Si vous avez une dépendance avec une variance élevée et que vous ne pouvez pas la réparer rapidement, vous pouvez utiliser une technique appelée « demande de couverture ». L’idée est d’envoyer deux requêtes ou plus et de choisir la plus rapide, en annulant les plus lentes si nécessaire. Mais cela ne fonctionne que pour les requêtes idempotentes, c’est-à-dire les requêtes qui peuvent être faites plusieurs fois avec le même résultat. Vous devez également acheminer les demandes vers différents nœuds, par exemple en utilisant un équilibreur de charge.

Le temps d’attente est basé sur le centile de latence de la dépendance. Par exemple, si vous choisissez une latence p99, seulement 1% des requêtes recevront une deuxième sous-requête.
Jouons avec une simulation :
- Utilisation de la distribution log-normale.
- Dépendance
p0..p99.9=10..1000ms
- Envoyez une seule requête de couverture pour les 1 % de sous-requêtes les plus lentes. Pour ce faire, nous allons définir le délai de couverture sur la dépendance
p99
. - Voyez comment cela affecte le service
p99.9
Dans ce cas le p99.9(Service)=260ms
par rapport à la p99.9(Dependency)=1000ms
ce qui correspond à la p99.2(Dependency)
.
C’est une amélioration impressionnante !

Le pourcentage de demandes couvertes est de 1,012 %.
Ceci est particulièrement remarquable car il a un prix minime — le nombre de demandes de dépendance est augmenté de 1 % (car dans 99 % des cas, aucune demande supplémentaire n’est envoyée).
Malheureusement, la couverture des demandes se heurte assez rapidement à la loi des rendements décroissants. Le 1 % suivant de l’amélioration de la latence du service coûte environ 5 % de requêtes supplémentaires. Et même si nous doublons le nombre de requêtes, nous obtenons (au maximum) une autre amélioration de 1 % de latence pour le p99.9 du service :

Bien sûr, cela peut être amélioré un peu plus en envoyant trois demandes ou plus en parallèle pour choisir la réponse la plus rapide, mais le coût peut l’emporter sur les avantages.
La couverture de la demande n’est pas efficace pour les petits écarts
Si la variance dans un système est déjà faible, la couverture des demandes n’apportera pas beaucoup d’amélioration. Par exemple, si, p0..p99.9(Dependency)=50..200ms
alors p99.9(Service)=130ms
:
La latence la plus élevée pour la demande couverte sera toujours proche de la latence la plus élevée d’origine (p99.75).
Il est important de considérer le coût et les avantages avant de mettre en œuvre la couverture des demandes, car cela rendra le système plus complexe et coûteux. Le gain de latence a un prix.
Lorsque la couverture des demandes tourne mal
Il est important d’être conscient des inconvénients potentiels de la couverture des demandes. Si elle n’est pas gérée avec soin, la technique peut amplifier les pannes en augmentant le nombre de demandes effectuées. Un scénario pourrait se dérouler comme ceci :
- Le service de dépendance ralentit.
- Le service principal envoie plus de sous-requêtes, ce qui renforce le ralentissement du service de dépendance.
- Le service de dépendance commence à expirer ou à renvoyer des erreurs.
- Le service principal et/ou ses appelants lancent de nouvelles tentatives, ce qui aggrave encore la situation.
- La disponibilité du service principal diminue.
Pour éviter de tels scénarios, il est essentiel de mettre en place des mesures qui limitent les frais généraux. Ceux-ci peuvent inclure une boucle de rétroaction négative, un disjoncteur qui suspend la couverture des demandes sous certaines conditions, ou une combinaison des deux.
Certaines stratégies pour atténuer les risques de couverture des demandes comprennent :
- Utilisation d’un seau à jetons qui recharge toutes les N opérations et envoi d’une sous-requête uniquement s’il y a un jeton disponible (limitation du débit).
- Actualiser périodiquement le seuil pour qu’il corresponde au centile de latence réel.
- Surveiller la disponibilité et les performances du service de dépendance et suspendre la couverture des demandes en cas de chute.
Lors de la conception d’un système qui utilise la couverture des demandes, il est toujours préférable de dégrader temporairement la qualité de service plutôt que de provoquer une panne. La désactivation des fonctionnalités non critiques dans des conditions de stress est une sage précaution.
Conclusion
La couverture des demandes peut apporter des avantages à l’expérience utilisateur, mais elle comporte également des risques potentiels qui doivent être pris en compte. Une gestion prudente de la technique, y compris l’annulation des sous-requêtes plus lentes pour conserver les ressources, est essentielle. N’oubliez pas que l’ingénierie consiste à faire des compromis, pas des systèmes parfaits.
Ce poste est lié à Garantir des performances prévisibles dans les systèmes distribuésqui explore la variance et la latence de queue des services réseau.