Contatori atomici DynamoDB: come funziona ADD e quando non funziona
Un contatore atomico è un attributo numerico che metti in posizione con un singolo
Chiamata UpdateItem: nessuna lettura prima, nessuna corsa di lettura-modifica-scrittura. Si applica DynamoDB
ogni incremento nell'ordine di arrivo e non consente mai a due scrittori di ostacolarsi a vicenda
contare.
Cos'è un contatore atomico DynamoDB?
Un contatore atomico DynamoDB è un attributo numerico che si incrementa con una singola chiamata UpdateItem utilizzando un'espressione di aggiornamento ADD (o SET x = x + :n). DynamoDB legge, aggiunge e scrive il valore lato server, quindi gli scrittori simultanei serializzano senza perdere aggiornamenti, ma non è idempotente, quindi una chiamata ripetuta aumenta due volte.
- Utilizzare
ADD(oSET x = x + :n) per incrementare in una chiamata. DynamoDB legge, aggiunge e scrive lato server: i chiamanti simultanei serializzano, senza perdere aggiornamenti. - Non leggere prima. Provenendo da SQL diresti
SELECTe poiUPDATE; qui salti la lettura è completa e l'operazione è ancora sicura in concorrenza. - I contatori atomici non sono idempotenti. Un nuovo tentativo di
UpdateItemaumenta di nuovo. Se non riesci a tollerare il conteggio eccessivo o insufficiente, utilizza un . ADDsu un attributo mancante inizia da 0, quindi solo il primo incremento funziona: non è necessaria la scrittura seed.
Il problema con lettura-modifica-scrittura
Supponiamo che tu monitori le visualizzazioni di un video. L'istinto ingenuo, direttamente da SQL, è:
GetItem, aggiungine uno nella tua app, PutItem il nuovo total back.
Due spettatori avviano la riproduzione contemporaneamente. Entrambi leggono views = 41. Entrambi scrivono 42. Tu
contato una visualizzazione, non due. Questo è un aggiornamento perduto: la classica concorrenza
footgun e non viene visualizzato finché non c'è traffico.
In SQL lo schiveresti con UPDATE videos SET views = views + 1, spingendo il
aritmetica nel database. DynamoDB ha la stessa mossa, ed è il tutto
punto di un contatore atomico.
Incremento in una chiamata
Modella un elemento statistico per video. partition key VID#<id>, chiave di ordinamento STATS#TOTAL,
con un play_count numerico:
| PK | SK | play_count |
|---|---|---|
| "VID#9f3a" | "STATS#TOTAL" | 41 |
Per registrare una giocata, invia un UpdateItem con una clausola ADD:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression ADD play_count :one
Values :one = 1
DynamoDB legge play_count, aggiunge 1 e scrive il risultato all'interno di un singolo
funzionamento lato server. Non c'è alcuna finestra in cui un altro scrittore possa infilarsi. Dieci
le riproduzioni simultanee producono +10, ogni volta: questo è ciò che ti offre "atomico".
Puoi creare e copiare questa espressione esatta: nomi, valori e tutti e quattro tipi di clausola - con il Creatore di espressioni DynamoDB.
ADD funziona anche quando play_count non esiste ancora: DynamoDB tratta un mancante
attributo numerico come 0, quindi la prima riproduzione lo crea in 1. Nessun seme separato
scrivere. (AWS: utilizzo delle espressioni di aggiornamento)
ADD vs SET +: scegline uno
Due espressioni eseguono la stessa operazione aritmetica. AWS consiglia SET per uso generale
perché si compone con altre azioni SET e legge in modo più esplicito. ([AWS:
Utilizzo delle espressioni di aggiornamento[upd])
ADD play_count :one | SET play_count = play_count + :one | |
|---|---|---|
| Attr mancante | Lo crea, a partire da 0 | Errori: richiede if_not_exists |
| Tipi di dati | Solo numeri e insiemi | Numeri (e altro) tramite SET |
Combina con SET | Clausola separata | Una clausola SET, separata da virgole |
| Guida AWS | Multa per i contatori | Predefinito consigliato |
Se l'attributo potrebbe non esistere e desideri SET, proteggilo:
SET play_count = if_not_exists(play_count, :zero) + :one. Con ADD salti
quello: semina da 0 gratuitamente.
Scrivi il costo di ogni incremento
Su richiesta in us-east-1, ogni UpdateItem con un ADD fattura 1 WCU per
KB della dimensione dell'elemento dopo la scrittura (arrotondato per eccesso). Una riga di statistiche da 900 byte
costa 1 WCU per partita registrata; dieci giocate simultanee risultano ancora 10
WCU totale, non uno. La suddivisione del contatore tra le partizioni sposta il file
limite massimo di throughput senza modificare la matematica WCU per articolo. Dimensiona la riga con
calcolatore delle dimensioni dell'articolo e velocità di linea eccezionale
percorsi nel calcolatore dei prezzi.
Fallo in DynoTable
Apri l'elemento delle statistiche per ispezionare il contatore live, quindi arrotola un contatore frammentato
con SUM e GROUP BY nell'SQL Workbench per vedere il totale su ogni
Riga STATS#TOTAL#0..N. Per redigere l'incremento stesso, utilizzare il web
DynamoDB Expression Builder per comporre il file
ADD Espressione UpdateItem, nomi e valori inclusi.
La trappola: i contatori non sono idempotenti
Un contatore atomico incrementa ogni volta che UpdateItem viene eseguito. ([AWS: funzionante
con articoliarticoli)
Immagina un blip di rete: invii l'incremento, la connessione si interrompe prima del la risposta ritorna e non sai se è andata a buon fine. Riprova. Se il la prima chiamata ha avuto successo, ora hai contato quella giocata due volte.
Per le visualizzazioni video va bene: qualche conteggio doppio su un milione di riproduzioni non farà male chiunque, e AWS chiama questo esatto caso di "tracciamento dei visitatori" l'uso canonico di contatori atomici. (AWS: Lavorare con gli elementi)
Non va bene per tutto ciò che deve essere esatto: inventario che puoi vendere in eccesso, crediti che puoi spendere due volte, un saldo che puoi corrompere. Lì, prendi a aggiornamento condizionale.
Quando serve precisione: aggiornamenti condizionati
Un aggiornamento condizionale è idempotente se condiziona sullo stesso attributo che sei
cambiando. Incrementa da play_count a 42, ma solo se attualmente è 41:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression SET play_count = :next
ConditionExpression play_count = :current
Values :next = 42, :current = 41
Ora un nuovo tentativo è sicuro: se la prima scrittura ha già spostato play_count su 42, il file
condizione play_count = 41 fallisce la seconda volta e non cambia nulla. ([AWS:
Lavorare con gli elementi[elementi])
Il costo è la concorrenza. Due scrittori che gareggiano nella stessa condizione significa che uno vince
e si ottiene un ConditionalCheckFailedException per riprovare: hai scambiato il
throughput del contatore incondizionato per correttezza. Per l'esattezza, sostenuto
ribatte che è il mestiere giusto. Per quanto riguarda le visualizzazioni è eccessivo.
Insidie
- Un . Una singola riga di contatore corrisponde a una chiave di partizione. Un video virale
martellare
VID#9f3a/STATS#TOTALpuò raggiungere un limite di scrittura per partizione. Suddividilo: distribuisci le scritture suSTATS#TOTAL#0..Ne somma in lettura. - Nessun incremento batch.
BatchWriteItemè solo put/delete: non può essere eseguito . I contatori passano attraversoUpdateItem, un articolo per chiamata. Se devi colpire atomicamente diversi segnalini,TransactWriteItemsesegue azioni di aggiornamento su un massimo di 100 elementi in una richiesta, a circa il doppio del costo di scrittura. ADDè composto solo da numeri e insiemi. Non toccherà stringhe o valori booleani; quello è unSET. Per la versione completa vedere Tipi di dati DynamoDB. modello di attributi.
Passaggi successivi
I contatori atomici sono un modello di scrittura; il modo in cui leggi gli aggregati è un modello
domanda: vedere progettazione a tabella singola per mantenerla
elementi delle statistiche accanto al genitore e Query vs Scan quindi
arrotolando un contatore frammentato rimane un Query.
Disegna e copia l'incremento nel file Builder di espressioni DynamoDB, quindi prova DynoTable per eseguire aggiornamenti atomici sulle tue tabelle e guardare i conteggi muoversi.