Cloud Tasks vous permet d'envoyer de grands volumes de tâches asynchrones tout en contrôlant le débit auquel le trafic atteint vos files d'attente et vos services en aval. En appliquant des modèles de montée en puissance progressive et des contrôles de débit, vous pouvez faire évoluer les charges de travail de manière fluide sans déclencher de pics de latence de file d'attente ni de surcharge de la cible lorsque le trafic augmente plus rapidement que l'infrastructure ne peut s'adapter.
Présentation
Ce document présente les bonnes pratiques à suivre pour maintenir des performances Cloud Tasks élevées dans les files d'attente à fort trafic. Une file d'attente à TPS élevé est une file d'attente qui comporte au moins 500 tâches créées ou distribuées par seconde (TPS). Un groupe de files d'attente à TPS élevé est un ensemble contigu de files d'attente, par exemple [queue0001, queue0002, …, queue0099], qui ont au moins 2 000 tâches créées ou distribuées par seconde au total. Vous pouvez afficher l'historique des TPS d'une file d'attente ou d'un groupe de files d'attente à l'aide des métriques Cloud Monitoring, api/request_count pour les opérations CreateTask et queue/task_attempt_count pour les tentatives de tâches. Les files d'attente et les groupes de files d'attente à fort trafic sont sujets à deux grandes classes d'échecs :
Une surcharge de file d'attente se produit lorsque la création et l'envoi de tâches vers une file d'attente ou un groupe de files d'attente individuels augmentent plus rapidement que l'infrastructure de file d'attente ne peut s'adapter. L'infrastructure de Google utilise des couches adaptatives qui réallouent dynamiquement la charge en fonction des modèles de trafic, et cette adaptation prend du temps. De même, une surcharge de la cible se produit lorsque le taux de distribution des tâches entraîne des pics de trafic dans l'infrastructure cible en aval. Dans les deux cas, suivez un modèle 500/50/5 : lorsque vous effectuez un scaling au-delà de 500 TPS, n'augmentez pas le trafic de plus de 50 % toutes les 5 minutes.
Indépendamment du modèle 500/50/5 pour les charges de travail à TPS élevé, la montée en puissance initiale de la file d'attente affecte toutes les files d'attente lorsqu'elles démarrent à partir d'un état froid ou inactif, y compris les files d'attente configurées pour des taux de distribution modérés. Ce document passe en revue différents scénarios pouvant introduire des risques de scaling et donne des exemples de gestion de la montée en puissance de la file d'attente et d'application du modèle 500/50/5.
Montée en puissance initiale de la file d'attente
Le modèle 500/50/5 s'applique aux files d'attente à TPS élevé qui fonctionnent déjà à un rythme constant. La montée en puissance initiale de la file d'attente est un mécanisme système distinct qui s'applique à toutes les files d'attente, y compris celles configurées pour des taux de distribution modérés tels que 20 à 100 TPS, lorsqu'elles passent d'un état froid ou inactif à un fonctionnement en régime permanent.
Une file d'attente passe à l'état froid ou inactif dans l'une des situations suivantes :
La file d'attente vient d'être créée ou a été réactivée après avoir été mise en pause.
La file d'attente est inactive depuis quelques minutes sans envois actifs.
La file d'attente est en cours de récupération après avoir reçu des réponses d'erreur HTTP
429ou5xxen aval. Pour en savoir plus sur l'impact du backoff d'erreur sur les taux de distribution, consultez Erreurs de backoff et taux appliqués.
Lorsque des tâches arrivent dans une file d'attente froide ou inactive, Cloud Tasks ne les distribue pas immédiatement au taux max_dispatches_per_second configuré. Pour protéger les cibles en aval des pics de trafic soudains, Cloud Tasks commence à distribuer les tâches à un taux de référence faible, par exemple environ 1 TPS. Il augmente ensuite progressivement le taux d'envoi appliqué à des intervalles d'évaluation périodiques. Le taux appliqué continue d'augmenter tant que la demande de la file d'attente reste saturée et que les gestionnaires cibles renvoient des réponses HTTP 2xx. Selon votre taux cible, l'atteinte de valeurs max_dispatches_per_second élevées peut prendre plusieurs minutes.
Si votre charge de travail envoie un trafic irrégulier séparé par de brèves périodes d'inactivité de quelques minutes ou plus, la file d'attente se réinitialise à un état froid entre les pics et répète ce processus de montée en puissance à chaque pic. Pour minimiser les délais de montée en puissance des charges de travail sensibles aux pics, suivez ces bonnes pratiques :
Maintenez un flux constant de trafic de référence pour que les files d'attente sensibles à la latence restent actives entre les pics.
Réutilisez les files d'attente existantes plutôt que de les supprimer et de les recréer fréquemment.
Provisionnez une capacité cible en aval suffisante pour que les gestionnaires renvoient des réponses HTTP
2xxet évitent de renvoyer des réponses d'erreur HTTP429ou5xxqui réinitialisent le taux de distribution appliqué.
Diagnostiquer la limitation de la file d'attente
Si votre file d'attente distribue les tâches plus lentement que le taux max_dispatches_per_second configuré, vérifiez si le goulot d'étranglement provient d'une montée en puissance de la file d'attente à froid ou inactive, d'un intervalle exponentiel entre les tentatives en cas de congestion de la cible ou de limites de simultanéité.
Montée en puissance de la file d'attente froide ou inactive
La montée en puissance initiale de la file d'attente est probablement la cause si toutes les conditions suivantes s'appliquent :
- La file d'attente a été récemment créée, réactivée après avoir été mise en pause ou inactive pendant quelques minutes avant l'arrivée du trafic.
- Les tentatives de tâche aboutissent sans erreur de cible, affichant
response_code="OK"dans la métrique Monitoringcloudtasks.googleapis.com/queue/task_attempt_count. - Les envois en cours restent inférieurs à
max_concurrent_dispatches, tandis quecloudtasks.googleapis.com/queue/depthoucloudtasks.googleapis.com/queue/task_attempt_delaysest élevé. En même temps, le taux d'envoi danscloudtasks.googleapis.com/queue/task_attempt_countaugmente progressivement à des intervalles d'évaluation périodiques.
Pour en savoir plus sur les métriques Monitoring, consultez Envoyer des métriques à Monitoring.
Surcharge de la cible et intervalle entre les tentatives en cas de congestion
Cloud Tasks réduit de manière dynamique les taux de distribution si votre cible en aval renvoie des réponses d'erreur HTTP 429 Too Many Requests ou HTTP 5xx, telles que HTTP 503 Service Unavailable. Ce backoff de congestion empêche la surcharge de la cible.
Pour vérifier si des erreurs de cible entraînent la limitation des envois par Cloud Tasks, affichez la métrique Monitoring cloudtasks.googleapis.com/queue/task_attempt_count regroupée par le critère de regroupement response_code. Si la journalisation des files d'attente est activée, vous pouvez également inspecter les journaux de réponse des tentatives dans l'explorateur de journaux :
resource.type="cloud_tasks_queue"
jsonPayload.attemptResponseLog.status!="OK"
Dans response_code et jsonPayload.attemptResponseLog.status, Cloud Tasks enregistre les codes d'état gRPC canoniques au lieu des codes d'état HTTP numériques. Par exemple, HTTP 429 correspond à RESOURCE_EXHAUSTED, HTTP 503 correspond à UNAVAILABLE, HTTP 500 correspond à INTERNAL, et HTTP 504 ou un délai avant expiration correspond à DEADLINE_EXCEEDED.
Si vous observez RESOURCE_EXHAUSTED, UNAVAILABLE, ou d'autres états d'erreur du serveur de la cible, effectuez un scaling à la hausse de vos instances de service cibles ou augmentez la simultanéité cible avant d'augmenter les limites de distribution de la file d'attente.
Pour en savoir plus sur l'activation des journaux de file d'attente, consultez Utiliser Cloud Logging avec des files d'attente.
Goulot d'étranglement lié à la simultanéité
Selon la loi de Little, la latence cible en aval limite votre débit d'envoi maximal :
Max Throughput (tasks/sec) = min(
max_dispatches_per_second,
max_concurrent_dispatches / Downstream Latency in seconds
)
Par exemple, si la latence d'exécution en aval est de deux secondes et que max_concurrent_dispatches est défini sur 100, le débit est limité à 50 tâches par seconde, même si max_dispatches_per_second est configuré sur 500.
Pour déterminer si la simultanéité est le goulot d'étranglement, divisez max_concurrent_dispatches par la latence de réponse cible enregistrée dans le champ jsonPayload.attemptResponseLog.attemptDuration dans Logging. Comparez ce seuil calculé à votre taux d'envoi réel dans la métrique Monitoring cloudtasks.googleapis.com/queue/task_attempt_count. Si les envois réels se stabilisent près de ce seuil alors que cloudtasks.googleapis.com/queue/depth ou cloudtasks.googleapis.com/queue/task_attempt_delays augmente, effectuez l'une des actions suivantes :
- Si votre cible en aval dispose d'une capacité de réserve, par exemple lorsque les tâches passent la majeure partie de leur temps à attendre des E/S externes, augmentez
max_concurrent_dispatches. - Si votre cible en aval utilise déjà beaucoup de ressources, l'augmentation de
max_concurrent_dispatchespeut aggraver la surcharge de la cible. Effectuez plutôt un scaling horizontal de vos instances cibles ou réduisez la latence d'exécution du gestionnaire.
Surcharge de la file d'attente
Les files d'attente ou les groupes de files d'attente peuvent être surchargés à tout moment en cas d'augmentation soudaine du trafic. Par conséquent, ces files d'attente peuvent rencontrer les problèmes suivants :
- Augmentation de la latence liée à la création de tâches
- Augmentation du taux d'erreur lié à la création de tâches
- Réduction du taux de distribution
Pour vous protéger contre ce problème, établissez des contrôles dans toutes les situations où le taux de création ou de distribution d'une file d'attente ou d'un groupe de files d'attente peut augmenter soudainement. Commencez par un maximum de 500 opérations par seconde sur une file d'attente ou un groupe de files d'attente à froid, puis augmentez le trafic de 50 % toutes les cinq minutes. En théorie, vous pouvez atteindre 740 000 opérations par seconde après 90 minutes en utilisant ce calendrier de montée en puissance. Cela peut se produire dans plusieurs circonstances.
Exemple :
- Lancement de nouvelles fonctionnalités qui dépendent fortement de Cloud Tasks
- Déplacement du trafic entre les files d'attente
- Rééquilibrage du trafic sur un nombre plus ou moins élevé de files d'attente
- Exécution de jobs par lot qui injectent un grand nombre de tâches
Dans ces cas et dans d'autres, suivez le schéma 500/50/5.
Utiliser la répartition du trafic App Engine
Si une application App Engine crée les tâches, vous pouvez utiliser la répartition du trafic App Engine (environnement standard App Engine ou environnement flexible App Engine) pour lisser les augmentations de trafic. En répartissant le trafic entre les versions (environnement standard ou environnement flexible), vous pouvez augmenter progressivement les requêtes gérées par débit pour protéger l'état de la file d'attente. Prenons l'exemple d'une augmentation du trafic vers un groupe de files d'attente récemment développé : soit [queue0000, queue0199] une séquence de files d'attente à TPS élevé qui reçoivent 100 000 créations de TPS au total au pic.
[queue0200, queue0399] correspond à une séquence de nouvelles files d'attente. Une fois que vous avez transféré tout le trafic, le nombre de files d'attente de la séquence double et la nouvelle plage de files d'attente reçoit 50 % du trafic total de la séquence.
Lorsque vous déployez la version qui augmente le nombre de files d'attente, augmentez progressivement le trafic vers la nouvelle version, et donc vers les nouvelles files d'attente, à l'aide de la répartition du trafic :
- Commencez par transférer 1 % du trafic vers la nouvelle version. Par exemple, 50 % de 1 % de 100 000 TPS donne 500 TPS à l'ensemble de nouvelles files d'attente.
- Toutes les cinq minutes, augmentez de 50 % le trafic envoyé à la nouvelle version, comme indiqué dans le tableau suivant :
| Nombre de minutes depuis le début du déploiement | % du trafic total transféré vers la nouvelle version | % du trafic total transféré vers les nouvelles files d'attente | % du trafic total transféré vers les anciennes files d'attente |
|---|---|---|---|
| 0 | 1 | 0,5 | 99,5 |
| 5 | 1,5 | 0,75 | 99,25 |
| 10 | 2,3 | 1,15 | 98,85 |
| 15 | 3,4 | 1,7 | 98,3 |
| 20 | 5,1 | 2,55 | 97,45 |
| 25 | 7,6 | 3,8 | 96,2 |
| 30 | 11,4 | 5,7 | 94,3 |
| 35 | 17,1 | 8,55 | 91,45 |
| 40 | 25,6 | 12,8 | 87,2 |
| 45 | 38,4 | 19,2 | 80,8 |
| 50 | 57,7 | 28,85 | 71,15 |
| 55 | 86,5 | 43,25 | 56,75 |
| 60 | 100 | 50 | 50 |
Pics de trafic générés par les versions
Lors du lancement d'une version qui augmente considérablement le trafic vers une file d'attente ou un groupe de files d'attente, le déploiement progressif est, là encore, un mécanisme important pour lisser les augmentations. Déployez progressivement vos instances de sorte que le lancement initial ne dépasse pas 500 opérations par seconde au total vers les nouvelles files d'attente, en augmentant de 50 % au maximum toutes les cinq minutes.
Nouvelles files d'attente ou nouveaux groupes de files d'attente à TPS élevé
Les files d'attente nouvellement créées sont particulièrement vulnérables. Les groupes de files d'attente, par exemple [queue0000, queue0001, …, queue0199], sont tout aussi sensibles que les files d'attente uniques lors des étapes de déploiement initiales. Pour ces files d'attente, le déploiement progressif est une stratégie importante. Lancez des services nouveaux ou mis à jour qui créent des files d'attente ou des groupes de files d'attente à TPS élevé par étapes. Maintenez la charge initiale en dessous de 500 TPS et échelonnez les augmentations de 50 % ou moins à au moins cinq minutes d'intervalle.
Groupes de files d'attente récemment développés
Lorsque vous augmentez la capacité totale d'un groupe de files d'attente, par exemple en étendant [queue0000-queue0199 à queue0000-queue0399], suivez le modèle 500/50/5. Pour les procédures de déploiement, les nouveaux groupes de files d'attente se comportent de la même manière que les files d'attente individuelles. Appliquez le modèle 500/50/5 au nouveau groupe dans son ensemble, et pas seulement aux files d'attente individuelles du groupe.
Pour ces expansions de groupes de files d'attente, le déploiement progressif est une stratégie importante. Si la source de votre trafic est App Engine, vous pouvez utiliser la répartition du trafic. Lorsque vous migrez votre service pour ajouter des tâches au nombre accru de files d'attente, déployez progressivement vos instances de sorte que le lancement initial ne dépasse pas 500 opérations au total vers les nouvelles files d'attente, et n'augmentez pas le trafic de plus de 50 % toutes les cinq minutes.
Extension du groupe de files d'attente d'urgence
Vous pouvez parfois souhaiter étendre un groupe de files d'attente existant, par exemple parce que vous vous attendez à ce que des tâches soient ajoutées au groupe de files d'attente plus rapidement que le groupe ne peut les distribuer. Si vous répartissez les noms des nouvelles files d'attente de manière uniforme parmi les noms de vos files d'attente existantes par ordre lexicographique, vous pouvez envoyer immédiatement du trafic vers ces files d'attente. Assurez-vous qu'il n'y a pas plus de 50 % de nouvelles files d'attente entrelacées et que le trafic vers chaque file d'attente est inférieur à 500 TPS. Cette méthode est une alternative à l'utilisation de la répartition du trafic et du déploiement progressif.
Pour obtenir ce type de nommage entrelacé, ajoutez un suffixe aux files d'attente se terminant par des nombres pairs. Par exemple, si vous disposez de 200 files d'attente existantes [queue0000-queue0199] et que vous souhaitez créer 100 nouvelles files d'attente, choisissez [queue0000a, queue0002a, queue0004a, …, queue0198a] comme noms de nouvelles files d'attente, au lieu de [queue0200-queue0299].
Si vous avez besoin d'une augmentation supplémentaire, vous pouvez toujours entrelacer jusqu'à 50 % de files d'attente supplémentaires toutes les cinq minutes.
Mise en file d'attente de tâches par lot ou à grande échelle
Lorsque vous devez ajouter un grand nombre de tâches, par exemple des millions ou des milliards, un modèle de double injection peut être utile. Au lieu de créer des tâches à partir d'un seul job, utilisez une file d'attente d'injecteur. Chaque tâche ajoutée à la file d'attente de l'injecteur est distribuée et ajoute 100 tâches à la file d'attente ou au groupe de files d'attente concerné. Vous pouvez accélérer la file d'attente de l'injecteur au fil du temps. Par exemple, commencez à 5 TPS pour générer 500 TPS dans la file d'attente ou le groupe de files d'attente cible, puis augmentez le taux de 50 % toutes les 5 minutes.
Tâches nommées
Lorsque vous créez une tâche, Cloud Tasks lui attribue un nom unique par défaut. Vous pouvez attribuer votre propre nom à une tâche à l'aide du paramètre name. Cependant, cela introduit une surcharge de performances importante, entraînant des latences accrues et des taux d'erreur potentiellement plus élevés associés aux tâches nommées. Les noms de tâches séquentiels, tels que les codes temporels, peuvent augmenter considérablement cette surcharge.
Si vous attribuez vos propres noms, utilisez un préfixe bien distribué pour les noms de tâches, tel qu'un hachage du contenu. Pour en savoir plus sur l'attribution d'un nom à une tâche, consultez la documentation de référence sur le champ Task.name.
Surcharge de la cible
Cloud Tasks peut surcharger les services et ressources en aval que vous utilisez, tels qu'App Engine, Firestore en mode Datastore (Datastore) et votre réseau, si les envois de files d'attente augmentent soudainement. Si un backlog de tâches s'est accumulé, la réactivation de ces files d'attente peut surcharger ces services. Pour vous protéger contre la surcharge de la cible, suivez le modèle 500/50/5 : si une file d'attente distribue plus de 500 TPS, n'augmentez pas le trafic déclenché par une file d'attente de plus de 50 % toutes les cinq minutes. Pour surveiller de manière proactive l'augmentation de votre trafic, utilisez les métriques Monitoring. Vous pouvez utiliser les alertes Monitoring pour détecter les situations potentiellement dangereuses.
Réactiver ou reprendre les files d'attente à TPS élevé
Lorsque vous réactivez une file d'attente mise en pause, Cloud Tasks applique une accélération initiale de la file d'attente et augmente progressivement le taux de distribution à partir d'une valeur de référence faible vers le taux max_dispatches_per_second configuré de la file d'attente. Toutefois, si un grand nombre de tâches s'accumulent dans une file d'attente à TPS élevé ou dans plusieurs files d'attente que vous réactivez en même temps, le taux d'envoi peut toujours augmenter plus rapidement que la capacité des services cibles en aval. Pour éviter de surcharger la cible lorsque vous reprenez des files d'attente avec un backlog important, échelonnez la reprise de plusieurs files d'attente. Vous pouvez également réduire temporairement le taux max_dispatches_per_second et l'augmenter progressivement en suivant le modèle 500/50/5. Pour en savoir plus sur la façon dont Cloud Tasks limite et augmente les envois lorsque les files d'attente sont réactivées, consultez Erreurs d'intervalle exponentiel entre les tentatives et taux appliqués.
Planification des tâches groupées
Un grand nombre de tâches planifiées pour être distribuées en même temps peut également entraîner un risque de surcharge de la cible. Si vous devez démarrer un grand nombre de tâches à la fois, envisagez d'utiliser des contrôles de débit de file d'attente pour augmenter progressivement le débit de distribution ou provisionner la capacité cible à l'avance.
Augmentation de la distribution ramifiée
Lorsque vous mettez à jour les services appelés par Cloud Tasks, l'augmentation du nombre d'appels distants peut créer des risques de production. Par exemple, supposons que les tâches d'une file d'attente à TPS élevé appellent le gestionnaire /task-foo. Une nouvelle version peut augmenter considérablement le coût d'appel de /task-foo si, par exemple, elle ajoute plusieurs appels Datastore coûteux au gestionnaire.
Le résultat net d'une telle version est une augmentation massive du trafic Datastore, qui est immédiatement liée aux modifications du trafic utilisateur. Utilisez un déploiement progressif ou la répartition du trafic pour gérer la montée en puissance.
Tentatives
Le code peut effectuer de nouvelles tentatives en cas d'échec lors d'appels à l'API Cloud Tasks. Toutefois, lorsqu'une proportion importante de requêtes échoue avec des erreurs côté serveur, un taux de nouvelles tentatives élevé peut surcharger davantage vos files d'attente et ralentir la récupération. Limitez la quantité de trafic sortant si votre client détecte qu'une proportion importante de requêtes échoue avec des erreurs côté serveur. Par exemple, vous pouvez utiliser l'algorithme de limitation adaptative décrit dans le chapitre Handling Overload (Gérer la surcharge) du livre Site Reliability Engineering (Ingénierie de la fiabilité des sites). Les bibliothèques clientes gRPC de Google implémentent une variante de cet algorithme.