Avancé7 min de lecture

Pourquoi un GSI throttle les écritures de la table de base dans DynamoDB

Tu écris dans ta table. L'écriture échoue avec une exception de débit — mais l'exception nomme un Global Secondary Index, pas la table. La table a de la capacité de reste.

En venant de SQL, c'est absurde : un index secondaire ne peut pas bloquer un INSERT. Dans DynamoDB il le peut, et le mécanisme s'appelle la back-pressure 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 est aussi répliquée vers chaque GSI, et si une partition de GSI ne peut pas absorber sa part, DynamoDB applique une back-pressure pour empêcher l'index de prendre un retard permanent. Ainsi une clé de GSI sous-provisionnée ou à faible cardinalité devient un plafond strict sur ton débit d'écriture de table de base.

  • Une écriture sur 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 permanent. (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 partition d'index chaude 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 sur la table.
  • La solution, c'est la capacité ou la conception de clé, pas des boucles de retry — augmente le débit du GSI, ou choisis une clé de partition de GSI qui répartit.

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éploie en N écritures physiques — la table plus chaque index.

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

Pour stopper cette dérive, DynamoDB applique la back-pressure : il throttle l'écriture source pour que l'index ne devienne jamais indéfiniment périmé.

Ainsi la capacité d'écriture du GSI est un plafond strict sur ton débit d'écriture de la table de base — même si 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 forte cardinalité, donc les écritures de commandes se répartissent équitablement sur les partitions de base. Pas de clé chaude, plein de capacité.

Maintenant tu ajoutes un GSI pour répondre à « montre-moi chaque commande 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 de viser toute ta tempête d'écritures dessus.

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 back-pressure — écriture de base équilibrée, écriture d'index concentrée :

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

Le throttle remonte à l'envers : une partition de GSI chaude rejette l'écriture de la table de base qui l'a alimentée.

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
ProvisionnéIndexWriteKeyRangeThroughputExceededUne seule partition de GSI chaude
On-demandIndexWriteMaxOnDemandThroughputExceededPlafond on-demand max configuré du GSI
On-demandIndexWriteAccountLimitExceededLimite de débit du compte/de la région

Source : Understanding GSI write throttling and back pressure.

La raison KeyRange est l'indice révélateur du cas de partition chaude ci-dessus : la capacité globale du GSI peut sembler correcte tandis qu'une seule plage de clé est saturée.

Comment corriger ça

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

Si tu as provisionné la table généreusement et laissé le GSI maigre, augmente la capacité d'écriture du GSI (ou son max on-demand).

Corrige la clé de partition. La capacité ne sauvera pas une clé à faible cardinalité — tu ne peux pas sur-provisionner une seule partition chaude. 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 sur les partitions et tu fais toujours un Query d'un état en requêtant 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 « commandes par état » est une question d'admin occasionnelle, pas un chemin chaud, un scan périodique avec un filtre peut battre un index en permanence chaud — pèse ça face à Query vs Scan.

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

KeyConditionExpression     "#s = :state"
ExpressionAttributeNames   { "#s": "order_state" }
ExpressionAttributeValues  { ":state": { "S": "PENDING" } }

Le piège à retenir

L'instinct relationnel — « les index ne ralentissent les écritures qu'un peu » — ne se transfère 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 fera back-pressure sur la table qu'il sert.

Surveille le ConsumedWriteCapacityUnits et les ThrottledRequests du GSI par partition, pas seulement ceux de la table.

Étapes suivantes

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

Essaie DynoTable pour observer la capacité consommée et les événements de throttle d'un GSI sur tes propres tables avant qu'une vente ne les fasse virer au rouge.

Mis à jour