Profi7 Min. Lesezeit

Wie DynamoDB intern speichert

DynamoDB ist eine Hashtabelle, deren Werte sortierte Bäume sind, verteilt über Maschinen in drei Availability Zones. Zwei Datenstrukturen erledigen fast die ganze Arbeit: Ein Hash auf den wählt eine Maschine, ein B-Baum auf den ordnet die Items darin.

Wie speichert DynamoDB Daten?

DynamoDB speichert deine Daten als riesige verteilte Hashtabelle, deren Werte sortierte B-Bäume sind. Ein Hash auf den wählt einen Storage-Knoten; darin ordnet ein B-Baum die Items nach Sort Key. Jeder Schreibvorgang geht an einen Leader, der ihn an zwei Peers über drei Availability Zones repliziert und bestätigt, sobald ein Quorum (zwei der drei Replikate) ihn hat.

  • Der Partition Key wird gehasht, nicht durchsucht. DynamoDB lässt eine Hash-Funktion über deinen PK laufen, um den Storage-Knoten zu finden (oder die Knoten, sobald eine große Collection sich teilt), der diese Partition hält — ein O(1)-Sprung, unabhängig von der Tabellengröße.
  • Der Sort Key lebt in einem B-Baum. Innerhalb einer Partition werden Items in einem B-Baum gespeichert, geordnet nach Sort Key — UTF-8-Byte-Reihenfolge bei Strings, numerische Reihenfolge bei Number-Keys — und genau deshalb sind Bereichslesevorgänge (begins_with, between) günstig und ein Scan nicht.
  • Jeder Schreibvorgang committet auf einem Quorum, bevor er bestätigt wird. Ein Schreibvorgang geht an einen Leader, der ihn an zwei Peers in anderen AZs repliziert und bestätigt, sobald ein Quorum (zwei der drei Replikate) ihn hat — Dauerhaftigkeit ist bezahlt, bevor dein PutItem zurückkehrt.
  • Deshalb gibt es die Zugriffsmuster-Regeln. Hash-dann-Baum ist nur schnell, wenn du über den Key liest. Kein Key, kein schneller Pfad — du fällst darauf zurück, den Baum zu scannen.

Beginne bei der Datenstruktur, nicht beim API

Aus der SQL-Welt stellst du dir eine Tabelle als Zeilen auf der Platte vor, mit einem Query-Planner, der Indizes wählt. DynamoDB hat keinen Planner. Das Speicherlayout ist der Vertrag — was schnell ist und was ein Footgun ist, folgt beides direkt aus zwei Strukturen.

Stell dir eine riesige verteilte Map vor. Der Key ist ein Hash deines Partition Keys. Der Wert ist ein ganzer B-Baum aus Items, die sich diesen Partition Key teilen, geordnet nach Sort Key.

Alles Weitere — Query-Semantik, die 10-GB-Warnungen, warum ein fehlender Key einen Scan erzwingt — ist eine Folge dieses einen Satzes.

Den Partition Key hashen, um den Knoten zu finden

Wenn ein Request eintrifft, wendet DynamoDB eine interne Hash-Funktion auf den Partition-Key-Wert an. Der Hash bildet deterministisch auf einen Storage-Knoten ab — die physische Partition, der diese Items gehören. AWS dokumentiert das als den Mechanismus hinter Key-Lookups in konstanter Zeit, unabhängig von der Tabellengröße.

Das ist der O(1)-Schritt. Eine 10-TB-Tabelle und eine 10-KB-Tabelle kosten dasselbe, um lokalisiert zu werden: hashen, springen, fertig. Es gibt keinen Index-Scan, um den Knoten zu finden, keine Statistiken, keinen Plan.

Der Haken ist die Kehrseite. Lieferst du den Partition Key nicht mit, hat DynamoDB keinen Knoten, zu dem es springen könnte — es muss jede Partition ablaufen. Das ist ein Scan, und das ist der Unterschied zwischen O(1) und dem Lesen der ganzen Tabelle.

PutItem / GetItemPK=DEVICE#a91Hash(PK)Speicherknoten(eine Partition)B-Baum auf SKREADING#... geordnetItem

Der Request hasht auf genau eine Partition und steigt dann in deren Sort-Key-B-Baum bis zum Item hinab — zwei günstige Schritte statt eines Tabellendurchlaufs.

Items im B-Baum je Partition ordnen

Innerhalb einer einzelnen Partition sind Items kein Haufen. Sie liegen in einem B-Baum, der über den Sort Key gekeyt ist, lexikografisch geordnet. Eine B-Baum-Suche ist O(log n), und entscheidend ist: Dieses n sind die Items in einer Partition, nicht in der ganzen Tabelle.

Das ist der ganze Grund, warum Sort-Key-Bereichslesevorgänge günstig sind. Nimm eine Flotten-Telemetrietabelle, in der die Messwerte jedes Geräts unter einem Partition Key liegen:

PKSK
PK = DEVICE#a91SK = READING#2026-06-23T08:00Z
PK = DEVICE#a91SK = READING#2026-06-23T08:05Z
PK = DEVICE#a91SK = READING#2026-06-23T08:10Z

Weil der B-Baum sortiert ist, ist „alle Messwerte zwischen 08:00 und 09:00“ ein Abstieg im Baum bis zum Startwert plus ein sequenzieller Lauf — kein Filter über jeden Messwert, den das Gerät je gesendet hat. Du liest nur den getroffenen Bereich.

Diese Ordnung ist auch der Grund, warum eine Abfrage begins_with(SK, "READING#2026-06-23") schnell ist, das Filtern auf ein Nicht-Key-Attribut aber nicht. Der Baum kann nach SK suchen; nach irgendetwas anderem kann er es nicht. Um solche Key-Bedingungen sicher zusammenzusetzen, baue sie im DynamoDB Expression Builder, statt Strings von Hand zu verketten:

KeyConditionExpression  PK = :pk AND begins_with(SK, :day)

Jeden Schreibvorgang in drei AZs replizieren

Eine Partition ist nicht eine Maschine. Jede wird über drei Knoten in drei Availability Zones repliziert — das Leader-basierte Quorum-Design, das im DynamoDB-Paper der USENIX ATC 2022 beschrieben wird (das Amazon-Dynamo-Paper von 2007 ist der Namens- und Philosophie-Vorfahr, nicht dieses Replikationsmodell).

Ein Knoten ist der Leader der Partition. Ein Schreibvorgang geht an den Leader, der lokal schreibt und an seine zwei Peers repliziert. Der Leader bestätigt den Schreibvorgang, sobald ein dauerhaftes Quorum an Knoten ihn hat — Dauerhaftigkeit über AZs hinweg ist also bezahlt, bevor dein PutItem zurückkehrt.

Beim Lesen hast du die Wahl. Ein Lesevorgang geht an den Leader und sieht den zuletzt committeten Schreibvorgang. Ein Lesevorgang kann von jedem der drei Knoten bedient werden, und einer davon kann ein paar Millisekunden hinterherhinken — das ist die Verzögerung, die du gegen günstigere, verfügbarere Lesevorgänge eintauschst.

Letztendlich konsistentStark konsistent
Bedient vonEinem beliebigen der 3 KnotenNur dem Leader-Knoten
Sieht den letzten SchreibvorgangVielleicht (kleine Verzögerung)Immer
RCU-KostenHalb (0,5 RCU pro 4 KB bei On-Demand in us-east-1)Voll (1 RCU pro 4 KB)
VerfügbarkeitHöherNiedriger (ein Knoten)

Bei On-Demand-Abrechnung kostet ein stark konsistenter Lesevorgang eines 2 KB großen Items 1 RCU; derselbe Lesevorgang letztendlich konsistent kostet 0,5 RCU. Rechne deine Hot Paths im Preisrechner durch.

Dieselbe Idee der asynchronen Propagierung ist der Grund, warum ein GSI-Lesevorgang veraltet sein kann — siehe GSIs sind letztendlich konsistent.

Die Regeln direkt aus der Struktur ablesen

Fast jede DynamoDB-„Regel“ ist schlicht Speicherphysik:

  • Liefere immer den Partition Key. Kein Key, kein Hash-Ziel — du scannst die ganze Map. Das ist der Kern von Query vs. Scan.
  • Lege zusammen, was du zusammen liest, unter einen Partition Key, damit ein einzelner Hash + Baumdurchlauf die ganze Item Collection zurückgibt. Das ist die Grundlage von Single-Table-Design.
  • Halte Partitionen begrenzt. Eine Partition ist ein B-Baum auf einer endlichen Menge von Knoten; ein außer Kontrolle geratener Hot Key und die 10-GB-Grenze eines LSI sind beides Limits dieser physischen Partition.

Sobald du die Form „Hash, dann B-Baum“ siehst, fühlt sich die Disziplin bei den Zugriffsmustern nicht mehr willkürlich an — du hältst einfach jeden Lesevorgang auf dem schnellen Pfad.

Nächste Schritte

Modelliere deine Keys passend zur Struktur mit Sort-Key-Strategien und Single-Table-Design, und setze die tatsächlichen Ausdrücke dann im DynamoDB Expression Builder zusammen. Probier DynoTable aus, um diese Lesevorgänge gegen deine eigenen Tabellen laufen zu sehen und genau zu erkennen, welche Items eine Key-Bedingung zurückholt.

Aktualisiert