celld:自建 Durable Objects
后端约 6 分钟阅读

celld:自建 Durable Objects

Deno 热榜项目 celld:每个 cell 一份 SQLite,S3 为真相源,无中心控制面的自建 Durable Objects。适合房间态与按名分片,桶权限即舰队权限。

GitHub 热榜上 Deno 团队的 celld 很安静地点中了一个后端痒点:Cloudflare Durable Objects 好用,但有人就是想把“按名字寻址的小对象 + 强一致单线程执行”搬回自己的机器和自己的桶里。

celld 的定位写得很干脆:self-hosted, distributed Durable Objects。每个 object 是一份自己的 SQLite;状态复制到你控制的 S3 兼容存储;节点之间只靠桶协调,没有单独的控制面,也没有一套共识服务撑场子。空闲 cell 几乎睡死,申请打过来再醒。

这不是又一个“在 K8s 上模拟 Workers”的玩具 README。它把对象存储当成真相源,节点当成可丢的执行器。这套形状,对做过有状态边缘、实时房间、按租户分片的人,会非常眼熟。

模型:一个 cell 一份库

传统做法是共享数据库加分片键。出问题的时候,慢查询、锁、连接池是整库的事。Durable Objects 的思路相反:状态跟对象走,对象名就是分片键。celld 把这点做绝——每个 cell 自带 SQLite,争用和爆炸半径在设计上被拆小,而不是靠更厚的中间件去“治理”。

运行时侧:节点内嵌 V8,跑 Wrangler 打出来的 Worker 包。舰队共享一个 S3 兼容桶,里面是部署物、cell 状态、所有权记录。对象存储上的 compare-and-swap 保证同一时间只有一个节点拥有某个 cell,不靠成员协议或故障检测器选主。

cell 迁移或唤醒时,新主人从桶恢复 SQLite 再继续跑。桶是耐用真相,节点坏了就换节点。这对运维心理是一次翻转:以前你保护的是那台有状态的机器,现在你保护的是桶的权限、版本与区域。

最小可跑通的形状

文档里的路径大致是:

sh
curl -fsSL https://celld.dev/install.sh | sh

celld deploy . --bucket s3://my-cells-bucket

celld \
  --bucket s3://my-cells-bucket \
  --listen 0.0.0.0:8080 \
  --advertise 10.0.0.12:8080

R2、MinIO 一类需要 --endpoint / --region。容器镜像在 ghcr.io/denoland/celld。多节点时每个实例 --advertise 必须是对等节点真正达得到的地址;前面挂负载均衡时尤其别抄成同一个 VIP 糊弄。

部署物写在桶里的 deploy/current.json 一类指针上,节点拉最新成功提交的版本。Worker 代码依赖 esbuild 在 PATH 里;纯静态资源项目可以例外。协议类型在仓库的 crates/celld/protocol.rs,有心对接的人直接读类型比读营销页快。

图:节点可替换,S3 兼容桶才是 cell 状态的真相源

安全边界比“能跑”更先

README 写得很硬,值得原样记在运维手册里:

  • Peer HTTP 不终止 TLS。广告地址只能放在受信私网或 WireGuard/Tailscale 一类叠加网上,不要把 peer 端口裸奔公网
  • 字面量公网 IP 默认拒绝,除非显式 --unsafe-public-advertise
  • 首个节点会在桶里建 fleet/peer-auth.json;对等请求带协议版本、HMAC、时钟窗口和防重放
  • 能碰桶凭证 = 舰队管理员。桶策略、密钥轮转、访问日志,优先级高于“再加一台 node”

这和把 Postgres 暴露到 0.0.0.0 是同一类事故预告。celld 把协调做得很薄,薄的代价是:存储与网络的正确配置变成了正确性的一部分。

celld diagnose 会枚举节点租约并对存活 peer 做签名探测,排障从这里开始比先翻应用日志更有用。

适合什么,不适合什么

比较顺的场景:

  • 实时协作房间、游戏房间、设备会话:按 room id / device id 建 cell
  • 需要单线程串行写的计数器、锁、短工作流,又不想上强依赖云厂商 DO
  • 已有 R2/S3,想把“有状态小服务”和对象存储账单绑在一起
  • 本地/专有云,合规要求计算与数据都在自己账本下

需要小心的场景:

  • 重跨 cell 事务:对象模型天生不爱分布式事务,业务上要能接受最终一致或显式编排
  • 超大单 cell 状态:SQLite 按 cell 复制,单对象胖到不合适时要重新切名
  • 把 peer 当公网 API:前面必须是你自己的入口与鉴权,celld 不是面向互联网的全家桶 PaaS
  • 指望“零运维”:你仍要管桶、节点、叠加网和发布

和 Cloudflare 上的 DO 比,你换来的是可控与可迁出,付出去的是舰队与存储的操作责任。和“整库 Postgres + 自己分片”比,你换来的是更小的爆炸半径和更贴对象的一致性,付出去的是工具链与心智模型切换。

观测与发布节奏

没有中心控制面,不代表没有中心故障。桶延迟飙高时,所有权 CAS、状态恢复、部署指针读取会一起抖。监控至少要有:节点租约是否过期、单 cell 恢复耗时、deploy 指针变更审计、桶 5xx/慢请求。应用层给每个 cell 名打点,比只看机器 CPU 有用。

发布上我倾向小步:先双写或影子流量验证序列化假设,再切读。Worker 包和 cloud DO 不完全同一运行时,API 子集、CPU 限制、I/O 模型都要在预发用真实对象大小压一遍。别在演示环境用空 cell 宣布胜利。

和缓存层别混为一谈

同周 Valkey 社区还在写 AI 推理栈怎么映射到内存原语:语义缓存、KV cache offload、限流计数。那是热数据与协调。celld 是有状态执行单元。可以同时存在:入口用 Valkey 做限流与幂等键,房间真相放 cell。不要因为都是“热”就塞进同一个系统。

小结

celld 把 Durable Objects 的核心赌注开源化了:按名分片、单主执行、SQLite 为单元、S3 为真相、节点可扔。热榜意义不在于明星 star 数,而在于后端可选路径又多了一条——云 DO、自建 celld、或老老实实共享库分片,按合规和操作能力选,不按演示文稿选。

先读 celld.dev 和仓库 README,用诊断命令跑通三节点私网,再让业务 proto 贴上去。桶的 IAM 没收紧之前,不要把生产流量切过去。

相关文章