self-hosted, distributed Durable Objects
celld
自托管、分布式的 Durable Objects。
celld 是一款开源守护进程,可在您自己的机器上运行 Cloudflare Workers 和 Durable Objects。每个对象都是其独立的 SQLite 数据库。celld 通过名称对对象进行寻址,并将其复制到您拥有的存储桶中。该存储桶可以是 S3 兼容的存储或 Google Cloud Storage。节点仅通过该存储桶进行协调,无需控制平面,也无需共识机制。由于每个对象都是独立的小型数据库,应用程序在构建时即实现分片——共享数据库的竞争问题和故障影响范围从设计层面得以消除,而非事后管理。节点未持有的单元处于非活动状态,非活动单元几乎不产生任何成本。欲了解更多信息,请访问 celld.dev 或阅读 文档。
工作原理
每个 celld 节点都嵌入了 V8 引擎并执行 Wrangler 捆绑包。整个节点集群共享一个存储桶,其中包含部署内容、单元状态和小型所有权记录。该存储桶可以是 S3 兼容的存储或 Google Cloud Storage。对象存储的比较并交换(compare-and-swap)功能确保同一时间只有一个节点拥有某个单元,无需成员协议、故障检测器或共识服务。
celld 持续将每个单元的 SQLite 数据库复制到存储桶。当单元迁移时,或当非活动单元被激活时,其新的所有者会恢复该数据库并继续执行。存储桶是持久的事实来源;节点是可替换的。
安装
安装程序会下载 celld 二进制文件(可通过 gh attestation verify 验证来源):
curl -fsSL https://celld.dev/install.sh | sh
如果安装程序提示,请将 ~/.local/bin 添加到你的 PATH 环境变量中。
使用 celld deploy 部署的 Worker 项目需要在 PATH 中配置 esbuild;纯资产项目则不需要。
安装程序会将每个版本保存在 ~/.local/lib/celld/releases 目录下,并通过一个符号链接指向当前版本。若要卸载 celld,删除该符号链接及 releases 目录即可:
rm `which celld` && rm -rf ~/.local/lib/celld
容器
发布镜像包含 celld 二进制文件,并针对 Linux x86-64 和 ARM64 架构进行发布:
docker run --rm ghcr.io/denoland/celld --version
持久化运行时的本地状态,并传递标准 AWS 凭证环境:
docker volume create celld-state
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 \
--internal-listen 10.0.0.12:8081 \
--advertise node-a.internal:8081
为 AWS S3 移除 --endpoint 和 --region 参数。通过负载均衡器暴露 8080 端口,并将 8081 端口保留在私有网络中。
运行
celld 使用标准的 AWS 凭证链。部署到兼容 S3 的存储桶,然后针对同一存储桶启动 celld:
celld deploy . \
--bucket s3://my-cells-bucket
celld \
--bucket s3://my-cells-bucket \
--listen 0.0.0.0:8080 \
--internal-listen 10.0.0.12:8081 \
--advertise 10.0.0.12:8081
若要使用其他 S3 兼容服务,请使用 --endpoint;若无法自动推断区域,请使用 --region。gs:// 存储桶将选择 Google Cloud Storage。此时,celld 会使用 Cloud Storage XML API 并应用生成预条件。身份验证采用应用默认凭据。对于 gs:// 存储桶,celld 会拒绝 S3 --endpoint,并忽略存储区域:
celld deploy . --bucket gs://my-cells-bucket
celld --bucket gs://my-cells-bucket --listen 0.0.0.0:8080 \
--internal-listen 10.0.0.12:8081 --advertise 10.0.0.12:8081
一个集群运行一个应用程序,每个节点都会从 deploy/current.json 加载其最新成功提交的部署。运行 celld --help 可查看完整命令行选项。
部署对象使用 crates/celld/protocol.rs 中记录的类型。celld deploy 会从 PATH 调用 esbuild 来处理 Worker 代码,接受受支持的 Wrangler 配置子集(包括共同部署的静态资源或仅资产的静态资源),并直接写入这些对象。每个节点通过存储桶租约发现所有者和对等节点;不存在账户或加入服务。
对等节点 HTTP 和操作员 API 使用内部监听器。请将所有公布的地址置于可信的私有网络或加密覆盖网络(如 WireGuard 或 Tailscale)上。不要公布内部端口。除非提供 --unsafe-public-advertise,否则 celld 会拒绝直接使用公网 IP。显式公布的地址需要显式的内部监听器地址。celld 无法验证主机名或转换后的端口,因此必须将公布的地址路由到内部监听器。当前的第一个节点会在存储桶中创建 fleet/peer-auth.json。所有对等节点请求均采用协议版本控制、正文绑定、HMAC 认证、时钟限制,并使用该集群密钥进行重放保护。请将对存储桶及其凭据的访问权限视为集群管理员权限。
操作集群
celld diagnose 默认会枚举每个节点租约,然后对每个活动的对等节点执行签名的直接探测:
celld diagnose --bucket s3://my-cells-bucket
该报告在发生个别故障后会持续检查,并区分过期记录、格式错误或不安全的广告地址、无法访问的对等节点以及不兼容的协议。它还会打印每个节点的大致驻留单元、WebSocket、RSS、CPU、文件描述符、压力和卸载样本。通过传递一个或多个 --peer NODE_ID 选项来限制检查范围。
在每个已加载的节点上设置硬性驻留单元限制:
CELLD_MAX_RESIDENT_CELLS=1000 \
celld --bucket s3://my-cells-bucket --listen 0.0.0.0:8080 \
--internal-listen 10.0.0.12:8081 --advertise node-a.internal:8081
celld 默认将 RSS 阈值设为可用内存的 80%。可通过设置 CELLD_MAX_RSS_MB 来修改该阈值,或将其设为 0 以禁用内存压力卸载机制。在内存压力下,celld 会对最近最少使用的闲置单元进行持久化复制并隔离,然后将这些单元标记为无主状态,且不重置它们的纪元。这些单元随后变为非活动状态,并且在 RSS 降至阈值的 80% 之前,celld 会拒绝重新获取新的无主单元。备用单元不会被分配任务。当正常流量到达时,它会通过相同的桶协议获取已释放的单元。celld 不会卸载正在处理活动任务或存在活跃主机 WebSocket 连接的单元。
贡献
拉取请求功能已禁用。编码工具使得发送大量低上下文的变更变得过于容易,这给维护者带来的时间成本超过了其节省的时间。我们欢迎经过深思熟虑的贡献;请务必理解代码,保持补丁的专注性,并尊重您所请求的审核时间。
请将 git format-patch 生成的补丁作为附件发送至 ry@deno.com。
贡献者许可协议:通过电子邮件发送补丁,即表示您证明自己有权提交该补丁,并将您在该补丁中可转让的所有权利转让给 Deno Land Inc.。对于无法转让的权利,您授予 Deno Land Inc. 一项永久、不可撤销、全球范围、免版税、可转让、可再许可的许可,允许其全部或部分使用、修改、组合、再许可、再分发或发布该补丁,无论是否注明出处。