Cloud
Azure Cosmos DB : diagnostiquer les 429 avant d'augmenter les RU/s
Un runbook de production pour qualifier les 429 Cosmos DB avec consommation RU, partitions chaudes, forme des requêtes, retries SDK, indexation, preuves KQL, décision de scaling et rollback.
Les réponses 429 de Cosmos DB sont faciles à mal lire pendant un incident. L’application ralentit, le SDK retry, les dashboards montrent du throttling, et quelqu’un propose d’augmenter les RU/s immédiatement. C’est parfois la bonne décision, mais cela ne doit pas être le premier changement inexpliqué. Une partition chaude, une nouvelle forme de requête, une dérive d’indexation ou une politique de retry trop agressive peuvent consommer la capacité disponible sans prouver que tout le container manque de débit.
Le cas d’usage est une API de production, orders-api-prod, qui lit et écrit des commandes dans le container orders. Depuis le dernier déploiement, la latence checkout augmente et les logs applicatifs montrent des erreurs intermittentes RequestRateTooLarge. L’objectif du runbook est de décider s’il faut augmenter les RU/s, corriger un problème de partition ou de requête, rollbacker le déploiement, ou conserver la capacité actuelle en améliorant les preuves.
Figer le contrat d’incident
Commencez par poser l’échec comme un contrat d’exploitation. L’équipe doit partager le container, le workload, la fenêtre, les symptômes et le rollback possible avant de modifier le throughput.
incident:
service: orders-api-prod
database: commerce
container: orders
account: cosmos-commerce-prod
region: westeurope
symptom:
- checkout latency increased
- application logs contain 429 / RequestRateTooLarge
- retry count increased after deployment
incident_window:
start: 2026-07-12T08:20:00Z
end: 2026-07-12T09:10:00Z
last_change:
deployment: orders-api-prod-20260712.3
suspected_area: order search and status update path
decision_needed:
- scale throughput
- rollback deployment
- fix query or partition usage
- hold change and keep monitoring
rollback_candidate:
deployment: orders-api-prod-20260712.2
throughput: previous container throughput or autoscale max RU/s Si le contrat d’incident dit seulement “Cosmos throttle”, l’action suivante sera probablement trop large. La bonne question est quelle opération, quel range de partition, quelle requête ou quel chemin client consomme la capacité.
Prouver le mode de capacité actuel
Ne supposez pas que le container est provisionné comme l’équipe s’en souvient. Vérifiez si le throughput est manuel, autoscale, partagé au niveau database, récemment modifié ou inférieur au baseline attendu.
SUBSCRIPTION="00000000-0000-0000-0000-000000000000"
RG="rg-commerce-prod"
ACCOUNT="cosmos-commerce-prod"
DB="commerce"
CONTAINER="orders"
az account set --subscription "$SUBSCRIPTION"
az cosmosdb sql container throughput show --resource-group "$RG" --account-name "$ACCOUNT" --database-name "$DB" --name "$CONTAINER" --query "{resource:resource, autoscaleSettings:autoscaleSettings}" --output json
az cosmosdb sql database throughput show --resource-group "$RG" --account-name "$ACCOUNT" --name "$DB" --query "{resource:resource, autoscaleSettings:autoscaleSettings}" --output json Une de ces commandes peut échouer légitimement si le throughput est configuré à l’autre niveau. Gardez ce résultat dans la note d’incident. Il évite une fausse hypothèse sur l’endroit où le scaling s’appliquerait vraiment.
Séparer saturation globale et partition chaude
Un taux de 429 au niveau container ne signifie pas automatiquement que tout le container manque de RU/s. Si une partition key ou un range de partition est chaud, augmenter le throughput total peut réduire la pression temporairement tout en laissant le problème de conception intact.
let StartTime = datetime(2026-07-12T08:20:00Z);
let EndTime = datetime(2026-07-12T09:10:00Z);
AzureDiagnostics
| where TimeGenerated between (StartTime .. EndTime)
| where ResourceProvider == "MICROSOFT.DOCUMENTDB"
| where Category has_any ("DataPlaneRequests", "PartitionKeyStatistics", "QueryRuntimeStatistics")
| extend StatusCode = tostring(statusCode_s)
| extend Operation = tostring(operationName_s)
| extend Collection = tostring(collectionName_s)
| extend PartitionKeyRangeId = tostring(partitionKeyRangeId_s)
| extend RequestCharge = todouble(requestCharge_s)
| where Collection == "orders" or Collection == ""
| summarize
Requests = count(),
Throttled = countif(StatusCode == "429"),
TotalRU = sum(RequestCharge),
P95RU = percentile(RequestCharge, 95)
by Operation, PartitionKeyRangeId, bin(TimeGenerated, 5m)
| order by TimeGenerated asc, Throttled desc Traitez aussi les champs manquants comme une preuve. Si le workspace ne permet pas de voir l’opération, le status code ou l’information de partition, le premier correctif peut être l’observabilité, pas la capacité.
Lire le comportement de retry client
Les retries des SDK Cosmos sont utiles, mais ils peuvent masquer un problème de production jusqu’à ce que la latence devienne visible. Vérifiez si l’application a changé le nombre de retries, le timeout, la région préférée, le niveau de consistance ou le pattern de requête.
Checks client
Version SDK changee dans le dernier deploiement
Nombre de retries et attente maximale connus
Diagnostics de requete journalises pour les operations en echec
Regions preferees inchangees
Niveau de consistance pas renforce sur le chemin chaud
Bulk mode ou parallel query settings sans amplification inattendue
Bloquer le scaling aveugle quand
Les 429 apparaissent seulement apres le nouveau deploiement
Les retries ont augmente mais la latence de bout en bout aussi
Le request charge par operation a fortement change
Les logs n'identifient pas operation ou contexte de partition key
Le meme profil utilisateur ou tenant apparait dans la majorite des echecs Si les retries absorbent la plupart des 429, le symptôme utilisateur peut être la latence plutôt que l’erreur. Cela reste important. Une tempête de retries peut consommer plus de threads client, garder les connexions plus longtemps et rendre le rollback plus difficile à interpréter.
Comparer la forme des opérations avant et après déploiement
La preuve la plus utile vient souvent du delta. Une nouvelle requête qui scanne plus de documents, manque un chemin indexé ou fan-out entre partitions peut ressembler à un incident de capacité.
let Before = AzureDiagnostics
| where TimeGenerated between (datetime(2026-07-12T07:20:00Z) .. datetime(2026-07-12T08:10:00Z))
| where ResourceProvider == "MICROSOFT.DOCUMENTDB"
| extend Operation = tostring(operationName_s)
| extend RequestCharge = todouble(requestCharge_s)
| summarize BeforeRequests=count(), BeforeRU=sum(RequestCharge), BeforeP95RU=percentile(RequestCharge, 95) by Operation;
let After = AzureDiagnostics
| where TimeGenerated between (datetime(2026-07-12T08:20:00Z) .. datetime(2026-07-12T09:10:00Z))
| where ResourceProvider == "MICROSOFT.DOCUMENTDB"
| extend Operation = tostring(operationName_s)
| extend RequestCharge = todouble(requestCharge_s)
| extend StatusCode = tostring(statusCode_s)
| summarize AfterRequests=count(), AfterRU=sum(RequestCharge), AfterP95RU=percentile(RequestCharge, 95), After429=countif(StatusCode == "429") by Operation;
Before
| join kind=fullouter After on Operation
| extend RUChange = AfterRU - BeforeRU
| order by After429 desc, RUChange desc Un After429 élevé sur un chemin d’écriture suggère une pression de capacité ou de partition. Un delta RU élevé sur un chemin de lecture ou de query suggère plutôt la forme de requête, l’indexation ou le fan-out. La décision n’est pas la même.
Valider indexation et requêtes avant scaling
Quand l’incident suit une release, inspectez les requêtes et la politique d’indexation avant de modifier les RU/s. Le but n’est pas de tout optimiser pendant l’incident. Le but est de trouver une explication sûre au nouveau coût de requête.
Questions de validation
Quel endpoint ou job a introduit la nouvelle requete ?
Filtre-t-elle par partition key ?
Trie-t-elle sur un chemin indexe ?
Utilise-t-elle OFFSET LIMIT ou un CONTAINS large ?
Lit-elle beaucoup de documents pour produire une petite reponse ?
La politique d'indexation a-t-elle change pres de la fenetre d'incident ?
Une operation de reindexation en arriere-plan est-elle en cours ?
Actions sures pendant l'incident
Desactiver ou rollbacker le nouveau chemin de requete
Reduire la taille de batch du job touche
Mettre en pause un backfill non critique
Router la recherche couteuse vers un read model plus sur
Scaler seulement avec condition de rollback et expiration Si l’application a introduit une requête cross-partition sur un chemin utilisateur chaud, le scaling peut acheter du temps, mais le rollback ou la correction de requête reste le correctif durable.
Construire une matrice de décision
Rendez la décision explicite pour éviter de traiter “plus de RU” comme le seul résultat acceptable.
Augmenter RU/s ou autoscale max RU/s
La consommation RU est saturee au niveau container
Le throttling touche plusieurs operations et ranges de partition
L'augmentation de trafic est attendue ou critique
La forme de requete et les retries n'expliquent pas le pic
Le scaling a owner, expiration et checks de validation
Rollbacker le deploiement
Le throttling commence apres une release
Un nouvel endpoint, job ou query domine le delta RU
Le request charge par operation augmente anormalement
L'impact utilisateur est lie au chemin change
La version precedente est connue et rollbackable
Corriger partition ou forme de workload
Un range de partition domine le throttling
Un tenant, client, campagne ou batch drive la pression
Lectures ou ecritures sont desequilibrees par cle
Le scaling masquerait le desequilibre sans retirer le risque
Maintenir et ameliorer les preuves
Les diagnostic logs n'identifient pas operation ou status
Les logs applicatifs omettent request charge et retry count
Le mode de capacite est ambigu
Aucun test sur ne prouve le chemin modifie La matrice doit être attachée à l’incident. Elle protège l’équipe contre un changement de capacité que personne ne pourra expliquer ensuite.
Appliquer une mitigation bornée
Quand le scaling est justifié, bornez-le. Une hausse de throughput est un changement d’exploitation : elle demande une cible, une fenêtre de validation, une condition de rollback ou de réduction, et un owner.
change:
target: cosmos-commerce-prod / commerce / orders
action: increase_autoscale_max_ru
reason: container-wide throttling across operations and partition ranges
owner: platform-oncall
validation_window: 30 minutes
success:
- 429 rate decreases on affected operations
- checkout latency returns to expected range
- retry count decreases in application logs
- no new hot partition dominates request charge
rollback_or_reduce_when:
- rollback of application removes RU pressure
- throttling persists on one partition only
- cost guardrail or change window expires
- diagnostics prove query or indexing regression Si la mitigation est un rollback, gardez la même discipline : déployer la version précédente, surveiller le taux de 429, le request charge et la latence, et ne pas toucher au throughput sauf si le rollback ne réduit pas la pression.
Garder l’artefact post-incident
L’artefact final doit être réutilisable. Il doit expliquer pourquoi l’équipe a scalé, rollbacké ou changé le workload, et quelles preuves permettraient de détecter le prochain événement plus tôt.
Resultat incident
Cause primaire:
Operation touchee:
Preuve partition:
Delta request charge:
Comportement retry:
Mode de throughput:
Mitigation:
Condition de rollback ou reduction:
Suivi:
- ajouter request charge et retry count aux logs applicatifs
- dashboard 429 par operation et range de partition
- revoir la forme des requetes dans la checklist de deploiement
- documenter owner et expiration autoscale quand utilise en mitigation Cette note vaut plus que le nombre exact de RU. Elle transforme l’incident en chemin de diagnostic répétable au lieu d’un souvenir de dashboard sous tension.
Conclusion
Un incident 429 Cosmos DB n’est pas automatiquement un incident de capacité. C’est un signal que le workload, la distribution des partitions, la forme des requêtes, la politique de retry et le throughput provisionné ne sont plus alignés.
Le runbook sûr consiste à prouver le mode de capacité, séparer saturation globale et partition chaude, comparer le coût des opérations avant et après déploiement, valider les changements de requête et d’indexation, puis décider : scaling borné, rollback de release, correction de forme de workload, ou amélioration des preuves avant de toucher à la production. Le meilleur résultat n’est pas toujours plus de RU/s. C’est une décision validable et réversible.