一次 FoundationDB 客户端调用
tr.set(b'user:42', b'paid') 再
tr.commit(),表面上像单机 KV 的
put,集群里却要先后拿到全局版本、过冲突检测、把
mutation
写进复制日志,再由存储进程异步消化。若把这些步骤塞进「一个带
Raft
的存储节点」,提交延迟、读扩展和恢复路径会缠在一起;FoundationDB
的选择是把它们拆开。
分布式 KV 对比 已经回答「何时选 FoundationDB」;TiKV / HTAP 内核 把 Multi-Raft 与 Percolator 快照隔离走通。中间仍缺一层:一次 FDB 事务如何经 Proxy、Sequencer、Resolver、TLog 提交,Storage Server 为何异步应用仍能提供版本化读取。本文是「FoundationDB 内核」系列第 1 篇(共 18 篇),只做三件事:
- 用 SIGMOD 2021 论文钉住 Unbundled 架构与控制面 / 数据面分工。
- 画出一次读写事务穿过哪些角色,作为后续篇目的坐标系。
- 给出 18 篇地图,并与站内相邻系列划清边界。
本文是「FoundationDB 内核」系列第 1 篇(共 18 篇)。→ 系列目录
篇目 核心内容 第 1 篇 · Unbundled 全景 角色分工、事务路径、系列路线 第 2 篇 · Client API 与事务模型 冲突范围、自动重试、5 秒预告 第 3 篇 · Coordinator 与集群配置 配置持久化、招募与 Paxos 边界
版本锚定:FoundationDB 7.x 官方文档(Architecture、Developer Guide);Zhou et al., FoundationDB: A Distributed Unbundled Transactional Key Value Store, SIGMOD 2021, DOI: 10.1145/3448016.3457559。官方 7.x 文档中版本与恢复协调角色常称 Master;SIGMOD 2021 与本系列主线称 Sequencer——二者对应同一逻辑职责,后文统一写 Sequencer,必要时注明文档别名。本文不复述 Raft / Paxos 教科书,也不展开 Record Layer。
一、Unbundled:控制面与数据面
Zhou et al.(SIGMOD 2021)把 FoundationDB 拆成 控制面(Control Plane) 与 数据面(Data Plane)。控制面管关键元数据与集群编排;数据面再拆成事务系统、日志系统与存储系统,彼此可独立扩缩。
| 平面 | 角色 | 职责摘要 | 本系列落点 |
|---|---|---|---|
| 控制面 | Coordinators | 持久化事务系统配置;磁盘 Paxos 组 | 第 3、13 篇 |
| 控制面 | Cluster Controller | 选举产生的单例;失败检测与角色招募入口 | 第 3、13 篇 |
| 控制面 | Data Distributor / Ratekeeper | 存储均衡与过载保护(6.2 起独立单例) | 第 5、16 篇 |
| 数据面 · TS | Sequencer(Master) | 分配 read / commit version;协调一代事务系统恢复 | 第 6、13 篇 |
| 数据面 · TS | Grv / Commit Proxy | 发 read version;编排提交 | 第 4、7 篇 |
| 数据面 · TS | Resolver | OCC 冲突检测(约 5 秒窗口内的写历史) | 第 8–9 篇 |
| 数据面 · LS | Log Server(TLog) | 复制持久化的 mutation 队列 | 第 10 篇 |
| 数据面 · SS | Storage Server | Shard 上的版本化读;异步拉取日志 | 第 11–12 篇 |
论文用语是「unbundled architecture」:内存侧事务管理、WAL 日志层、服务读的存储层分离(Zhou et al., SIGMOD 2021, §2.3.2)。这与「每个节点既做共识又存全量数据」的 shared-nothing 复制组不同——FDB 用 角色 切问题,而不是用 Region/Raft 组 切问题。
flowchart TB
subgraph control ["Control Plane"]
coord["Coordinators<br/>disk Paxos config"]
cc["Cluster Controller"]
dd["Data Distributor"]
rk["Ratekeeper"]
coord --> cc
cc --> dd
cc --> rk
end
subgraph data ["Data Plane"]
subgraph ts ["Transaction System"]
seq["Sequencer"]
proxy["Grv / Commit Proxy"]
res["Resolver"]
end
subgraph ls ["Log System"]
tlog["Log Servers"]
end
subgraph ss ["Storage System"]
stor["Storage Servers"]
end
end
cc --> seq
seq --> proxy
proxy --> res
proxy --> tlog
tlog -.->|"async pull"| stor
1.1 设计原则:拆开、失败走恢复、快速重配
SIGMOD 2021 §2.1 归纳了几条贯穿后续章节的原则:
- Divide-and-conquer:写路径(事务系统)与读路径(存储)分离;事务系统内部再拆版本、提交入口、冲突检测、日志。
- Make failure a common case:事务系统侧倾向「发现异常就关掉这一代、走统一恢复」,而不是为每一种局部故障写一条补丁路径。
- Fail fast and recover fast:可用性依赖缩短检测与重配时间;论文报告生产集群上该路径通常较短(见论文 §5.3,本文不转述具体数字为自测结论)。
- Simulation testing:确定性模拟把网络、磁盘、时钟变成可重放故障源——方法论见站内 distributed/54,工程落点见本系列第 14 篇。
1.2 与「每个副本投票掩盖故障」的分叉
论文明确对比:多数分布式数据库用 quorum 掩盖故障;FDB 更倾向 急切检测并重配,从而在同类容错目标下可用 \(f+1\) 而非 \(2f+1\) 副本(Zhou et al., SIGMOD 2021, Abstract / §1)。代价是恢复窗口内写路径可能暂停,且该策略更适合局域 / 城域部署;跨区域另有多 region 策略(论文 §3),本系列第 13、16 篇再钉运维边界。
这不是「没有共识」:Coordinators 上仍用 Active Disk Paxos 管配置(论文 §2.3.1)。共识的边界停在配置与世代,而不是每个用户 mutation 都走一轮 Paxos——第 3 篇专门收这条线。
二、与站内系列的分工
| 话题 | 已有内容 | 本系列怎么用 |
|---|---|---|
| etcd / TiKV / FDB 横向选型 | distributed/39 | 第 1、18 篇回链;不复述性能表 |
| 确定性模拟方法论 | distributed/54 | 第 14 篇只钉 FDB 角色恢复接口 |
| Multi-Raft / Percolator SI | tikv-htap | 第 8–9、18 篇对照严格可串行化 |
| Raft 安全不变量 | raft-explained | 第 3、13 篇只引用边界,不重讲选举 |
| LSM 单机引擎 | rocksdb | 第 12 篇对照 Redwood / SSD Engine |
一句话:distributed/39 讲何时选;tikv-htap 讲另一条严格程度不同的事务栈;本系列讲 FDB 七角色写路径与恢复如何兑现严格可串行化。
flowchart LR
kv39["distributed/39<br/>selection"]
tikv["tikv-htap<br/>Multi-Raft + Percolator SI"]
sim54["distributed/54<br/>det. simulation method"]
this["This series<br/>FDB Unbundled kernel"]
kv39 --> this
tikv -->|"contrast OCC SSI"| this
sim54 -->|"method"| this
常见误解
- 「FoundationDB 就是带事务的 etcd」。etcd 以单 Raft 组复制状态机为主;FDB 把提交日志与服务读的存储拆开,客户端读直接打到 Storage Server(Zhou et al., §2.3.3)。把运维习惯从「看 Raft 选主」平移过来,会错过 Proxy / Sequencer 世代切换。
- 「和 TiKV 一样,按 Region 理解副本即可」。TiKV 的复杂度在 Multi-Raft;FDB 的复杂度在角色管线与 OCC 窗口。Shard 存在,但提交正确性不依赖「每个 shard 一个共识组」这条主轴。
- 「Unbundled 等于无单点」。Sequencer、Cluster Controller 等是逻辑单例角色,失败走招募与恢复;不等于「该职责没有高可用设计」。第 6 篇专门纠「逻辑单点 = 无 HA」。
三、一次事务穿过哪几跳
后续篇目反复引用下面这条路径。以客户端事务读
user:42、再写入新值并提交为例(细节 API 见第 2
篇,提交流水线见第 7 篇)。
- 拿 read version:客户端联系 Grv Proxy;Proxy 向 Sequencer 取得不低于已知已提交版本的 read version,并确认本世代日志系统仍有效(官方 Architecture:Determine Read Version)。
- 读:客户端带该版本直接访问持有对应 key range 的 Storage Server;写缓存在客户端本地,读己之写由客户端合并缓冲与远端结果(论文 §2.4.1)。
- 提交:客户端把读冲突范围与写集合发给 Commit Proxy。
- 定 commit version:Commit Proxy 向 Sequencer 申请严格更大的 commit version。
- 冲突检测:Resolver 在约 5 秒的近期写历史上做 OCC;任一 Resolver 报冲突则整笔 abort(论文 Algorithm 1;官方 Known Limitations 与 Architecture)。
- 持久化:无冲突则 mutation 写入满足复制策略的 Log Server;日志 durable 后 Proxy 向客户端返回成功,并向 Sequencer 汇报已提交版本。
- 异步可读:Storage Server 后台从 Log Server 拉日志并 apply;提交成功与「某副本上立刻可读」之间允许短暂滞后(论文 §2.4.3)。
sequenceDiagram
participant Client
participant GrvProxy as Grv Proxy
participant CommitProxy as Commit Proxy
participant Seq as Sequencer
participant Res as Resolver
participant TLog as Log Server
participant SS as Storage Server
Client->>GrvProxy: get read version
GrvProxy->>Seq: request read version
Seq-->>GrvProxy: read version
GrvProxy-->>Client: read version
Client->>SS: read at version
SS-->>Client: values
Client->>CommitProxy: commit(read/write sets)
CommitProxy->>Seq: request commit version
Seq-->>CommitProxy: commit version
CommitProxy->>Res: check conflicts
Res-->>CommitProxy: ok / conflict
CommitProxy->>TLog: persist mutations
TLog-->>CommitProxy: durable
CommitProxy-->>Client: committed
TLog -.-> SS: async pull and apply
只读事务可在客户端本地「提交」而无须走完整写管线(论文 §2.4.1);这解释了为何文档强调读扩展跟 Storage Server 数量走、写扩展跟 Proxy / Resolver / Log Server 走。
四、本系列 18 篇地图
系列按「全景与角色 → 事务与严格可串行化 → 日志与存储 → 恢复 / 模拟 / Layer → 排障与选型」组织。完整依赖图见 系列 index。
flowchart TD
A["01 Unbundled overview"] --> B["02 Client API"]
A --> C["03 Coordinator"]
A --> D["04 Proxy"]
C --> E["05 Role topology"]
D --> E
E --> F["06 Sequencer"]
F --> G["07 Write pipeline"]
B --> H["08 Resolver OCC"]
G --> H
H --> I["09 Strict serializability"]
G --> J["10 TLog"]
J --> K["11 Storage Server"]
K --> L["12 Redwood"]
C --> M["13 Recovery"]
M --> N["14 Simulation"]
B --> O["15 Record Layer"]
K --> P["16 Operations"]
I --> Q["17 Troubleshooting"]
P --> Q
O --> R["18 Selection"]
N --> R
Q --> R
第 1–6 篇建立坐标系:API 契约、配置与招募、Proxy、拓扑总图、Sequencer。第 7–9 篇把严格可串行化与 5 秒窗口钉死。第 10–12 篇进入 durable 与 readable 的解耦。第 13–18 篇落到恢复、模拟、Layer、运维与选型。
学术谱系(本篇锚点)
Unbundled / 事务与存储分离的讨论可追溯到 Deuteronomy 等「把事务组件与数据组件拆开」的路线(论文 Related Work 引用 Lomet et al. 等)。FoundationDB 的工程分叉点是:OCC + MVCC 兑现严格可串行化,日志与存储异步衔接,并用确定性模拟压测试代价。与 TiKV「Multi-Raft + Percolator SI」相比,优化目标都是可扩展 OLTP,但一致性模型、故障处理哲学与扩展轴不同——第 9、18 篇再对照。
开放问题(本系列后续回答,此处只立题):高冲突下 OCC 重试是否可接受;durable 与 readable 的尾延迟如何观测;何时该停在 Layer 而非把数据模型塞进核心。
五、一层抽象:Layer 与「刻意变少」的核心
论文 Introduction 强调:FDB 提供有序、跨全 key 空间严格可串行化的 KV,但不捆绑完整查询语言、固定关系模型或内建二级索引语义。上层用 Layer(无状态、跑在客户端或旁路服务)把记录、文档、图等模型映射回 KV 事务。Record Layer、JanusGraph 插件、以及将 CouchDB 重建为 Layer 的路线,都被论文当作「窄核心是否够用」的证据。
对本系列的含义:
- 第 1–14、16–17 篇讲的是核心不变量;第 15 篇只在边界上碰 Record Layer。
- 看到「FDB 不能直接跑 SQL」不是缺陷清单项,而是分工:SQL/记录模型的正确性依赖 Layer 是否在同一事务里维护好派生 key。
- 与 TiDB「SQL 层无状态 + 存储层有状态」相似的是无状态上移;不同的是 FDB 核心连「表」都不定义。
flowchart TB
layers["Layers: Record / Document / Graph / ..."]
api["Ordered KV API<br/>strictly serializable txn"]
roles["Unbundled roles<br/>Proxy Sequencer Resolver TLog Storage"]
layers --> api
api --> roles
六、小结
三句话小结
- FoundationDB 用控制面 + 数据面(TS / LS / SS)把版本、冲突、日志持久化与版本化读拆成可独立扩展的角色,而不是「每份数据一个完整共识状态机」。
- 一次写事务的骨架是:Grv Proxy 取 read version → Storage 读 → Commit Proxy → Sequencer 定 commit version → Resolver OCC → TLog durable → Storage 异步 apply。
- 本系列从 SIGMOD 2021 与 7.x 文档下沉到生产路径;与 distributed/39、tikv-htap、distributed/54 分工明确,不重复选型表与模拟方法论全文。
下一篇进入客户端契约:Client API 与事务模型。
参考资料
核心论文
- Zhou, J. et al., FoundationDB: A Distributed Unbundled Transactional Key Value Store, SIGMOD 2021, DOI: 10.1145/3448016.3457559(Unbundled 架构、事务路径、OCC、恢复与模拟)。
规范 / 文档
- FoundationDB Documentation, Architecture(7.x;Master / Grv Proxy / Commit Proxy / Resolver / Transaction Log / Storage Server)。
- FoundationDB Documentation, Developer Guide、Known Limitations(事务模型与 5 秒等设计限制)。
站内
- distributed/39 分布式 KV 存储对比。
- TiKV / HTAP 内核。
- distributed/54 确定性模拟。
- 本系列 index(含规划入口与篇目地图)。
上一篇:系列目录
下一篇:Client API 与事务模型
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【FoundationDB 内核】角色拓扑与数据流:读写总图与扩展边界
用一张读写总图串联 FoundationDB 各角色,标明哪些可水平扩展、哪些是逻辑单例,并与 TiKV 多组件分离作机制对照。
【FoundationDB 内核】Unbundled · OCC · TLog · Redwood · Simulation
补齐 FoundationDB 选型叙事与生产内核之间的一层:拆解 Proxy、Sequencer、Resolver、TLog、Storage Server 的 Unbundled 写路径,严格可串行化、Redwood 与确定性模拟,并以 Record Layer 和 TiKV/etcd 对照收束。
【FoundationDB 内核】写事务流水线:Client → Commit Proxy → Sequencer → Resolver → TLog
钉住 FoundationDB 一次写事务的提交路径:Client 经 Commit Proxy 取 commit version、Resolver 做 OCC、TLog 多数持久化后才向客户端返回成功;并划清「提交成功」与「Storage Server 可读」之间的边界。
【FoundationDB 内核】Sequencer:read/commit version、逻辑单点与恢复
说明 Sequencer 如何分配 read version 与 commit version、为何是逻辑单点而非无高可用,以及世代恢复如何与版本推进衔接。