Avanzado7 min de lectura

Por qué un GSI throttlea las escrituras de la tabla base en DynamoDB

Escribes en tu tabla. La escritura falla con una excepción de rendimiento — pero la excepción nombra un Global Secondary Index, no la tabla. La tabla tiene capacidad de sobra.

Si vienes de SQL, eso es absurdo: un índice secundario no puede bloquear un INSERT. En DynamoDB sí puede, y el mecanismo se llama back-pressure del GSI.

¿Por qué un GSI de DynamoDB throttlea las escrituras de la tabla base?

DynamoDB throttlea la escritura de la tabla base porque cada escritura también se replica en cada GSI, y si una partición del GSI no puede absorber su parte, DynamoDB aplica back-pressure para evitar que el índice se quede atrás de forma permanente. Así que una clave de GSI infraaprovisionada o de baja cardinalidad se convierte en un techo duro para tu tasa de escritura en la tabla base.

  • Una escritura en la tabla base también escribe en cada GSI. Si un GSI no puede absorber su parte, DynamoDB throttlea la escritura de la tabla base para evitar que el índice se quede atrás permanentemente. (Documentación de AWS)
  • Una tabla base equilibrada no te salva. El GSI se particiona por su propia clave. Una clave de GSI de baja cardinalidad (como status) crea una partición de índice caliente incluso cuando las escrituras de la tabla base están perfectamente repartidas.
  • La excepción miente sobre la víctima. El ResourceArn apunta al GSI; la operación que realmente se está throttleando es tu escritura en la tabla.
  • La solución es capacidad o diseño de clave, no bucles de reintento — sube el rendimiento del GSI, o elige una clave de partición de GSI que reparta.

Cómo una sola escritura toca el índice

Un PutItem en la tabla base no es una sola escritura. DynamoDB replica los atributos proyectados del item en cada GSI de forma asíncrona, con un modelo eventualmente consistente. Una escritura lógica se abre en abanico a N escrituras físicas — la tabla más cada índice.

Esa replicación no es gratis ni opcional. El GSI debe mantener el ritmo, o el índice se aleja más de la tabla en cada operación.

Para frenar ese desfase, DynamoDB aplica back-pressure: throttlea la escritura de origen para que el índice nunca quede irremediablemente obsoleto.

Así que la capacidad de escritura del GSI es un techo duro para tu tasa de escritura en la tabla base — aunque nunca escribas directamente en el GSI.

Un ejemplo trabajado: una tabla de pedidos

Supón que gestionas una tabla de pedidos. El item base:

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

Las escrituras de la tabla base están sanas. CUST#... tiene alta cardinalidad, así que las escrituras de pedidos se reparten de forma equitativa entre las particiones base. Sin clave caliente, capacidad de sobra.

Ahora añades un GSI para responder "muéstrame todos los pedidos en un estado dado":

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

Cuatro posibles valores de clave de partición. Durante una venta flash, casi todos los pedidos nuevos aterrizan en order_state = "PENDING". Cada una de esas escrituras golpea la misma partición del GSI.

Esa partición tiene un límite de rendimiento por partición, y acabas de apuntar toda tu tormenta de escritura hacia ella.

La tabla base está bien. La partición PENDING del GSI está ardiendo. DynamoDB throttlea el PutItem de la tabla base para proteger el índice.

El flujo que te muerde

Aquí está la ruta del back-pressure — escritura base equilibrada, escritura de índice concentrada:

PutItemorder_state=PENDINGTabla baserepartida por CUST#Replicación asíncronaal GSIPartición del GSIPENDING (caliente)Límite de particiónsuperadoThrottlear laescritura BASE

El throttle viaja hacia atrás: una partición caliente del GSI rechaza la escritura de la tabla base que la alimentó.

Lee la excepción, no tu intuición

El tipo de excepción te dice exactamente qué techo alcanzaste. El ResourceArn nombra el GSI; la operación throttleada sigue siendo la escritura en la tabla.

ModoCódigo de razónQué se agotó
AprovisionadoIndexWriteProvisionedThroughputExceededCapacidad de escritura aprovisionada del GSI
AprovisionadoIndexWriteKeyRangeThroughputExceededUna sola partición caliente del GSI
On-demandIndexWriteMaxOnDemandThroughputExceededEl techo máximo on-demand configurado del GSI
On-demandIndexWriteAccountLimitExceededLímite de rendimiento de cuenta/región

Fuente: Understanding GSI write throttling and back pressure.

La razón KeyRange es la pista para el caso de partición caliente de arriba: la capacidad global del GSI puede parecer correcta mientras un rango de claves está saturado.

Cómo arreglarlo

Dale espacio al GSI. La causa más simple es el infraaprovisionamiento. Un GSI tiene su propia capacidad de lectura y escritura, totalmente separada de la tabla — ver GSI vs LSI.

Si aprovisionaste la tabla con generosidad y dejaste el GSI escaso, sube la capacidad de escritura del GSI (o su máximo on-demand).

Arregla la clave de partición. La capacidad no salvará una clave de baja cardinalidad — no puedes superaprovisionar para superar una sola partición caliente. Elige una clave de partición de GSI que reparta.

Compónla: order_state#shard donde shard es un pequeño sufijo aleatorio, o incorpora la fecha (PENDING#2026-06-23). Las escrituras se reparten entre particiones y aún puedes hacer Query de un estado consultando los shards.

Proyecta menos atributos. Cada escritura del GSI copia los atributos proyectados. Una proyección KEYS_ONLY o un INCLUDE ajustado significa escrituras de índice más pequeñas y menos presión que ALL. No proyectes lo que nunca leerás del índice.

Elimina el GSI si solo es para reporting. Si "pedidos por estado" es una pregunta ocasional de administración, no una ruta caliente, un scan periódico con un filtro puede ganarle a un índice permanentemente caliente — sopésalo frente a Query vs Scan.

Cuando consultes ese índice, el Expression Builder escribe el KeyConditionExpression por ti — p. ej. #s = :state AND begins_with(SK, :prefix) — con los nombres y valores escapados correctamente:

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

La trampa que recordar

El instinto relacional — "los índices solo ralentizan un poco las escrituras" — no se transfiere. Un GSI de DynamoDB es una dependencia de rendimiento, no una estructura pasiva. Dimensiónalo por debajo o elige una clave que se amontone, y aplica back-pressure a la tabla a la que sirve.

Vigila el ConsumedWriteCapacityUnits y ThrottledRequests del GSI por partición, no solo los de la tabla.

Próximos pasos

  • GSI vs LSI — por qué un GSI tiene su propia capacidad y una clave de partición diferente.
  • Diseño de tabla única — sobrecargar un GSI para servir muchos patrones sin multiplicar índices calientes.
  • Query vs Scan — cuándo un índice no merece su coste de escritura.

Prueba DynoTable para observar la capacidad consumida de un GSI y los eventos de throttle contra tus propias tablas antes de que una venta las ponga en rojo.

Actualizado