Los objetos duraderos ganan prominencia porque resuelven algo difícil (estado consistente con acceso serializado en el borde) y esto crea un sesgo: los ingenieros que acaban de aprender la herramienta tienden a aplicarla a problemas que no necesitan resolver. El resultado no es un mal código. Es un código correcto y funcional, más caro y más complejo de lo necesario. Para un CRUD simple construido sobre DO cuando D1 sería suficiente, la factura podría ser entre diez y cincuenta veces mayor, sin ninguno de los beneficios de consistencia que requeriría el caso de uso.
La pregunta que determina si necesitas HACER
Antes de decidirse por Durable Objects, hay una pregunta concreta: ¿el estado que necesita administrar requiere acceso serializado desde múltiples clientes simultáneos?
Serializado significa que el orden de las operaciones importa y que dos operaciones simultáneas sobre los mismos datos deben ser mutuamente excluyentes. Múltiples clientes en competencia significa que más de un agente puede intentar modificar los mismos datos al mismo tiempo, y ambos agentes deben ver un resultado consistente.
Si la respuesta es no (si los datos son leídos por muchos pero rara vez escritos, o si las escrituras simultáneas en el mismo registro son poco probables o son manejadas por otra capa), un DO agrega complejidad y costo sin agregar seguridad útil.
Donde D1 es la respuesta correcta
Para datos relacionales, D1 es el lugar natural dentro de la pila de Cloudflare. Tiene SQL completo, admite JOIN, índices, transacciones, consultas ad hoc: todo lo que D1 tiene y DO no tiene. Un DO es un almacén de valores clave linealizable con API de procedimiento. No tiene forma de responder "enumerar todos los usuarios que iniciaron sesión en los últimos 7 días y aún tienen un saldo positivo" sin que usted haya calculado previamente y almacenado explícitamente estos datos.
D1 tiene un costo mucho menor para las cargas de lectura: $0,001/millón de líneas leídas, $1,00/millón de líneas escritas. La latencia de escritura adicional en la región del banco principal, que es la desventaja más citada de D1, solo afecta las operaciones de escritura. Para aplicaciones donde dominan las lecturas, esta compensación favorece en gran medida a D1.
El caso confuso: "pero necesito que las escrituras sean atómicas". D1 tiene transacciones. BEGIN; UPDATE a...; UPDATE b...; COMMIT; garantiza la atomicidad. La diferencia es que D1 usa bloqueos de base de datos, con potencial de contención en alta concurrencia, mientras que un DO usa serialización por diseño. Para la inmensa mayoría de aplicaciones con cargas de escritura normales, D1 con transacciones es suficiente y mucho más económico.
Donde KV es la respuesta correcta
KV está optimizado para el patrón que domina la mayoría de los casos de uso periféricos: muchas lecturas, escrituras ocasionales, sin necesidad de una fuerte coherencia entre diferentes PoP. Caché de configuración, resultados informáticos precalculados, sesiones de usuario en las que la coherencia final es aceptable: KV responde a las lecturas de caché local en el PoP con una latencia inferior a milisegundos y un modelo de precios que favorece la lectura intensa.
El error es suponer que debido a que KV no tiene operaciones atómicas de lectura, modificación y escritura, necesita DO para cualquier cosa que cambie. La gran mayoría de los datos en las aplicaciones web cambian con patrones que no requieren una atomicidad estricta: el perfil de usuario que se actualiza cuando el usuario edita sus preferencias no necesita exclusión mutua con otro script de la competencia, porque nadie más está editando el mismo perfil al mismo tiempo.
DO comienza a tener sentido cuando la frecuencia de escrituras simultáneas en los mismos datos es lo suficientemente alta como para que la eventual coherencia de KV produzca resultados incorrectos visibles para el usuario.
La limitación de velocidad no es un caso de uso de DO
La limitación de velocidad es el ejemplo más común de "parece que necesita DO pero no es así". La intuición es correcta: la limitación de velocidad requiere un contador por usuario que se incrementa atómicamente con cada solicitud. Si dos trabajadores incrementan el mismo contador al mismo tiempo, puede haber una condición de carrera que permita al usuario realizar más solicitudes que el límite.
La API de limitación de tarifas de Cloudflare resuelve esto de forma nativa, sin código, sin DO y sin costos adicionales más allá del plan. Está disponible en todos los planes pagos, admite límites por IP, por usuario autenticado, por ruta, por encabezado y con períodos configurables. Para limitar la velocidad en el borde, usar la API nativa es más simple, más barato y más confiable que implementar un contador DO.
El caso legítimo para DO para la limitación de velocidad es cuando tiene requisitos que la API nativa no cubre: lógica de ventana deslizante personalizada con precisión exacta, límites que dependen de los datos de la sesión del usuario que no están en los encabezados o limitación de velocidad que debe ser coherente con otros datos que ya se encuentran en una aplicación DO.
Colas de trabajadores para procesamiento asincrónico
Otro patrón que a veces aparece como candidato a DO: una cola de trabajo donde múltiples productores ponen en cola tareas y múltiples consumidores procesan. DO podría modelar esto como un objeto con una lista de tareas y un bucle de procesamiento.
Las colas de trabajadores resuelven esto de forma nativa: los productores ganan env.QUEUE.send(message), los consumidores reciben lotes a través del controlador, con reintento automático, cola de mensajes no entregados y un cargo separado de $0,40/millón de mensajes. Para el procesamiento asincrónico con reintentos y retrocesos, las colas son más adecuadas, más económicas y no tienen el límite de rendimiento en serie de un DO.
DO para el procesamiento asincrónico tiene sentido cuando el consumo debe serializarse por identidad (procesar todas las acciones de un usuario en orden, sin paralelismo) y cuando ese procesamiento necesita acceder a un estado que de todos modos es local para el DO.
El almacenamiento de archivos es R2, no almacenamiento DO
El almacenamiento DO es un almacén clave-valor optimizado para objetos pequeños: configuraciones, contadores, estado de sesión, mensajes. No tiene límites documentados de valor, pero está diseñado para datos que pueden caber razonablemente en una solicitud. Para archivos, imágenes, videos y cualquier blob más grande, R2 es el lugar correcto: $0,015/GB-mes de almacenamiento (menos de una décima parte del costo del almacenamiento DO), sin costo de salida para los trabajadores, con API compatible con S3.
El almacenamiento DO no reemplaza el almacenamiento de objetos: es un almacén de estado transaccional para el propio DO.
Diagnóstico antes de elegir
Cuatro casos de uso donde DO resuelve algo que las alternativas no resuelven con las mismas garantías: edición colaborativa con múltiples clientes modificando el mismo documento simultáneamente, coordinación de presencia en tiempo real donde la lista de quién está en línea debe ser consistente, bloqueos distribuidos con tiempo de espera donde se debe garantizar la caducidad incluso si el titular falla, y registros de eventos ordenados por llegada donde el orden de inserción es semánticamente importante.
Para todo lo que no entra en esta lista, existe una alternativa dentro de la plataforma que es más barata, más sencilla o ambas cosas. La decisión de utilizar DO comienza con la pregunta sobre la serialización. Si no puede explicar por qué la serialización del acceso a datos es necesaria para el caso de uso, DO probablemente no sea la herramienta.
El riesgo de utilizar DO donde no es necesario no es que rompa nada: el código funcionará. El costo es acarrear una complejidad innecesaria: una abstracción que impone límites de rendimiento en serie, requiere un plan Workers Paid como prerrequisito, tiene una curva de aprendizaje distinta y cuesta más que las alternativas para los casos que las alternativas resuelven bien. Para un equipo que ya utiliza DO en otras partes del sistema, el costo marginal de un DO más es menor. Para un equipo que comienza en Cloudflare con un CRUD simple, comenzar con D1 y KV y agregar DO donde la serialización es realmente necesaria es el orden correcto de complejidad.
Lea también
- Objetos duraderos de Cloudflare: estado consistente en el borde: lo que realmente cambia
- Objetos duraderos en producción: cómo será el billete y los límites que sorprenden
- El modelo de programación de objetos duraderos: lo que se diferencia de cualquier cosa que haya usado alguna vez
- Objetos Durables y WebSockets: multijugador sin servidor dedicado
- Migrar de Pages a Workers: cuándo tiene sentido y el coste real del cambio
- WebAssembly para líderes: cuando la decisión arquitectónica vale la pena