Leer wat Amazon DynamoDB is, hoe het NoSQL-model werkt en praktische ontwerp-patronen voor schaalbare, lage-latentie systemen en microservices.

Amazon DynamoDB is een volledig beheerde NoSQL-database van AWS, ontworpen voor applicaties die consistente, lage-latentie reads en writes nodig hebben op vrijwel elke schaal. "Volledig beheerd" betekent dat AWS de infrastructuur regelt—hardware provisioning, replicatie, patching en veel operationele taken—zodat teams zich kunnen richten op het uitrollen van features in plaats van op het beheren van databaseservers.
In de kern slaat DynamoDB gegevens op als items (rijen) binnen tabellen, maar elk item kan flexibele attributen hebben. Het datamodel is het beste te begrijpen als een mix van:
Teams kiezen DynamoDB wanneer ze voorspelbare performance en eenvoudigere operaties willen voor workloads die niet goed passen bij relationele joins. Het wordt vaak gebruikt voor microservices (elke service bezit zijn data), serverless-apps met bursty verkeer en event-driven systemen die reageren op datavernieuwingen.
Dit artikel loopt door de bouwstenen (tabellen, sleutels en indexen), hoe je modelleert rond toegangspatronen (inclusief single-table-ontwerp), hoe schaling en capaciteitsmodi werken, en praktische patronen om wijzigingen te streamen naar een event-driven architectuur.
DynamoDB is georganiseerd rond een paar eenvoudige bouwstenen, maar de details zijn belangrijk omdat ze bepalen hoe je data modelleert en hoe snel (en kosteneffectief) verzoeken zijn.
Een tabel is de bovenste container. Elk record in een tabel is een item (vergelijkbaar met een rij), en elk item is een set attributen (vergelijkbaar met kolommen).
In tegenstelling tot relationele databases hoeven items in dezelfde tabel niet dezelfde attributen te delen. Het ene item kan {status, total, customerId} hebben, terwijl een ander {status, shipmentTracking} bevat—DynamoDB vereist geen vast schema.
Elk item wordt uniek geïdentificeerd door een primaire sleutel, en DynamoDB ondersteunt twee typen:
In de praktijk maken samengestelde sleutels "gegroepeerde" toegangspatronen mogelijk zoals "alle bestellingen voor een klant, nieuwste eerst."
Een Query leest items op basis van de primaire sleutel (of een indexsleutel). Het richt zich op een specifieke partitie en kan filteren op sorteersleutelbereiken—dit is het efficiënte, voorkeurskanaal.
Een Scan loopt de hele tabel (of index) door en filtert daarna. Het is makkelijk om mee te beginnen, maar meestal trager en duurder op schaal.
Een paar beperkingen die je vroeg zult tegenkomen:
Deze fundamenten zetten alles klaar wat volgt: toegangspatronen, indexkeuzes en performancekenmerken.
DynamoDB wordt vaak beschreven als zowel een key-value store als een documentdatabase. Dat klopt, maar het helpt om te begrijpen wat elk daarvan in de dagelijkse ontwerppraktijk betekent.
In de kern haal je data op via een sleutel. Geef de primaire sleutelwaarden op en DynamoDB geeft een enkel item terug. Die sleutelgebaseerde lookup levert voorspelbare, lage-latentie opslag voor veel workloads.
Tegelijk kan een item geneste attributen bevatten (maps en lists), waardoor het aanvoelt als een documentdatabase: je kunt gestructureerde payloads opslaan zonder vooraf een rigide schema te definiëren.
Items passen natuurlijk bij JSON-achtige data:
profile.name, profile.address).Dit is een goede match wanneer een entiteit meestal als geheel gelezen wordt—zoals een gebruikersprofiel, een winkelwagen of een configuratiebundle.
DynamoDB ondersteunt geen server-side joins. Als je app in één leesoperatie "een bestelling plus regelitems plus verzendstatus" nodig heeft, zul je vaak denormaliseren: kopieer attributen naar meerdere items, of embed kleine substructuren direct in een item.
Denormalisatie verhoogt schrijfcomplexiteit en kan update fan-out veroorzaken. De winst is minder rondritten en snellere reads—vaak het kritieke pad in schaalbare systemen.
De snelste DynamoDB-queries zijn die je kunt uitdrukken als "geef mij deze partitie" (en optioneel "binnen deze partitie, geef mij dit bereik"). Daarom gaat sleutelkeuze vooral over hoe je data leest, niet alleen hoe je het opslaat.
De partitiesleutel bepaalt naar welke fysieke partition een item gaat. DynamoDB hasht deze waarde om data en verkeer te verspreiden. Als veel verzoeken zich concentreren op een klein aantal partitiesleutelwaarden, kun je "hot" partitions creëren en throughput-limieten raken, zelfs als de tabel verder rustig is.
Goede partitiesleutels:
"GLOBAL")Met een sorteersleutel worden items met dezelfde partitiesleutel samen opgeslagen en geordend op de sorteersleutel. Dit maakt efficiënte:
BETWEEN, begins_with)Een veelgebruikt patroon is het samenstellen van de sorteersleutel, zoals TYPE#id of TS#2025-12-22T10:00:00Z, om meerdere queryvormen te ondersteunen zonder extra tabellen.
PK = USER#<id> (simpel GetItem)PK = USER#<id>, SK begins_with ORDER# (of SK = CREATED_AT#...)PK = DEVICE#<id>, SK = TS#<timestamp> met BETWEEN voor tijdvenstersAls je partitiesleutel aansluit op je meest gebruikte queries en gelijkmatig verdeelt, krijg je consistente lage-latentie reads en writes. Zo niet, dan compenseer je met scans, filters of extra indexen—elk met meer kosten en een groter risico op hot keys.
Secundaire indexen geven DynamoDB alternatieve querypaden buiten de primaire sleutel van je tabel. In plaats van je basistabel te hervormen voor elk nieuw toegangspatroon kun je een index toevoegen die dezelfde items her-sleutelt voor een ander querydoel.
Een Global Secondary Index (GSI) heeft zijn eigen partitiesleutel (en optionele sorteersleutel) die compleet verschillend kan zijn van die van de tabel. Het is "global" omdat het over alle tabelpartities heen gaat en op elk moment toegevoegd of verwijderd kan worden. Gebruik een GSI voor een nieuw toegangspatroon dat niet past bij het originele sleutelontwerp—bijv. orders op customerId queryen als de tabel op orderId is ge-keyed.
Een Local Secondary Index (LSI) deelt de zelfde partitiesleutel als de basistabel maar gebruikt een andere sorteersleutel. LSI's moeten bij het aanmaken van de tabel worden gedefinieerd. Ze zijn nuttig als je meerdere sorteringen binnen dezelfde entiteitgroep wilt (dezelfde partitiesleutel), zoals orders van een klant sorteren op createdAt versus status.
Projectie bepaalt welke attributen DynamoDB in de index opslaat:
Elke write naar de basistabel kan writes naar één of meer indexen triggeren. Meer GSI's en brede projecties verhogen schrijfkosten en capacity gebruik. Plan indexen rond stabiele toegangspatronen en houd geprojecteerde attributen minimaal waar mogelijk.
DynamoDB-scaling begint met één keuze: On-Demand of Provisioned capaciteit. Beide kunnen zeer hoge throughput aan, maar ze gedragen zich anders bij veranderend verkeer.
On-Demand is het eenvoudigst: je betaalt per verzoek en DynamoDB past zich automatisch aan variërende belasting aan. Het is een goede keuze voor onvoorspelbaar verkeer, vroege producten en bursty workloads waarbij je geen capaciteitstargets wilt beheren.
Provisioned is capaciteitsplanning: je specificeert (of auto-scaleert) read- en write-throughput en krijgt voorspelbaardere prijzen bij steady gebruik. Het is vaak goedkoper voor bekende, consistente workloads en voor teams die vraag kunnen voorspellen.
Provisioned throughput wordt gemeten in:
Je itemgrootte en toegangspatroon bepalen de echte kosten: grotere items, sterke consistentie en scans kunnen capaciteit snel verbruiken.
Auto scaling past provisioned RCUs/WCUs aan op basis van benuttingsdoelen. Het helpt bij geleidelijke groei en voorspelbare cycli, maar het is niet direct. Plotselinge spikes kunnen nog steeds throttlen als capaciteit niet snel genoeg omhoog gaat, en het lost geen hot partition-problemen op die verkeer naar één key concentreren.
DynamoDB Accelerator (DAX) is een in-memory cache die read-latentie kan verminderen en herhaalde reads kan ontlasten (bijv. populaire productpagina's, sessie-lookup, leaderboards). Het is het meest nuttig wanneer veel clients dezelfde items herhaaldelijk opvragen; het helpt niet bij write-zware patronen en vervangt geen zorgvuldig sleutelontwerp.
DynamoDB laat je kiezen tussen leesgaranties versus latency en kosten, dus het is belangrijk expliciet te zijn over wat "correct" betekent voor elke operatie.
Standaard gebruiken GetItem en Query eventually consistent reads: je kunt kort na een write een oudere waarde zien. Dit is vaak acceptabel voor feeds, productcatalogi en andere read-zware views.
Met strongly consistent reads (een optie voor reads van de basistabel in één regio) garandeert DynamoDB dat je de laatst erkende write ziet. Strong consistency kost meer read capacity en kan de tail-latency verhogen, dus reserveer het voor echt kritieke reads.
Strong consistency is waardevol voor reads die onomkeerbare acties afdwingen:
Voor tellers is de veiligste aanpak meestal geen "sterke read gevolgd door write", maar een atomische update (bijv. UpdateItem met ADD) zodat increments niet verloren gaan.
DynamoDB-transacties (TransactWriteItems, TransactGetItems) bieden ACID-semantiek over tot 25 items. Ze zijn nuttig wanneer je meerdere items samen moet bijwerken—zoals het schrijven van een order en het reserveren van voorraad—of invarianten moet afdwingen die geen tussenliggende toestanden tolereren.
Retries zijn normaal in gedistribueerde systemen. Maak writes idempotent zodat retries effecten niet dupliceren:
ConditionExpression (bijv. "only create if attribute_not_exists")Correctheid in DynamoDB draait meestal om het kiezen van het juiste consistentieniveau en het ontwerpen van operaties zodat retries je data niet breken.
DynamoDB slaat tabeldata over meerdere fysieke partitions op. Elke partition heeft beperkte throughput voor reads en writes, plus een limiet aan hoeveel data het kan bewaren. Je partitiesleutel bepaalt waar een item woont; als te veel verzoeken naar dezelfde partitiesleutelwaarde (of een klein aantal waarden) gaan, wordt die partition de bottleneck.
Hot partitions ontstaan meestal door sleutelkeuzes die verkeer concentreren: een "globale" partitiesleutel zoals USER#1, TENANT#default of STATUS#OPEN, of tijd-geordende patronen waarbij iedereen schrijft naar "nu" onder één sleutel.
Je ziet meestal:
ProvisionedThroughputExceededException) voor een subset van keysOntwerp eerst voor distributie, daarna voor querygemak:
TENANT#<id> in plaats van een gedeelde constante).ORDER#<id>#<shard> om writes over N shards te spreiden, en query over shards wanneer nodig.METRIC#2025-12-22T10) om te voorkomen dat "alle writes naar het nieuwste item" gaan.Voor onvoorspelbare spikes kan on-demand capaciteit pieken absorberen (binnen service-limieten). Bij provisioned capaciteit gebruik auto scaling en implementeer client-side exponentiële backoff met jitter bij throttles om gesynchroniseerde retries te voorkomen die de piek versterken.
DynamoDB-datamodeling begint bij toegangspatronen, niet bij ER-diagrammen. Ontwerp je sleutels zodat de queries die je nodig hebt snelle Query-operaties worden, terwijl alles wat overblijft of wordt vermeden of asynchroon wordt afgehandeld.
"Single-table-ontwerp" betekent meerdere entiteitstypen (users, orders, messages) in één tabel opslaan en consistente sleutelconventies gebruiken om gerelateerde data in één Query te halen. Dit vermindert cross-entity rondreizen en houdt latency voorspelbaar.
Een veelgebruikte aanpak is samengestelde sleutels:
PK groepeert een logische partition (bijv. USER#123)SK ordent items binnen die groep (bijv. PROFILE, ORDER#2025-12-01, MSG#000123)Dit laat je "alles voor een gebruiker" of "alleen orders voor een gebruiker" ophalen door een sort-key prefix te kiezen.
Voor graph-achtige relaties werkt een adjacency list goed: sla edges op als items.
PK = USER#123, SK = FOLLOWS#USER#456Om reverse lookups of echte many-to-many te ondersteunen, voeg een omgekeerd edge-item toe of projecteer naar een GSI, afhankelijk van de leespaden.
Voor events en metrics, vermijd onbegrensde partitions door te bucketen:
PK = DEVICE#9#2025-12-22 (device + dag)SK = TS#1734825600 (timestamp)Gebruik TTL om oude punten automatisch te laten verlopen, en bewaar aggregaten (per uur/per dag) als aparte items voor snelle dashboards.
Als je een diepere opfrisser wilt over sleutelconventies, zie partition-key-and-sort-key-design.
DynamoDB Streams is de ingebouwde change data capture (CDC) feed van DynamoDB. Wanneer ingeschakeld op een tabel, produceert elke insert, update of delete een streamrecord waar downstream consumenten op kunnen reageren—zonder de tabel te hoeven pollën.
Een streamrecord bevat sleutels en (optioneel) de oude en/of nieuwe afbeelding van het item, afhankelijk van de stream view type die je kiest (keys only, new image, old image, both). Records zijn gegroepeerd in shards, die je sequentieel leest.
Een veelvoorkomende opstelling is DynamoDB Streams → AWS Lambda, waarbij elke batch records een functie triggert. Andere consumenten zijn ook mogelijk (custom consumers, of doorsturen naar analytics/logsystemen).
Typische workflows omvatten:
Dit houdt de primaire tabel geoptimaliseerd voor lage-latentie reads/writes en duwt afgeleide verwerking naar asynchrone consumenten.
Streams bieden geordende verwerking per shard (wat doorgaans correleert met de partitiesleutel), maar er is geen globale ordering over alle keys. Levering is at-least-once, dus duplicaten kunnen voorkomen.
Om dit veilig te verwerken:
Ontworpen met deze garanties in gedachten, kunnen Streams van DynamoDB een solide ruggengraat maken voor event-driven systemen.
DynamoDB is ontworpen voor hoge beschikbaarheid door data over meerdere Availability Zones binnen een regio te verspreiden. Voor de meeste teams komen de praktische betrouwbaarheidwinst uit een duidelijke backupstrategie, het begrijpen van replicatieopties en het monitoren van de juiste metrics.
On-demand backups zijn handmatige (of geautomatiseerde) snapshots die je neemt wanneer je een bekende restore-point wilt—voor een migratie, na een release of voorafgaand aan een grote backfill. Ze zijn ideaal voor "bookmarks".
Point-in-time recovery (PITR) legt continu wijzigingen vast zodat je de tabel naar elk gewenst moment binnen de retentieperiode kunt herstellen. PITR is het vangnet voor per ongeluk verwijderen, slechte deploys of foutieve writes.
Als je multi-region veerkracht of lage-latentie reads dicht bij gebruikers nodig hebt, repliceren Global Tables data over geselecteerde regio's. Ze vereenvoudigen failoverplanning, maar introduceren replicatievertraging en conflict-resolutieoverwegingen—houd schrijfpatronen en item-eigendom duidelijk.
Minimaal, waarschuw op:
Deze signalen tonen meestal hot-partition issues, onvoldoende capaciteit of onverwachte toegangspatronen.
Bij throttling, identificeer eerst het toegangspatroon dat het veroorzaakt, mitigeren door tijdelijk naar on-demand te schakelen of provisioned capaciteit te verhogen, en overweeg sharding van hot keys.
Bij gedeeltelijke storingen of verhoogde fouten, verklein het blast radius: schakel niet-kritisch verkeer uit, retry met jittered backoff en degradeer gracieus (bijv. bedien gecachte reads) totdat de tabel stabiliseert.
DynamoDB-beveiliging gaat vooral over wie welke API-acties mag aanroepen, vanaf waar en op welke keys. Omdat tabellen veel entiteitstypen (en soms veel tenants) kunnen bevatten, moet toegangscontrole samen met het datamodel ontworpen worden.
Begin met identity-based IAM-policies die acties beperken (bijv. dynamodb:GetItem, Query, PutItem) tot het minimum en scope ze naar specifieke tabel-ARNs.
Voor fijnmazigere controle gebruik dynamodb:LeadingKeys om toegang per partitiesleutelwaarden te beperken—handig wanneer een service of tenant alleen items in zijn eigen keyspace mag lezen/schrijven.
DynamoDB versleutelt data at rest standaard met AWS-owned keys of een customer-managed KMS-key. Als je compliance-eisen hebt, verifieer:
Voor encryptie in transit, zorg dat clients HTTPS gebruiken (AWS SDKs doen dit standaard). Als je TLS terminateert in een proxy, bevestig dat de hop tussen de proxy en DynamoDB nog steeds versleuteld is.
Gebruik een VPC Gateway Endpoint voor DynamoDB zodat verkeer op het AWS-netwerk blijft en je endpoint-policies kunt toepassen om toegang te beperken. Combineer dit met egress-controls (NACLs, security groups en routing) om te voorkomen dat "alles naar het openbare internet kan".
Voor gedeelde tabellen, voeg een tenant-identificator toe in de partitiesleutel (bijv. TENANT#<id>), en handhaaf tenantisolatie met IAM-condities op dynamodb:LeadingKeys.
Als je strengere isolatie nodig hebt, overweeg aparte tabellen per tenant of per omgeving, en reserveer gedeelde-tabellen voor gevallen waar operationele eenvoud en kosten-efficiëntie zwaarder wegen dan een kleiner blast radius.
DynamoDB is vaak "goedkoop als je precies bent, duur als je vaag bent." Kosten volgen doorgaans je toegangspatronen, dus de beste optimalisaties beginnen met die patronen expliciet maken.
Je factuur wordt hoofdzakelijk bepaald door:
Een veelvoorkomende verrassing: elke write naar een tabel is ook een write naar elke getroffen GSI, dus "nog een index" kan schrijfkosten vermenigvuldigen.
Goed sleutelontwerp vermindert de noodzaak voor dure operaties. Als je vaak Scan nodig hebt, betaal je om data te lezen die je weggooit.
Geef de voorkeur aan:
Query per partitiesleutel (en optioneel sorteersleutelcondities)Als een toegangspatroon zeldzaam is, overweeg het via een aparte tabel, een ETL-job of een gecachte leesmodel te bedienen in plaats van een permanente GSI.
Gebruik TTL om tijdelijk items (sessies, tokens, tussenliggende workflowstatus) automatisch te verwijderen. Dit verkleint opslag en houdt indexen in de tijd kleiner.
Voor append-heavy data (events, logs) combineer TTL met sorteersleutelontwerpen waarmee je "alleen recent" kunt queryen zodat je niet routinematig koude historie raakt.
In provisioned mode, stel conservatieve baselines en scale met auto scaling op basis van echte metrics. In on-demand mode, let op inefficiënte patronen (grote items, chatty clients) die verzoekvolume opdrijven.
Behandel Scan als laatste redmiddel—wanneer je echt full-table processing nodig hebt, plan het off-peak of voer het gecontroleerd uit met paginering en backoff.
DynamoDB blinkt uit wanneer je applicatie als een set goed gedefinieerde toegangspatronen kan worden uitgedrukt en je consistente lage latency op grote schaal nodig hebt. Als je je reads en writes van tevoren kunt beschrijven (per partitiesleutel, sorteersleutel en een klein aantal indexen) is het vaak één van de eenvoudigste manieren om een zeer beschikbare datastore te beheren.
DynamoDB is een sterke keuze als je hebt:
Kijk elders als je kernvereisten omvatten:
Veel teams gebruiken DynamoDB voor “hot” operationele reads/writes en voegen dan toe:
Als je toegangspatronen en single-table-conventies valideert, is snelheid belangrijk. Teams prototypen soms de service en UI in Koder.ai (een vibe-coding platform dat web, server en mobiele apps bouwt vanuit chat) en itereren dan op het DynamoDB-sleutelontwerp naarmate echte querypaden opduiken. Zelfs als je productie-backend verschilt, helpen snelle end-to-end prototypes om te onthullen welke queries Query-operaties zouden moeten zijn versus welke per ongeluk dure scans worden.
Valideer: (1) je topqueries zijn bekend en key-based, (2) correctheidsbehoeften passen bij het consistentiemodel, (3) verwachte itemgroottes en -groei zijn begrepen, en (4) het kostenmodel (on-demand vs provisioned plus autoscaling) past binnen je budget.
DynamoDB is een volledig beheerde NoSQL-database van AWS, ontworpen voor consistent lage latency bij lezen/schrijven op zeer grote schaal. Teams kiezen het wanneer ze sleutelgebaseerde toegangspatronen kunnen definiëren (ophalen per ID, lijst per eigenaar, tijdsvensters) en geen database-infrastructuur zelf willen beheren.
Het wordt vaak gebruikt in microservices, serverless-apps en event-driven systemen.
Een tabel bevat items (zoals rijen). Elk item is een flexibele set attributen (zoals kolommen) en kan geneste gegevens bevatten.
DynamoDB werkt goed wanneer één verzoek meestal “hele entiteit” nodig heeft, omdat items maps en lists kunnen bevatten (JSON-achtige structuren).
Een partitiesleutel (partition key) alleen identificeert een item uniek (eenvoudige primaire sleutel). Een partitiesleutel + sorteersleutel (composite key) laat meerdere items dezelfde partitiesleutel delen terwijl ze uniek blijven en geordend worden door de sorteersleutel.
Composite keys maken patronen mogelijk zoals:
Gebruik Query wanneer je de partitiesleutel kunt opgeven (en optioneel een sorteersleutelvoorwaarde). Het is de snelle, schaalbare route.
Gebruik Scan alleen als je echt alles moet lezen; het doorloopt de hele tabel of index en filtert daarna, wat doorgaans trager en duurder is.
Als je vaak scant, is dat een teken dat je sleutel- of indexontwerp moet worden aangepast.
Secundaire indexen bieden alternatieve querypaden.
Indexen verhogen de schrijfkosten omdat wijzigingen naar de indexen worden gerepliceerd.
Kies On-Demand als het verkeer onvoorspelbaar of bursty is, of je geen capaciteit wilt beheren. Je betaalt per verzoek.
Kies Provisioned als het gebruik stabiel of voorspelbaar is en je de kosten beter wilt beheersen. Combineer het met auto scaling, maar realiseer je dat het niet altijd instant reageert op plotselinge pieken.
Standaard zijn reads eventually consistent, wat betekent dat je kort na een write een oudere waarde kunt lezen.
Gebruik strongly consistent reads voor kritieke checks die actuele data vereisen, zoals autorisaties of workflowstappen.
Voor correctheid onder concurrency heeft het de voorkeur om atomische updates te gebruiken (bijv. conditionele writes of ADD) boven read-modify-write loops.
Transacties (TransactWriteItems, TransactGetItems) bieden ACID-garanties over maximaal 25 items.
Gebruik ze wanneer je meerdere items samen moet bijwerken (bijv. een order aanmaken en voorraad reserveren) of invarianten moet afdwingen die geen gedeeltelijke updates toestaan.
Ze kosten meer en verhogen latency, dus gebruik ze alleen voor flows die ze echt nodig hebben.
Hot partitions ontstaan wanneer te veel verzoeken naar dezelfde partitiesleutelwaarde (of een klein aantal waarden) gaan, waardoor throttling optreedt, zelfs als de tabel verder onderbenut is.
Veelvoorkomende mitigaties:
Schakel DynamoDB Streams in om een change feed te krijgen voor inserts, updates en deletes. Een veelgebruikt patroon is Streams → Lambda om downstream werk te triggeren.
Belangrijke garanties om voor te ontwerpen:
Maak consumenten (upsert per sleutel, gebruik conditionele writes of sla verwerkte event-ID's op).