Profi6 Min. Lesezeit

Warum ein DynamoDB-GSI Base-Table-Writes drosselt

Du schreibst auf deine Tabelle. Der Write scheitert mit einer Throughput- Exception — aber die Exception nennt einen Global Secondary Index, nicht die Tabelle. Die Tabelle hat Spare Capacity.

Aus SQL ist das Unsinn: ein Secondary Index kann kein INSERT blockieren. In DynamoDB kann er das, und der Mechanismus heißt GSI Back-Pressure.

Warum drosselt ein DynamoDB-GSI Base-Table-Writes?

DynamoDB drosselt den Base-Table-Write, weil jeder Write auch in jeden GSI repliziert — und wenn eine GSI-Partition ihren Anteil nicht absorbieren kann, wendet DynamoDB Back-Pressure an, damit der Index nicht dauerhaft zurückfällt. Ein unterprovisionierter oder low-cardinality GSI-Key wird so zur harten Decke deiner Base-Table-Write-Rate.

  • Ein Write auf die Base Table schreibt auch in jeden GSI. Wenn ein GSI seinen Anteil nicht absorbieren kann, drosselt DynamoDB den Base-Table-Write, damit der Index nicht dauerhaft zurückfällt. (AWS docs)
  • Eine gleichmäßige Base Table rettet dich nicht. Der GSI ist nach seinem eigenen Key partitioniert. Ein low-cardinality GSI-Key (wie status) erzeugt eine , selbst wenn Base-Table-Writes perfekt verteilt sind.
  • Die Exception lügt über das Opfer. Die ResourceArn zeigt auf den GSI; die Operation, die wirklich gedrosselt wird, ist dein Write auf die Tabelle.
  • Der Fix ist Capacity oder Key-Design, nicht Retry-Loops — hebe GSI- Throughput an, oder wähle einen GSI-, der streut.

Wie ein einzelner Write den Index berührt

Ein PutItem auf der Base Table ist nicht ein Write. DynamoDB repliziert die projezierten Attribute des Items asynchron in jeden GSI, auf einem eventually consistent Modell. Ein logischer Write fächert zu N physischen Writes auf — Tabelle plus jeder Index.

Diese Replikation ist nicht gratis und nicht optional. Der GSI muss mithalten, sonst driftet der Index bei jeder Operation weiter von der Tabelle weg.

Um diesen Drift zu stoppen, wendet DynamoDB Back-Pressure an: es drosselt den Source-Write, damit der Index nie ungebunden stale wird.

Die Write Capacity des GSI ist also eine harte Decke deiner Base-Table-Write- Rate — obwohl du nie direkt auf den GSI schreibst.

Praxisbeispiel: eine Orders-Tabelle

Angenommen, du betreibst eine Orders-Tabelle. Das Base-Item:

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

Base-Table-Writes sind gesund. CUST#... hat hohe Kardinalität, also streuen Order-Writes gleichmäßig über Base-Partitionen. Kein Hot Key, reichlich Capacity.

Jetzt fügst du einen GSI hinzu, um „zeig mir jede Order in einem gegebenen State“ zu beantworten:

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

Vier mögliche Partition-Key-Werte. Während eines Flash Sale landet fast jede neue Order in order_state = "PENDING". Jeder dieser Writes trifft dieselbe GSI-Partition.

Diese Partition hat ein Per-Partition-Throughput-Limit, und du hast gerade deinen gesamten Write-Storm darauf gerichtet.

Die Base Table ist fine. Die PENDING-GSI-Partition brennt. DynamoDB drosselt das Base-Table-PutItem, um den Index zu schützen.

Der Flow, der dich beißt

Back-Pressure-Pfad — Base-Write balanciert, Index-Write konzentriert:

PutItemorder_state=PENDINGBase Tableverteilt nach CUST#Async replizierenzum GSIGSI-PartitionPENDING (heiß)Partition-LimitüberschrittenBASE-Writedrosseln

Eine heiße GSI-Partition lehnt den Base-Table-Write ab, der sie gefüttert hat.

Lies die Exception, nicht dein Bauchgefühl

Der Exception-Typ sagt dir genau, welche Decke du getroffen hast. Die ResourceArn nennt den GSI; die gedrosselte Op ist trotzdem der Table-Write.

ModeReason codeWas ausging
ProvisionedIndexWriteProvisionedThroughputExceededprovisionierte Write Capacity des GSI
BothIndexWriteKeyRangeThroughputExceededeine einzelne heiße GSI-Partition
On-demandIndexWriteMaxOnDemandThroughputExceededkonfigurierte Max-On-Demand-Decke des GSI
On-demandIndexWriteAccountLimitExceededAccount-/Region-Throughput-Grenze

Quelle: Understanding GSI write throttling and back pressure.

Der KeyRange-Reason ist der Verräter für den Hot-Partition-Fall oben: die Gesamt-GSI-Capacity kann fine aussehen, während eine Key-Range gesättigt ist.

So behebst du es

Gib dem GSI Raum. Die einfachste Ursache ist Under-Provisioning. Ein GSI hat seine eigene Read- und Write-Capacity, vollständig getrennt von der Tabelle — siehe GSI vs LSI.

Hast du die Tabelle großzügig provisioniert und den GSI dünn gelassen, hebe die Write Capacity des GSI an (oder sein On-Demand-Max).

Fix den Partition Key. Capacity rettet keinen low-cardinality Key — du kannst eine einzelne heiße Partition nicht herausprovisionieren. Wähle einen GSI- Partition Key, der streut.

Compose ihn: order_state#shard, wobei shard ein kleines Random-Suffix ist, oder fold das Datum ein (PENDING#2026-06-23). Writes streuen über Partitionen und du Queryst einen State weiterhin, indem du die Shards queryst.

Projeziere weniger Attribute. Jeder GSI-Write kopiert die projezierten Attribute. Eine KEYS_ONLY- oder enge INCLUDE-Projektion heißt kleinere Index-Writes und weniger Druck als ALL. Projeziere nicht, was du nie vom Index liest.

Drop den GSI, wenn er nur für Reporting ist. Wenn „Orders by State“ eine gelegentliche Admin-Frage ist, kein Hot Path, kann ein periodischer Scan mit Filter einen permanent heißen Index schlagen — wäge es gegen Query vs Scan.

Wenn du diesen Index queryst, schreibt der Expression Builder die KeyConditionExpression für dich — z. B. #s = :state AND begins_with(SK, :prefix) — mit korrekt escaped Names und Values:

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

Die Falle zum Merken

Der relationale Instinkt — „Indexes verlangsamen Writes nur ein bisschen“ — überträgt sich nicht. Ein DynamoDB-GSI ist eine Throughput-Dependency, keine passive Struktur. Unterdimensioniere ihn oder wähle einen klumpenden Key, und er übt Back-Pressure auf die Tabelle aus, die er bedient.

Beobachte ConsumedWriteCapacityUnits und WriteThrottleEvents auf der GSI- Dimension, nicht nur der der Tabelle, und nutze Contributor Insights, um die heißen Keys zu finden.

Nächste Schritte

  • GSI vs LSI — warum ein GSI eigene Capacity und einen anderen Partition Key hat.
  • Single-Table Design — einen GSI überladen, um viele Patterns zu bedienen, ohne heiße Indexes zu multiplizieren.
  • Query vs Scan — wann ein Index seine Write-Kosten nicht wert ist.

Probier DynoTable, um jeden GSI auf deinen Tabellen zu inspizieren — Key Schema und Item Counts — und deine Indexes zu querien, bevor ein Sale sie rot färbt.

Aktualisiert