Contadores atómicos en DynamoDB
Un contador atómico es un atributo numérico que incrementas en su sitio con una sola
llamada UpdateItem — sin leer primero, sin carrera de read-modify-write. DynamoDB
aplica cada incremento en orden de llegada y nunca deja que dos escritores se pisen el
conteo el uno al otro.
¿Qué es un contador atómico de DynamoDB?
Un contador atómico de DynamoDB es un atributo numérico que incrementas en su sitio con una sola llamada UpdateItem usando una expresión de actualización ADD (o SET x = x + :n). DynamoDB lee, suma y escribe el valor del lado del servidor, de modo que los escritores concurrentes se serializan sin actualizaciones perdidas — pero no es idempotente, así que una llamada reintentada incrementa dos veces.
- Usa
ADD(oSET x = x + :n) para incrementar en una llamada. DynamoDB lee, suma y escribe del lado del servidor — los llamadores concurrentes se serializan, sin actualizaciones perdidas. - Sin lectura previa. Si vienes de SQL harías un
SELECTy luego unUPDATE; aquí te saltas la lectura entera y la operación sigue siendo segura bajo concurrencia. - Los contadores atómicos no son idempotentes. Un
UpdateItemreintentado incrementa de nuevo. Si no puedes tolerar el sobreconteo o subconteo, usa una actualización condicional. ADDsobre un atributo inexistente empieza en 0, así que el primer incremento simplemente funciona — sin escritura de inicialización.
El problema con read-modify-write
Supón que rastreas las vistas de un vídeo. El instinto ingenuo, directo de SQL, es:
GetItem, suma uno en tu app, PutItem del nuevo total.
Dos espectadores le dan a play a la vez. Ambos leen views = 41. Ambos escriben 42.
Contaste una vista, no dos. Eso es una actualización perdida — el error clásico de
concurrencia, y no aparece hasta que tienes tráfico.
En SQL lo esquivarías con UPDATE videos SET views = views + 1, empujando la aritmética
a la base de datos. DynamoDB tiene el mismo movimiento, y es todo el sentido de un
contador atómico.
Incrementa en una llamada
Modela un item de estadísticas por vídeo. Clave de partición VID#<id>, clave de
ordenación STATS#TOTAL, con un play_count numérico:
| PK | SK | play_count |
|---|---|---|
| "VID#9f3a" | "STATS#TOTAL" | 41 |
Para registrar una reproducción, envía un solo 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, suma 1 y escribe el resultado dentro de una única operación
del lado del servidor. No hay ventana para que otro escritor se cuele. Diez
reproducciones concurrentes producen +10, siempre — eso es lo que te compra "atómico".
Puedes construir y copiar esta expresión exacta — nombres, valores y los cuatro tipos de cláusula — con el DynamoDB Expression Builder.
ADD funciona incluso cuando play_count aún no existe: DynamoDB trata un atributo
numérico inexistente como 0, así que la primera reproducción lo crea en 1. Sin
escritura de inicialización separada. (AWS: Usar expresiones de actualización)
ADD vs SET +: elige uno
Dos expresiones hacen la misma aritmética. AWS recomienda SET para uso general porque
compone con otras acciones SET y se lee de forma más explícita. (AWS: Usar
expresiones de actualización)
ADD play_count :one | SET play_count = play_count + :one | |
|---|---|---|
| Atributo ausente | Lo crea, empezando en 0 | Da error — 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 separada | Una cláusula SET, separada por comas |
| Recomendación de AWS | Vale para contadores | Valor por defecto recomendado |
Si el atributo podría no existir y quieres SET, protégelo:
SET play_count = if_not_exists(play_count, :zero) + :one. Con ADD te saltas eso —
inicializa desde 0 gratis.
Hazlo en DynoTable
Abre el item, edita play_count, y puedes ver aterrizar un incremento atómico sin
escribir JSON a mano — el panel de actualización emite la expresión ADD por ti y
muestra el nuevo valor en el momento en que se confirma.
La trampa: los contadores no son idempotentes
Aquí está la parte que muerde a los equipos en producción. Un contador atómico
incrementa cada vez que se ejecuta UpdateItem. (AWS: Trabajar con 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 aterrizó. Reintentas. Si la primera llamada sí tuvo éxito, ahora has contado esa reproducción dos veces.
Para vistas de vídeo eso está bien — unos pocos doble-conteos en un millón de reproducciones no le harán daño a nadie, y AWS llama a este caso exacto de "rastrear visitantes" el uso canónico de los contadores atómicos. (AWS: Trabajar con items)
No está bien para nada que deba ser exacto: inventario que puedes sobrevender, 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 actualmente es 41:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression SET play_count = :next
ConditionExpression play_count = :current
Values :next = 42, :current = 41
Ahora un reintento es seguro: si la primera escritura ya movió play_count a 42, la
condición play_count = 41 falla la segunda vez y nada cambia. (AWS: Trabajar con
items)
El coste es la concurrencia. Dos escritores compitiendo sobre la misma condición
significa que uno gana y otro recibe un ConditionalCheckFailedException para reintentar
— has cambiado el rendimiento del contador incondicional por corrección. Para contadores
exactos y disputados ese es el intercambio correcto. Para conteos de vistas es excesivo.
Trampas
- Un item caliente. Una sola fila de contador es una sola clave de partición. Un
vídeo viral martilleando
VID#9f3a/STATS#TOTALpuede alcanzar un techo de escritura por partición. Shardéalo: reparte las escrituras entreSTATS#TOTAL#0..Ny suma en la lectura. - Sin incremento por lotes.
BatchWriteItemes solo put/delete — no puede ejecutar expresiones de actualización. Los contadores pasan porUpdateItem, un item por llamada. ADDes solo números y conjuntos. No tocará cadenas ni booleanos; eso es unSET. Ver 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 — ver diseño de tabla única
para mantener los items de estadísticas junto a su padre, y
Query vs Scan para que sumar un contador shardeado siga siendo
un Query.
Redacta y copia el incremento en el DynamoDB Expression Builder, luego prueba DynoTable para ejecutar actualizaciones atómicas contra tus propias tablas y ver moverse los conteos.