DynamoDB Contadores atómicos: cómo funciona ADD y cuándo no
Un contador atómico es un atributo numérico que se coloca con un solo
UpdateItem llamada: sin lectura primero, sin carrera de lectura-modificación-escritura. DynamoDB se aplica
cada incremento en el orden de llegada y nunca permite que dos escritores se golpeen entre sí.
contar.
¿Qué es un contador atómico DynamoDB?
Un contador atómico DynamoDB es un atributo numérico que se incrementa en su lugar con una sola llamada UpdateItem usando una expresión de actualización ADD (o SET x = x + :n). DynamoDB lee, agrega y escribe el valor en el lado del servidor, por lo que los escritores concurrentes serializan sin perder actualizaciones, pero no es idempotente, por lo que una llamada reintentada se incrementa dos veces.
- Utilice
ADD(oSET x = x + :n) para incrementar en una llamada. DynamoDB lecturas, agrega y escribe en el lado del servidor: las personas que llaman simultáneamente se serializan, sin pérdida de actualizaciones. - No leer primero. Viniendo de SQL tendrías
SELECTy luegoUPDATE; aquí te saltas la lectura completa y la operación aún son seguras en concurrencia. - Los contadores atómicos no son idempotentes. Un reintento de
UpdateItemincrementos otra vez. Si no puede tolerar un conteo excesivo o insuficiente, utilice una . ADDen un atributo faltante comienza en 0, por lo que el primer incremento solo funciona, no se necesita escritura inicial.
El problema con lectura-modificación-escritura
Supongamos que realiza un seguimiento de las vistas de un vídeo. El instinto ingenuo, directamente de SQL, es:
GetItem, agrega uno en tu aplicación, PutItem el nuevo total de regreso.
Dos espectadores pulsan reproducir a la vez. Ambos leen views = 41. Ambos escriben 42. tu
Contó una vista, no dos. Esa es una actualización perdida: la concurrencia clásica
Footgun, y no aparece hasta que tienes tráfico.
En SQL lo esquivarías con UPDATE videos SET views = views + 1, empujando el
aritmética en la base de datos. DynamoDB tiene el mismo movimiento, y es el conjunto
punto de un contador atómico.
Incremento en una llamada
Modele un elemento de estadísticas por video. Clave de partición VID#<id>, clave de clasificación STATS#TOTAL,
con un numérico play_count:
| PK | SK | play_count |
|---|---|---|
| "VID#9f3a" | "STATS#TOTAL" | 41 |
Para registrar una obra, envía un UpdateItem con una cláusula ADD:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression ADD play_count :one
Values :one = 1
DynamoDB lee play_count, le suma 1 y escribe el resultado dentro de una única
operación del lado del servidor. No hay ninguna ventana por la que otro escritor pueda
colarse. Diez reproducciones concurrentes producen +10, siempre: eso es lo que compra
la palabra "atómico".
Puedes construir y copiar esta misma expresión — nombres, valores y los cuatro tipos de cláusula — con el Generador de expresiones de DynamoDB.
ADD funciona incluso cuando play_count todavía no existe: DynamoDB trata un atributo
numérico ausente como 0, así que la primera reproducción lo crea con valor 1. No hace
falta una escritura inicial aparte. (AWS: Using update expressions)
ADD frente a SET +: elige uno
Dos expresiones hacen la misma aritmética. AWS recomienda SET para uso general porque
se compone con otras acciones SET y se lee de forma más explícita. (AWS:
Using update expressions)
ADD play_count :one | SET play_count = play_count + :one | |
|---|---|---|
| Atributo ausente | Lo crea, empezando en 0 | Falla — necesita if_not_exists |
| Tipos de datos | Solo números y conjuntos | Números (y más) vía SET |
Combinar con SET | Cláusula aparte | Una cláusula SET, separada por comas |
| Recomendación AWS | Correcto para contadores | Valor predeterminado recomendado |
Si el atributo puede no existir y quieres usar SET, protégelo:
SET play_count = if_not_exists(play_count, :zero) + :one. Con ADD te ahorras eso:
parte de 0 gratis.
Coste de escritura de cada incremento
Bajo demanda en us-east-1, cada UpdateItem con un ADD factura 1 WCU por KB del
tamaño del elemento después de la escritura (redondeado hacia arriba). Una fila de
estadísticas de 900 bytes cuesta 1 WCU por reproducción registrada; diez
reproducciones concurrentes siguen sumando 10 WCU en total, no una. Fragmentar el
contador entre particiones sube el techo de rendimiento sin cambiar la aritmética de WCU
por elemento. Dimensiona la fila con la
calculadora de tamaño de elemento y calcula la
tarifa de las rutas calientes en la
calculadora de precios.
Hazlo en DynoTable
Abre el elemento de estadísticas para inspeccionar el contador en vivo y después agrega un
contador fragmentado con SUM y GROUP BY en el SQL Workbench para ver el total de todas
las filas STATS#TOTAL#0..N. Para redactar el propio incremento, usa el
Generador de expresiones de DynamoDB de la web y
compón la expresión ADD del UpdateItem, con nombres y valores incluidos.
La trampa: los contadores no son idempotentes
Un contador atómico se incrementa cada vez que se ejecuta UpdateItem. (AWS: Working
with items)
Imagina un corte de red: envías el incremento, la conexión se cae antes de que vuelva la respuesta y no sabes si llegó a aplicarse. Reintentas. Si la primera llamada sí tuvo éxito, acabas de contar esa reproducción dos veces.
Para las vistas de un vídeo eso da igual: unos pocos recuentos duplicados en un millón de reproducciones no hacen daño a nadie, y AWS describe justamente este caso de "seguimiento de visitantes" como el uso canónico de los contadores atómicos. (AWS: Working with items)
No vale para nada que deba ser exacto: inventario que puedes vender de más, créditos que puedes gastar dos veces, un saldo que puedes corromper. Ahí, recurre a una actualización condicional.
Cuando necesitas exactitud: actualizaciones condicionales
Una actualización condicional es idempotente si condicionas sobre el mismo atributo que
estás cambiando. Incrementa play_count a 42, pero solo si ahora vale 41:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression SET play_count = :next
ConditionExpression play_count = :current
Values :next = 42, :current = 41
Ahora el reintento es seguro: si la primera escritura ya movió play_count a 42, la
condición play_count = 41 falla la segunda vez y no cambia nada. (AWS:
Working with items)
El precio es la concurrencia. Dos escritores compitiendo por la misma condición significa
que uno gana y el otro recibe un ConditionalCheckFailedException para reintentar: has
cambiado el rendimiento del contador incondicional por corrección. Para contadores exactos
y disputados esa es la decisión correcta. Para contar vistas es excesivo.
Escollos
- Un solo . Una única fila de contador es una sola
clave de partición. Un vídeo viral machacando
VID#9f3a/STATS#TOTALpuede alcanzar el techo de escritura por partición. Fragméntalo: reparte las escrituras entreSTATS#TOTAL#0..Ny suma en la lectura. - No hay incremento por lotes.
BatchWriteItemes solo put/delete: no puede ejecutar . Los contadores pasan porUpdateItem, un elemento por llamada. Si tienes que subir varios contadores de forma atómica,TransactWriteItemsejecuta acciones Update sobre hasta 100 elementos en una petición, a aproximadamente el doble de coste de escritura. ADDes solo números y conjuntos. No toca cadenas ni booleanos; para eso estáSET. Consulta tipos de datos de DynamoDB para el modelo de atributos completo.
Próximos pasos
Los contadores atómicos son un patrón de escritura; cómo lees los agregados de vuelta es
una cuestión de modelado: consulta
diseño de tabla única para mantener los elementos de
estadísticas junto a su elemento padre, y Query frente a Scan
para que agregar un contador fragmentado siga siendo un Query.
Redactar y copiar el incremento en el DynamoDB Generador de expresiones, luego pruebe DynoTable para ejecutar actualizaciones atómicas en sus propias tablas y Mira cómo se mueven los conteos.