Fortgeschritten7 Min. Lesezeit

Singleton-Items in DynamoDB

Ein Singleton-Item ist eine einzelne Zeile mit einem festen, hartkodierten Key, die Zustand für deine ganze Anwendung hält — nicht ein Datensatz pro Nutzer oder pro Bestellung, sondern ein Datensatz, Punkt. Feature-Flags, ein Config-Blob, ein globaler Kill-Switch: die Art von Sache, die eine relationale App in einer Einzeilen-Settings-Tabelle halten würde.

Von SQL kommend würdest du zu einer config-Tabelle mit id = 1 und einem SELECT * FROM configgreifen. In DynamoDB machst du dasselbe mit einem hartkodierten Partition Key — und weil du diesen Key immer kennst, liest du ihn mit einemGetItem, nicht einer Queryoder einemScan.

Was ist ein Singleton-Item in DynamoDB?

Ein Singleton-Item ist eine einzelne DynamoDB-Zeile, die unter einem festen, hartkodierten Key gespeichert ist und globalen Zustand für deine gesamte Anwendung hält — Feature-Flags, einen Config-Blob, eine systemweite Version — statt eines Datensatzes pro Nutzer oder Bestellung. Weil du den Key immer kennst, liest du es mit einem GetItem und aktualisierst es mit - plus Condition-Expressions.

  • Ein Singleton ist ein Item mit konstantem Key. Du hartkodierst den PK/SK in deinem Code (z. B. CONFIG#GLOBAL), statt eine Nutzer- oder Bestell-ID einzusetzen.
  • Lies es mit GetItem, nie mit Scan. Du kennst immer den vollen Key, also ist ein Point Read eine konsistente, vorhersehbare RCU — kein Filter, kein Tabellendurchlauf.
  • Es ist per Definition ein Hot Key. Jeder Request kann dieselbe Partition berühren, also cache es und halte das Item klein; mach es nicht zum Schreib-Bottleneck.
  • Mutiere es sicher mit Update- + Condition-Expressions, nicht mit Read-Modify-Write in deiner App — dort lauert der Lost-Update-Race.

Das Muster erkennen

Du hast globalen Zustand, wenn die Daten an keine einzelne Entität gebunden sind. Ein paar Anzeichen:

  • Ein Flag, das für alle gleich ist (signup_enabled = false).
  • Ein Blob von Stellschrauben, die deine App beim Booten liest (Rate Limits, Standardkontingente).
  • Ein Zähler oder eine Versionsnummer für das ganze System, nicht pro Zeile.

Alles, was an einen Nutzer, Mandanten oder eine Bestellung gebunden ist, ist kein Singleton — das ist ein gewöhnliches Item, das durch die ID dieser Entität verschlüsselt ist. Das Singleton ist die übrige globale Scheibe, die nirgendwo sonst hinpasst.

Gib ihm einen konstanten Key

Das ganze Muster hängt an einer Entscheidung: Der Key ist ein Literal, kein Template. Für ein globales Feature-Flags-Item in einer überladenen Single-Table wähle ein festes Präfix und einen festen Wert:

PKSKattributes
SETTINGS#APPFLAGS#V1signup_enabled, maintenance_mode, ai_search_enabled

PK = "SETTINGS#APP" und SK = "FLAGS#V1" sind im Code festgebacken. Da gibt es keine Nutzer-ID, keine Mandanten-ID — die Anwendung fragt jedes Mal nach genau diesem Item. Diese Vorhersehbarkeit ist der Sinn: Ein bekannter Key ist ein GetItem, und ein GetItem ist der günstigste, konsistenteste Read, den DynamoDB bietet.

Das V1-Suffix ist gewollt. Wenn sich das Flag-Schema später in der Form ändert, schreibst du ein FLAGS#V2-Item und schaltest die Reader um, statt das Live-Item an Ort und Stelle zu mutieren. Den Singleton-Key zu versionieren verschafft dir eine saubere Migrations-Naht.

Lies es mit GetItem

Weil der Key vollständig bekannt ist, machst du für ein Singleton nie eine Query und nie einen Scan. Ein Scan liest die ganze Tabelle und filtert client-seitig — das klassische Scan-Footgun — und es ist absurder Overkill, um eine Zeile zu holen, die du direkt adressieren kannst.

Ein GetItem gegen SETTINGS#APP / FLAGS#V1 gibt die Flags in einem einzelnen stark oder letztendlich konsistenten Read zurück. AWS berechnet ein GetItem eines Items ≤ 4 KB als 0,5 RCU letztendlich konsistent oder 1 RCU stark konsistent (AWS Read/Write-Capacity-Doku). Halte das Singleton klein und diese Kosten bleiben für immer flach.

Der Read-Pfad ist einfach: App bootet oder ein Request landet, du machst ein GetItem auf den festen Key, du cachest das Ergebnis. Hier ist der Ablauf.

janeinApp / RequestGetItem PK=SETTINGS#APPSK=FLAGS#V1Item gefunden?Flags verwenden, lokal cachenAuf sichere Defaults zurückfallen

Der feste Key verwandelt einen globalen Lookup in einen Point Read mit eingebautem Default-Pfad.

Beachte den nein-Zweig: Ein fehlendes Singleton sollte dich nie zum Absturz bringen. Falle auf den sicheren Wert zurück (Feature aus, Maintenance an), damit eine Lücke beim ersten Deploy oder ein schlechter Key fail-closed scheitert, nicht fail-open.

Aktualisiere es ohne Race

Die Falle ist, ein Singleton mit Read-Modify-Write in deiner App zu aktualisieren: Du machst ein GetItem auf die Flags, kippst eines im Speicher, dann ein PutItem des ganzen Dings zurück. Zwei nebenläufige Writer lesen beide das alte Item und das zweite Put überschreibt die Änderung des ersten. Lost Update.

Zwei DynamoDB-Features töten den Race ohne app-seitiges Locking:

  • Update-Expressions mutieren ein Attribut server-seitig und lassen den Rest unberührt. Kein Bedarf, das ganze Item erneut zu Put-en.
  • Condition-Expressions lassen den Write nur gelingen, wenn das Item noch so aussieht, wie du es erwartest, sodass ein veralteter Write mit ConditionalCheckFailedException abgewiesen wird (AWS Condition-Expression-Doku).

Um ein Flag zu kippen, ziele nur auf dieses Attribut mit einem SET und sichere es mit einem Versions-Bump ab, damit nebenläufige Writer sich nicht gegenseitig zertreten:

# UpdateItem
Key                  PK=SETTINGS#APP  SK=FLAGS#V1
UpdateExpression     SET signup_enabled = :on, schema_version = :next
ConditionExpression  schema_version = :current

Wenn zwei Writer um die Wette laufen, scheitert der schema_version = :current- Check des zweiten und er versucht es erneut gegen den frischen Wert. Du kannst die Names, Values und genau diese Expression-Form im DynamoDB Expression Builder gerüstartig aufbauen, bevor du es in Code verdrahtest. Für einen tieferen Blick auf die Operatoren siehe den Guide zu den Update-Expression-Idiomen.

Achte auf den Hot Key

Ein Singleton ist konstruktionsbedingt ein Hot Key — jeder Teil deiner App kann dieselbe Partition lesen. Für Reads ist das in Ordnung, wenn du cachest, aber es ist das eine echte Risiko des Musters.

  • Cache aggressiv. Lies die Flags einmal pro Prozess (oder pro N Sekunden), nicht bei jedem Request. Der Wert des Singletons ist das Günstigste zum Memoisieren.
  • Mach es nicht zum Schreib-Hotspot. Ein Flag, das ein Admin ein paar Mal pro Tag umschaltet, ist nichts. Ein Singleton, das du bei jedem Request inkrementierst, ist ein Partition-Throughput-Bottleneck — das ist ein Zähler-Problem, kein Singleton.
  • Halte es klein. Read-Kosten skalieren mit der Item-Größe in 4-KB-Blöcken. Ein aufgeblähter Config-Blob macht jeden Boot teurer, als er sein müsste.

Wenn du wirklich einen globalen Zähler mit hoher Schreibrate brauchst, ist das Singleton die falsche Form — sharde ihn über N Items und summiere beim Read. Das ist ein anderes Muster.

Singleton vs. Per-Entity-Item

Die Linie ist einfach, woran die Daten gebunden sind.

Singleton-ItemPer-Entity-Item
KeyHartkodierte Konstante (SETTINGS#APP)Mit ID templated (USER#42)
Wie vieleGenau einesEines pro Nutzer / Bestellung / Mandant
Typischer ReadGetItem auf den bekannten KeyGetItem oder Query nach Entität
ScopeGanze AnwendungEine einzelne Entität
Verwenden fürGlobale Flags, Config, SystemversionProfile, Bestellungen, alles pro ID

Wenn du dich dabei ertappst, zwei Singletons derselben Art zu wollen, hast du kein Singleton — du hast ein Per-Entity-Item und die Entität ist das, nach dem zu verschlüsseln du vergessen hast (etwa Per-Mandant-Config).

Fallstricke und nächste Schritte

  • Mach keinen Scan dafür. Du kennst den Key; adressiere ihn direkt.
  • Mach kein Read-Modify-Write damit. Verwende Update- + Condition-Expressions.
  • Lass es nicht still fehlen. Falle bei einem Cache-Miss auf den sicheren Wert zurück.
  • Überlade es nicht mit hochfrequenten Writes. Das ist ein Sharded-Counter-Job.

Das Singleton lebt bequem in einem Single-Table-Design — es ist einfach eine weitere Item-Collection mit festem Key neben deinen Entitätszeilen.

Probiere DynoTable aus, um deine Tabelle zu durchsuchen, die Singleton-Zeile an ihrem festen Key zu finden und Flags von Hand zu bearbeiten, während du den Schreibpfad baust.

Aktualisiert