Cloudflare 在 2026 年 10 月 13 日公开了 D1 控制平面的实现细节。面对按用户、租户或预览环境创建大量小数据库的平台,D1 将查询执行、资源管理和后台统计分开处理,减少中央元数据库对日常查询的影响。
这次动态是一篇架构说明,并非 D1 首次上线,也没有宣布每个账户默认都能创建百万数据库。对开发者更有参考价值的问题是:资源数量不断增加时,如何避免每次查询都查中央目录,又怎样处理创建过程中已经发生、却未完整登记的状态?
数据库变小了,管理工作却没有消失
许多应用只维护少数数据库,租户数据靠表中的标识区分。按租户或环境分库后,单库可能不大,但创建、删除、路由、配额与统计都要面对更多对象。一个原本不起眼的“查一下这个数据库在哪里”,也可能变成平台瓶颈。
D1 是基于 SQLite 的托管无服务器数据库。官方文章介绍,每个 D1 数据库由 SQLite Durable Object 支撑,Postgres 保存数据库元信息以及到 Durable Object 的映射,Workers KV 保存供查询读取的路由信息。
官方披露,截至 2026 年 10 月 8 日,未删除数据库数量在过去一年增长 15 倍,日活数据库数量增长 18 倍;这里的日活指当天至少执行过一次查询。这些是厂商对自身服务的统计,不能据此推导单个数据库吞吐提升了多少,也不是跨产品性能测试。
规模数字还要和账户额度分开看。本文查阅时,D1 限额文档列出的默认数据库数量是 Free 每账户 10 个、Workers Paid 每账户 50,000 个;Paid 和 Enterprise 可以申请提高,文档说明可支持百万到千万级或更多数据库。采用按租户分库前,应先确认数量、单库容量和账户总存储额度。
两种查询入口,中央目录的参与程度不同
D1 对外提供 HTTP API 查询,也允许用户部署的 Worker 通过 D1 Binding 查询。两条路径最终都会经过内部 Eyeball Worker,再到支撑数据库的 Durable Object,但取得路由信息的方式不同。
HTTP 查询由 Edge API Worker 处理认证、资源授权、限流和请求校验,并优先从 Workers KV 读取数据库 UUID 对应的元信息。如果 KV 没有该记录,就经 Hyperdrive 查询 Postgres 只读副本;Hyperdrive 会先检查自己的缓存。
D1 Binding 已经携带内部路由信息和针对特定数据库的授权信息,因此用户 Worker 的查询可以直接进入 Eyeball Worker,不必每次再解析 UUID 映射。Eyeball Worker 仍会验证绑定携带的信息,并执行自己的限流,不能把这条短路径理解成绕过授权。
| 入口或操作 | 主要路径 | 中央 Postgres 的角色 |
|---|---|---|
| HTTP API 查询 | Edge API Worker → KV 路由查询 → Eyeball Worker → Durable Object | 路由记录缺失时,经 Hyperdrive 回退查询只读副本 |
| 用户 Worker 的 D1 Binding 查询 | 用户 Worker → Eyeball Worker → Durable Object | 无须逐次查询 UUID 映射 |
| 创建、删除等管理操作 | Edge API Worker → Hyperdrive → Postgres,并按操作调用 Durable Object | 保存和读取资源元信息 |
| 用量统计与限制判断 | 异步事件、聚合任务、缓存和周期检查 | 承担部分统计状态,不逐条同步处理 SQL 请求 |
所以,“控制平面离开热路径”描述的是减少常规查询对中央组件的依赖,不是承诺任何请求都绝不访问 Postgres。
KV 也不只是给 Postgres 多加一层缓存。它有自己的持久存储,即使某个边缘位置的 KV 缓存未命中,仍可由 KV 存储层提供记录,不必全部回到 D1 的中央 Postgres。官方文章指出,如果百万数据库的路由信息只依靠普通查询缓存,一次大规模缓存清空可能让中央数据库承受集中回源。
这并不表示 KV 没有冷读延迟或故障风险。它的作用是改变回源落点和故障影响范围。
创建流程为什么不能简单套一个长事务
创建数据库需要同时完成两种不同的工作:初始化 Durable Object,以及在 Postgres 中登记它。前者可能发生在距离中央数据库很远的位置。
如果在整个远程初始化期间一直持有 Postgres 事务和连接,网络等待就会占用中央数据库资源。D1 因此没有将全过程包在一个长事务里,而是选择明确的创建检查点和后续修正机制。
流程先生成数据库 UUID 与独立 Durable Object ID,初始化对象,将账户和数据库信息存入其持久存储;初始化成功后,才向 Postgres 主库写入元信息和映射。这个写入是创建检查点。即使最终响应没能送达客户端,数据库此时也已经被视为创建成功。
这个顺序很重要。先登记映射再初始化对象,查询可能被路由到尚未就绪的数据库。先初始化再登记,则需要处理另一类问题:对象已经存在,登记却失败了。
D1 在重试时使用新的数据库 UUID 和新的 Durable Object ID,避免多个对象认为自己属于同一个数据库。假设对象 A 初始化成功但 Postgres 写入失败,下一次尝试创建对象 B 并成功登记,合法映射就只指向 B。
A 不会靠“重试应该成功”来解决自己的状态。它会在后续心跳中向控制平面核对,发现对应数据库不存在,再将自己标记为已删除。官方说明,通常心跳间隔为 30 秒并带每数据库的随机抖动,还允许按数据库或账户调整。因此,这里的周期是内部实现描述,不应当作所有故障都在 30 秒内恢复的服务保证。
客户端也要考虑检查点之后的超时。本文的实践建议是先查询资源是否已存在,再决定是否重新创建;不能仅凭客户端没有收到成功响应,就认定远端什么都没发生。
最终一致性的路由,需要对象自己的状态兜底
创建后的确认调用在后台执行,由 Durable Object 将数据库元信息写入 KV。这一步尽力执行,失败时由后续心跳修正。
删除也采用类似机制:对象保存自己的已删除状态,再更新 KV 中的状态。如果 KV 暂时仍返回旧路由,对象可以根据本地持久状态拒绝查询。这让路由传播和查询是否被接受不必完全依赖同一个缓存更新时刻。
Workers KV 的官方文档明确说明,它是最终一致的;其他位置可能要等待 60 秒或更久才能看到变化,不能依赖写入位置总是立即可见。把同一个 key 的写入交给对应 Durable Object 串行处理,也不会把所有 KV 读取自动变成强一致读取。
对自建平台,这个设计可转成两项明确要求。路由目录可以允许短暂陈旧,但目标资源必须能判断自己是否还有效;状态更新必须有重试或核对机制,不能只在创建请求的最后执行一次。
这是一种分层防护。缓存告诉请求去哪里,对象决定当前能否处理,中央元数据库提供需要持续核对的事实依据。
账户总用量:少扫表,也少抢同一行锁
管理大量数据库时,另一个容易被忽略的成本是账户总用量。
D1 的 Durable Object 异步报告存储用量。事件先在边缘聚合,再进入内部队列,由受控数量的消费者更新 Postgres。限制消费者数量,能防止流量高峰直接转成失控的中央写入压力。这里使用的是内部队列,不能把文章中的所有内部组件都当作公开产品接口。
判断账户是否超过存储额度,需要账户下全部数据库的总量。每次检查都扫描该账户所有数据库,成本会随资源数量增加。D1 因此维护预计算的账户总量。
但如果每个数据库每次更新都直接修改同一行账户总量,大账户又会遇到行锁竞争。D1 增加了一张变化记录表,让触发器将单库用量差值写进去,再由每秒运行的任务按账户汇总,集中更新总量表。
它减少了两种不同的负担:读取时不再反复求全量总和,写入时不再让所有单库更新都争抢同一条账户记录。代价是总量不能实时反映每个变化。
Durable Object 通过心跳读取账户总量,查询经 Hyperdrive 缓存和 Postgres 副本执行。缓存参数只包含账户 ID,能让同账户的数据库共用结果。若加入数据库 ID,缓存项就会分散,中央读取压力也可能增加。
官方还介绍,用时间分桶参数改变特定查询的缓存键,以便更快读取新值。这个办法改变的是缓存键,并没有让队列处理、聚合、副本读取与心跳都变成同步流程。它适合允许一定延迟的使用量管理,不能直接照搬成严格实时余额扣减方案。
给多租户平台的落地检查
采用这类设计之前,可以先做小规模故障测试,再扩大资源数量。重点不只是“能够创建多少个数据库”,而是失败和恢复时发生什么。
建议检查以下情况:
- 初始化成功、元信息写入失败时,是否会留下无法识别的孤儿对象,后续如何清理。
- 创建已登记、客户端响应超时时,调用方能否识别已有资源,避免重复申请。
- 路由缓存过期或被清空后,回源落到哪里,中央目录能否承受集中读取。
- 删除状态尚未传播时,目标对象是否仍可能接受本应拒绝的请求。
- 用量事件延迟、重复或顺序变化时,聚合结果如何校验,是否需要定期对账。
这些是本文根据架构提出的验证问题,并非 Cloudflare 对所有具体故障处理方式的额外承诺。
多数据库模式也不会自动解决跨租户分析、schema 升级和跨库事务。即使控制平面能管理百万资源,应用仍需要组织批量迁移、失败重试与跨库数据汇总。选型时应同时评估隔离收益和这些长期运维成本。
结语
D1 这次公开的设计,将中央元信息、边缘路由、数据库自身状态和后台统计分别放在合适的路径上。查询通常不必等待中央目录,创建也不必在远程初始化期间占住一个长事务;无法一次完成的更新,由心跳和异步聚合继续修正。
最值得借鉴的是把等待和一致性要求写清楚:哪些判断必须立即生效,哪些数据可以暂时陈旧,以及失败后由谁把状态补齐。对按租户或环境分配资源的平台,这些问题往往比数据库总数本身更能决定系统是否稳定。
参考来源
- Cloudflare:Under the hood, off the hot path: how D1 scales to millions of databases,2026 年 10 月 13 日发布,本文近期选题与架构事实的主要来源。
- Cloudflare Docs:D1 Limits,核对默认账户限额、单库容量和申请提高额度的说明。
- Cloudflare Docs:How KV works,核对 KV 存储、冷读与最终一致性边界。
- Cloudflare Docs:Hyperdrive Query caching,核对只读查询缓存与默认缓存配置;D1 内部策略以技术文章为准。