Profi6 Min. Lesezeit

DynamoDB-Migrationen ohne Downtime

Aus SQL ist eine Migration ein ALTER TABLE, das die Tabelle sperrt, während es jede Row umschreibt. DynamoDB hat kein Schema zum Ändern — Items sind schemaless, also ist ein Attribut oder ein neuer Entity-Typ gratis hinzuzufügen.

Der harte Teil ist das Access Pattern, das die neuen Daten bedienen müssen, und Live-Daten so umzuformen, dass sie es bedienen — ohne Stop-the-World-Rewrite.

Wie migrierst du eine DynamoDB-Tabelle ohne Downtime?

DynamoDB hat kein ALTER TABLE, also sperren Migrationen die Tabelle nie. Du fügst Attribute, eine neue Key-Form oder einen neuen online mit UpdateTable hinzu und formst Live-Daten inkrementell um: alte Items lazy on Read oder mit gedrosseltem Sweep backfüllen, und während des Übergangs beide Formate dual-writen. Es gibt keinen Flag-Day-Cutover.

  • Es gibt kein ALTER TABLE. Items sind schemaless. Eine „Migration“ heißt Attribute, eine neue Key-Form oder einen neuen Index hinzufügen — nie ein fixes Column-Set umschreiben.
  • Neue Writes sind leicht; alte Items sind das Problem. Die bestehenden Rows tragen die neuen Attribute nicht, also verfehlt jeder neue Index oder jede neue Query sie still, bis du backfüllst.
  • Indexes online hinzufügen, lazy backfüllen. UpdateTable baut einen GSI auf einer Live-Tabelle; backfülle alte Items on Read (lazy) oder mit kontrolliertem Sweep — nie Flag-Day-Cutover.
  • Dual-Write über den Übergang. Solange beide Formen koexistieren, schreibe altes und neues Format zusammen, damit kein Read-Pfad veraltet.

Als Access Pattern framen, nicht als Spalte

Angenommen, du betreibst ein SaaS-Workspace-Produkt auf einer Tabelle. Items nutzen PK = "WS#<id>" und SK pro Entity:

PKSKattributes
WS#a91METAname, tier
WS#a91DOC#2026-04-01#x7title, author, body
WS#a91DOC#2026-04-02#k2title, author, body

Jetzt will Product Comments auf Documents, plus einen neuen Read: „liste jeden Comment, den ein Member workspace-weit geschrieben hat, neueste zuerst.“ Dieser letzte Satz ist die Migration. Ein neuer Entity-Typ allein ist trivial; eine Query zu bedienen, die die aktuellen Keys nicht beantworten können, ist die Arbeit.

Zuerst den neuen Entity-Typ hinzufügen

Comments sind einfach neue Items in derselben Partition — keine Migrationszeremonie, keine neue Tabelle:

PKSKattributes
WS#a91DOC#2026-04-01#x7#CMT#01HZ...author, text, createdAt

Eine Query auf PK = "WS#a91" mit SK begins_with "DOC#2026-04-01#x7#CMT#" listet schon die Comments eines Documents. Bestehende Documents bleiben unberührt. Diese Hälfte shipped am Tag eins — siehe Item Collections und überladene Keys, warum dieselbe Partition beides hält.

Die neue Query braucht einen GSI

„Alle Comments eines Members, neueste zuerst“ kann die Base Table nicht bedienen — memberId ist weder der PK noch ein SK-Prefix. Das ist ein neuer Index, und ihn richtig zu wählen ist eine eigene Entscheidung: siehe GSI vs LSI (ein LSI muss bei Table Creation existieren, also ist für eine Migration auf einer Live-Tabelle ein GSI deine einzige Option).

Füge einen generischen GSI1 hinzu und schreibe die neuen Attribute auf neue Comment-Items:

GSI1PKGSI1SK
MEMBER#u442026-04-02T09:15:00Z

Query GSI1 WHERE GSI1PK = "MEMBER#u44" mit ScanIndexForward = false liefert neueste-zuerst Comments pro Member.

Den Index online bauen

UpdateTable fügt einen GSI einer Live-Tabelle ohne Downtime hinzu. DynamoDB backfüllt bestehende Items im Hintergrund in den Index; der Index meldet CREATING/backfilling bis fertig, dann flippt er zu ACTIVE (Managing GSIs).

UpdateTable: GSI1 hinzufügenIndex-Status: CREATINGBestehende Items backfüllenStatus: ACTIVEQuery GSI1 sicher

Zwei Fallen hier. Erstens warnt AWS, dass das Hinzufügen eines Base-Table-Writes drosseln kann, wenn der neue Key ungleich verteilt — füge ihn in einem Low-Traffic-Fenster hinzu und schau CloudWatch. Zweitens ist der Index , selbst nachdem er ACTIVE ist; ein Write kann einen Moment auf dem GSI unsichtbar sein. Siehe warum GSIs eventuell konsistent sind.

Die alten Items backfüllen

Der GSI indexiert nur Items, die GSI1PK/GSI1SK haben. Deine Pre-Migration-Comments — geschrieben, bevor das Attribut existierte — erscheinen nie, selbst nachdem Backfill fertig ist. Online-GSI-Backfill kopiert bestehende Items, kann aber Attribute nicht erfinden, die nicht auf ihnen liegen. Du musst die Werte hinzufügen.

Zwei Strategien:

StrategieWie sie funktioniertNutzen wenn
LazyBeim Read eines alten Items die neuen Attribute zurückschreibenAlte Items werden oft gelesen; Kosten tröpfeln
SweepEin paginierter Scan updated jedes alte Item einmalDer GSI muss bis Deadline komplett sein

Für den Sweep page mit Scan durch, und für jeden alten Comment füge die Index-Attribute mit conditional UpdateItem hinzu, damit du nie einen concurrent Write überschreibst.

Die Condition schützt darauf, dass das Attribut noch nicht existiert. Baue und kopiere die exakte ConditionExpression und UpdateExpression mit dem DynamoDB Expression Builder, statt attribute_not_exists(GSI1PK) handzutippen.

Dual-Write durch den Übergang

Bis jedes alte Item die neuen Attribute trägt, koexistieren zwei Formen. Der Write-Pfad muss das neue Format bei jedem Write befüllen — neue Comments und jedes Update an einem alten — damit die Lücke nur schrumpft.

Wähle eine Backfill-Endbedingung, die du verifizieren kannst: der Sweep hat die ganze Tabelle gepaged, oder der Lazy-Pfad lief lange genug, dass unkonvertierte Items by Design stale sind. Erst dann entfernst du den alten Read-Pfad. Das zu überspringen ist, wie eine Migration „fertig“ wird, während ein Bruchteil der Queries still zu kurze Results liefert.

Eine Tabelle in DynoTable pagen, um Items ohne die neuen Index-Attribute während eines Backfills zu finden.
Eine Tabelle in DynoTable pagen, um Items ohne die neuen Index-Attribute während eines Backfills zu finden.

Fallstricke

  • Attribut hinzufügen ≠ backgefüllt. Ein neuer GSI startet für alte Items leer. Verifiziere Coverage, bevor du der Query vertraust.
  • Einen Key in Place ändern ist ein Rewrite. Du kannst den PK/SK eines Items nicht mutieren; du schreibst ein neues Item unter dem neuen Key und löschst das alte. Plane es als Copy-then-Delete, Dual-Read dazwischen.
  • Kein transaktionaler Cutover. Es gibt keinen Moment, in dem die ganze Tabelle flippt. Designe jeden Schritt so, dass er sicher ist, während beide Formen live sind.

Nächste Schritte

Sanity-check die neuen Keys und überladenen Collections in Single-Table Design, und bestätige, dass das Backfill komplett ist, indem du die Live-Tabelle pagest. Probier DynoTable, um deine Tabelle zu browsen, un-backgefüllte Items zu finden und die conditional Updates gegen deine eigenen Daten zu fahren.

Aktualisiert