La gestión de estado distribuido y la ejecución de código sin servidor a escala presentan desafíos inherentes en cuanto a consistencia, disponibilidad y tolerancia a fallos. Los sistemas tradicionales a menudo recurren a complejos protocolos de consenso (como Paxos o Raft) o a bases de datos distribuidas con un plano de control centralizado, lo que introduce sobrecarga operacional y puntos únicos de fallo o contención. celld aborda este problema fundamental al desacoplar la gestión del estado de cada 'objeto durable' en unidades autónomas, cada una con su propio almacenamiento persistente y replicación asíncrona.
La innovación clave reside en la utilización de un bucket S3-compatible como el único punto de coordinación y fuente de verdad duradera. Esto permite que cada Durable Object, esencialmente una instancia de SQLite, sea gestionado de forma independiente por cualquier nodo disponible. La propiedad de un objeto se establece mediante operaciones atómicas de 'compare-and-swap' en el almacenamiento de objetos, eliminando la necesidad de un protocolo de membresía de clúster o un detector de fallos explícito. Este enfoque simplifica drásticamente la arquitectura distribuida, reduciendo la complejidad y la sobrecarga de coordinación entre nodos.
Arquitectura del Sistema
La arquitectura de celld se centra en la autonomía de cada Durable Object. Cada nodo celld incrusta el motor V8 para ejecutar bundles de Cloudflare Workers. El estado de cada Durable Object se persiste en una base de datos SQLite local. La durabilidad y la replicación se logran mediante la sincronización continua de estas bases de datos SQLite con un bucket S3-compatible. Este bucket actúa como el 'source of truth' duradero y el mecanismo de coordinación para todo el clúster.
Cuando un Durable Object necesita ser activado o movido a otro nodo, el nuevo nodo propietario restaura la base de datos SQLite correspondiente desde el bucket S3 y reanuda la ejecución. La propiedad de un objeto por un nodo específico se garantiza mediante operaciones de 'compare-and-swap' en el almacenamiento de objetos, que son inherentemente atómicas y proporcionan una garantía de 'exactly-one-owner'. Esto evita condiciones de carrera sin un protocolo de consenso explícito. Los nodos descubren otros nodos y sus objetos a través de 'leases' (arrendamientos) almacenados en el bucket. La comunicación entre pares se realiza a través de HTTP, con autenticación HMAC, protección contra reenvío y límites de tiempo para asegurar la integridad y confidencialidad de las interacciones. La gestión de la presión, como el uso de memoria o CPU, permite a celld 'shed' (desprenderse) de objetos inactivos, replicando su estado y liberando la propiedad para que otro nodo pueda adquirirlos si es necesario.
Flujo de Despliegue de un Worker/Durable Object
- 1 celld deploy El CLI de celld invoca esbuild para compilar el código del Worker/Durable Obj...
- 2 Generación de Objetos Se crean objetos de despliegue con tipos definidos en crates/celld/protocol.rs.
- 3 Escritura a S3 Los objetos de despliegue se escriben directamente en el bucket S3-compatible...
- 4 Nodos celld Cada nodo celld carga la última versión del despliegue exitosamente commitada...
Flujo de Adquisición y Replicación de un Durable Object
- 1 Solicitud de Objeto Un nodo celld recibe una solicitud para un Durable Object.
- 2 Adquisición de Lease El nodo intenta adquirir la propiedad (lease) del objeto en el bucket S3 medi...
- 3 Restauración de Estado Si tiene éxito, el nodo descarga la base de datos SQLite del objeto desde S3.
- 4 Ejecución V8 El nodo inicia o reanuda la ejecución del Worker en V8 con el estado restaurado.
- 5 Replicación Continua El nodo replica continuamente los cambios de la base de datos SQLite del obje...
- 6 Liberación/Shedding Si el objeto está inactivo o bajo presión, el nodo replica su estado final y ...
| Capa | Tecnología | Justificación |
|---|---|---|
| compute | V8 | Motor de ejecución JavaScript para Cloudflare Workers y Durable Objects. vs SpiderMonkey, JavaScriptCore |
| storage | SQLite | Base de datos local para persistir el estado de cada Durable Object individualmente. vs RocksDB, LevelDB |
| storage | S3-compatible bucket | Fuente de verdad duradera, mecanismo de replicación y coordinación para el estado de los Durable Objects y los despliegues. vs Azure Blob Storage, Google Cloud Storage --bucket s3://my-cells-bucket, --endpoint https://ACCOUNT.r2.cloudflarestorage.com |
| orchestration | Object-storage compare-and-swap | Mecanismo atómico para asegurar la propiedad exclusiva de un Durable Object por un solo nodo, sin un protocolo de consenso distribuido explícito. vs Raft, Paxos, ZooKeeper |
| security | HMAC-authenticated peer communication | Asegura la autenticidad, integridad y protección contra reenvío de las comunicaciones HTTP entre nodos celld. vs TLS mutuo, OAuth fleet/peer-auth.json en S3 para la clave secreta. |
Trade-offs
Ganancias
- ▲ Simplicidad arquitectónica
- ▲ Resiliencia a fallos de nodo
- ▲ Aislamiento de contención (sharding por construcción)
- ▲ Escalabilidad horizontal de Durable Objects
Costes
- △ Latencia de restauración de estado (cold start)
- ▲ Dependencia de la disponibilidad y rendimiento de S3
- △ Consistencia eventual para la replicación de objetos
docker run --rm --network host \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e AWS_SESSION_TOKEN \
-e CELLD_WATCH=/var/lib/celld/state \
-v celld-state:/var/lib/celld \
ghcr.io/denoland/celld \
--bucket s3://my-cells-bucket \
--endpoint https://ACCOUNT.r2.cloudflarestorage.com \
--region auto \
--listen 0.0.0.0:8080 \
--advertise node-a.internal:8080CELLD_MAX_RESIDENT_CELLS=1000 \
CELLD_RESIDENT_LOW_WATER=800 \
celld --bucket s3://my-cells-bucket --listen 0.0.0.0:8080 \
--advertise node-a.internal:8080Fundamentos Teóricos
El diseño de celld, particularmente su dependencia de un almacenamiento de objetos para la coordinación y la durabilidad, resuena con los principios de los sistemas 'shared-nothing' y 'shared-disk' en bases de datos distribuidas, pero con una simplificación radical. Aunque no utiliza un protocolo de consenso distribuido explícito como Paxos (Lamport, 1998) o Raft (Ongaro & Ousterhout, 2014) para la coordinación general del clúster, la dependencia de operaciones atómicas de 'compare-and-swap' en el almacenamiento de objetos para la gestión de la propiedad de los Durable Objects es una forma de lograr consistencia a nivel de objeto sin la sobrecarga de un consenso global.
La idea de que cada 'objeto' sea su propia base de datos replicada se alinea con el concepto de 'sharding por construcción', donde la granularidad de la persistencia y la replicación es el objeto mismo, en lugar de una tabla o una base de datos completa. Esto mitiga los problemas de contención y el 'blast radius' de fallos que se encuentran en bases de datos compartidas. El uso de un almacenamiento de objetos como fuente de verdad duradera y mecanismo de coordinación también se alinea con los principios de la arquitectura 'log-structured' y la inmutabilidad de los datos, donde el estado se reconstruye a partir de un log o una serie de instantáneas, un concepto explorado en sistemas como Dynamo (DeCandia et al., 2007) y los sistemas de archivos distribuidos.