Avancé7 min de lecture

Pourquoi un GSI throttle la table de base

Tu écris dans ta table. L'écriture échoue avec une exception de débit — mais l'exception nomme un index secondaire global, pas la table. La table a de la capacité disponible.

Quand tu viens du SQL, c'est absurde : un index secondaire ne peut pas bloquer un INSERT. Dans DynamoDB, si — et le mécanisme s'appelle la contre-pression du GSI.

Pourquoi un GSI DynamoDB throttle-t-il les écritures de la table de base ?

DynamoDB throttle l'écriture de la table de base parce que chaque écriture se réplique aussi vers chaque GSI, et si une partition de GSI ne peut pas absorber sa part, DynamoDB applique une contre-pression pour empêcher l'index de prendre un retard définitif. Une clé de GSI sous-provisionnée ou à faible cardinalité devient donc un plafond dur sur ton taux d'écriture dans la table de base.

  • Une écriture dans la table de base écrit aussi dans chaque GSI. Si un GSI ne peut pas absorber sa part, DynamoDB throttle l'écriture de la table de base pour empêcher l'index de prendre un retard définitif. (docs AWS)
  • Une table de base équilibrée ne te sauve pas. Le GSI est partitionné par sa propre clé. Une clé de GSI à faible cardinalité (comme status) crée une même quand les écritures de la table de base sont parfaitement réparties.
  • L'exception ment sur la victime. Le ResourceArn pointe vers le GSI ; l'opération réellement throttlée est ton écriture dans la table.
  • Le correctif est la capacité ou la conception des clés, pas des boucles de réessai — augmente le débit du GSI, ou choisis une de GSI qui répartit bien.

Comment une seule écriture touche l'index

Un PutItem sur la table de base n'est pas une seule écriture. DynamoDB réplique les attributs projetés de l'item dans chaque GSI de façon asynchrone, sur un modèle à cohérence à terme. Une écriture logique se démultiplie en N écritures physiques — la table plus chaque index.

Cette réplication n'est ni gratuite ni optionnelle. Le GSI doit suivre le rythme, sinon l'index dérive un peu plus loin de la table à chaque opération.

Pour arrêter cette dérive, DynamoDB applique une contre-pression : il throttle l'écriture source afin que l'index ne devienne jamais indéfiniment obsolète.

La capacité d'écriture du GSI est donc un plafond dur sur ton taux d'écriture dans la table de base — alors même que tu n'écris jamais directement dans le GSI.

Un exemple concret : une table de commandes

Disons que tu gères une table de commandes. L'item de base :

fieldvaluenote
PK"CUST#8841"partition key
SK"ORD#2026-06-23#A7"sort key
order_state"PROCESSING"
warehouse"EU-MAD-2"
total_cents4990

Les écritures de la table de base sont saines. CUST#... a une cardinalité élevée, donc les écritures de commandes se répartissent uniformément entre les partitions de base. Pas de clé surchargée, capacité largement suffisante.

Maintenant tu ajoutes un GSI pour répondre à « montre-moi toutes les commandes dans un état donné » :

GSI: orders-by-state
fieldvaluenote
GSI-PKorder_state"PENDING" | "PROCESSING" | "SHIPPED" | "CANCELED"
GSI-SKSK

Quatre valeurs de clé de partition possibles. Pendant une vente flash, presque chaque nouvelle commande atterrit dans order_state = "PENDING". Chacune de ces écritures frappe la même partition de GSI.

Cette partition a une limite de débit par partition, et tu viens d'y diriger toute ta tempête d'écritures.

La table de base va bien. La partition de GSI PENDING est en feu. DynamoDB throttle le PutItem de la table de base pour protéger l'index.

Le flux qui te mord

Voici le chemin de la contre-pression — écriture de base équilibrée, écriture d'index concentrée :

PutItemorder_state=PENDINGTable de baserépartie par CUST#Réplication asyncvers le GSIPartition GSIPENDING chaud)Limite de partitiondépasséeThrottle l'écriturede BASE

Le throttling remonte à contre-courant : une partition de GSI surchargée rejette l'écriture de la table de base qui l'alimentait.

Lis l'exception, pas ton intuition

Le type d'exception te dit exactement quel plafond tu as atteint. Le ResourceArn nomme le GSI ; l'opération throttlée reste l'écriture de la table.

ModeCode de raisonCe qui a manqué
ProvisionnéIndexWriteProvisionedThroughputExceededCapacité d'écriture provisionnée du GSI
Les deuxIndexWriteKeyRangeThroughputExceededUne seule partition de GSI surchargée
À la demandeIndexWriteMaxOnDemandThroughputExceededPlafond max à la demande configuré du GSI
À la demandeIndexWriteAccountLimitExceededLimite de débit du compte/de la région

Source : Understanding GSI write throttling and back pressure.

La raison KeyRange est le signe révélateur du cas de partition surchargée ci-dessus : la capacité globale du GSI peut paraître correcte alors qu'une seule plage de clés est saturée.

Comment le corriger

Donne de l'air au GSI. La cause la plus simple est le sous-provisionnement. Un GSI a sa propre capacité de lecture et d'écriture, entièrement séparée de la table — voir GSI vs LSI.

Si tu as provisionné la table généreusement mais laissé le GSI à sec, augmente la capacité d'écriture du GSI (ou son max à la demande).

Corrige la clé de partition. La capacité ne sauvera pas une clé à faible cardinalité — tu ne peux pas sur-provisionner ta sortie d'une seule partition surchargée. Choisis une clé de partition de GSI qui répartit.

Compose-la : order_state#shardshard est un petit suffixe aléatoire, ou intègre la date (PENDING#2026-06-23). Les écritures se répartissent entre les partitions et tu peux toujours Query un état en interrogeant les shards.

Projette moins d'attributs. Chaque écriture de GSI copie les attributs projetés. Une projection KEYS_ONLY ou un INCLUDE serré signifie des écritures d'index plus petites et moins de pression que ALL. Ne projette pas ce que tu ne liras jamais depuis l'index.

Supprime le GSI s'il ne sert qu'au reporting. Si « les commandes par état » est une question d'administration occasionnelle, pas un chemin critique, un scan périodique avec filtre peut battre un index en permanence surchargé — pèse ça face à Query vs Scan.

Quand tu interroges cet index, l' Expression Builder écrit la KeyConditionExpression pour toi — par ex. #s = :state AND begins_with(SK, :prefix) — avec les noms et valeurs échappés correctement :

KeyConditionExpression     "#s = :state AND begins_with(SK, :prefix)"
ExpressionAttributeNames   { "#s": "order_state" }
ExpressionAttributeValues  { ":state": { "S": "PENDING" }, ":prefix": { "S": "ORD#2026-06-23" } }

Le piège à retenir

L'instinct relationnel — « les index ne ralentissent qu'un peu les écritures » — ne se transpose pas. Un GSI DynamoDB est une dépendance de débit, pas une structure passive. Sous-dimensionne-le ou choisis une clé qui s'agglutine, et il exerce une contre-pression sur la table qu'il sert.

Surveille ConsumedWriteCapacityUnits et WriteThrottleEvents sur la dimension du GSI, pas seulement sur celle de la table, et utilise Contributor Insights pour trouver les clés surchargées.

Étapes suivantes

  • GSI vs LSI — pourquoi un GSI a sa propre capacité et une clé de partition différente.
  • Single-table design — surcharger un seul GSI pour servir plusieurs patterns sans multiplier les index surchargés.
  • Query vs Scan — quand un index ne vaut pas son coût d'écriture.

Essaie DynoTable pour inspecter chaque GSI de tes tables — schéma de clés et nombre d'items — et interroger tes index avant qu'une vente ne les fasse virer au rouge.

Mis à jour