机制已经沿 Proxy → Sequencer → Resolver → TLog → Storage 走通。生产告警往往只给一句「延迟高 / 报错多」。本文把四类高频问题——事务超时、冲突风暴、Sequencer 切换、Storage 落后——收成症状 → 机制决策树,并回链本系列对应章节。具体阈值以 7.x 官方文档为准,正文不承诺适用于所有集群的固定参数。
版本锚定:FoundationDB 7.x Developer Guide / Known Limitations / Administration;恢复机制见 Zhou et al., SIGMOD 2021 §2.4.4。
一、总决策树:先分流再下钻
flowchart TD
SYM["Symptom: latency errors retries"]
SYM --> Q1{"transaction_too_old or 5s window?"}
Q1 -->|yes| TIMEOUT["Txn timeout path<br/>Section 2"]
Q1 -->|no| Q2{"High not_committed conflict rate?"}
Q2 -->|yes| CONF["Conflict storm<br/>Section 3"]
Q2 -->|no| Q3{"Recovery or Sequencer restart in status?"}
Q3 -->|yes| SEQSW["Sequencer epoch switch<br/>Section 4"]
Q3 -->|no| Q4{"Storage versions lag TLog / slow reads at latest?"}
Q4 -->|yes| SSLAG["Storage lag<br/>Section 5"]
Q4 -->|no| OTHER["Client network disk Ratekeeper<br/>see ops article"]
| 分流问题 | 优先信号 | 机制锚点 |
|---|---|---|
| 是否踩 5 秒 / 过大事务 | transaction_too_old、官方限制文档 |
第 9 篇 |
| 是否 OCC 冲突 | not_committed、重试风暴 |
第 8 篇 |
| 是否世代恢复 | status 恢复中、角色重招 |
第 13 篇 |
| 是否存储追日志慢 | 读最新版本等待、SS 与 TLog 间隙 | 第 10–11 篇 |
二、事务超时与「事务过旧」
2.1 机制
Known Limitations:自事务第一次读起超过约
5 秒,后续需访问数据库的读通常报
transaction_too_old;带写的提交也会以
transaction_too_old 或
not_committed 失败。这与严格可串行化下的 MVCC
窗口、冲突历史有界绑定(第 9 篇),不是客户端「随便设的
timeout」。
另两组常被混谈的限制:
- 事务影响数据约 10 MB 上限;超过约 1 MB 的「大事务」文档警告可能影响性能甚至短暂可用性;
- 单键 ≤ 10 KB、单值 ≤ 100 KB。
2.2 症状 → 动作
flowchart TD
E["Error: transaction_too_old"]
E --> A{"Txn held open across user think time?"}
A -->|yes| APP["Close txn; move interactive work out"]
A -->|no| B{"Huge read or write set?"}
B -->|yes| SPLIT["Split into small txns or indirection"]
B -->|no| C{"Cluster recovering?"}
C -->|yes| WAIT["Retry after epoch recovery Section 4"]
C -->|no| D["Check client RTT and SS read stalls"]
处置方向(机制级):
- 交互流程不要跨用户思考时间持有同一事务;
- 大范围扫描用分页 / limit,避免巨型冲突范围;
- 批量导入用官方文档建议的短事务 + 间接交换,而不是单笔超大写。
三、冲突风暴
3.1 机制
Resolver 在 commit 版本已分配后做 OCC 冲突检测(第 8 篇)。读集与并发写集相交则 abort,客户端按 API 契约重试。冲突风暴的典型样貌是:CPU 与网络仍「忙」,但成功提交比例下降,重试放大写路径负载。
3.2 分流
| 观察 | 更可能原因 | 方向 |
|---|---|---|
| 冲突集中在少数 key 前缀 | 业务热点 / 计数器 | 原子操作、打散键、降低读改写 |
| 冲突随二级索引写入升高 | Record Layer 索引扇出 | 检查索引设计(第 15 篇) |
| 冲突在恢复后短时升高 | 重试叠加 | 退避;确认恢复已结束 |
| 几乎无冲突但提交仍慢 | 不是冲突风暴 | 转到 §四 / §五 |
flowchart LR
CONF["Conflict storm"]
CONF --> HOT["Hot keys"]
CONF --> IDX["Index amplification"]
CONF --> RETRY["Retry amplification"]
HOT --> FIX1["Atomic ops or key shatter"]
IDX --> FIX2["Narrow indexes"]
RETRY --> FIX3["Backoff and find root latency"]
不要把 Ratekeeper 限速误判成「冲突」:限速是过载保护(第 16 篇),冲突是 Resolver 语义拒绝。
四、Sequencer 切换与写暂停
4.1 机制回顾
任一被 Sequencer 监视的 Proxy / Resolver / LogServer 失败,或配置变更,Sequencer 终止;ClusterController 招募新 Sequencer,开新 epoch(第 13 篇)。窗口内旧 TLog 停写,新世代未接受提交前,写路径不可用。论文生产观测恢复常在约 5 秒量级(作者数据,非本站实测)。
4.2 症状
- 短时大量提交失败或超时,随后自行恢复;
fdbcli status显示恢复 / 角色变化(以你环境实跑为准);- 读可能仍部分可用,但新 read version 获取也可能受影响。
4.3 排障顺序
- 确认是否在做配置变更、排除进程、升级——预期内切换。
- 若非预期:查哪一类角色先失败(TLog 磁盘、Proxy OOM、网络分区)。
- 切换频繁时,优先查 TLog 稳定性与磁盘,因为 LogServer 失败会逼出完整恢复路径。
- 客户端保持幂等重试;不要在半恢复窗口对同一业务键做「人工补偿双写」。
sequenceDiagram
participant OPS as Operator
participant ST as fdbcli status
participant CL as Clients
OPS->>ST: Observe recovery flags
ST-->>OPS: New Sequencer recruited
CL->>CL: Commits fail then succeed
OPS->>OPS: If frequent find first failing role
五、Storage 落后于 TLog
5.1 机制
提交在 TLog 持久化并满足复制后即可向客户端确认;Storage 异步拉日志(第 10–11 篇)。因此存在「已提交但某 SS 尚未追上」的间隙。FDB paper Figure 3 展示过某一生产集群上的 lag 分布——说明间隙存在且通常很小,但不是零,也不能把该图数字当成你的 SLO。
读最新版本时,若 SS 尚未具备该版本,请求会等待或走文档所述的延迟路径;慢性落后则表现为读尾延迟升高、落后副本上的局部现象。
5.2 决策
flowchart TD
LAG["Suspect storage lag"]
LAG --> R{"Only some SS slow?"}
R -->|yes| DISK["Disk IO network on those processes"]
R -->|no| W{"Write rate vs apply capacity?"}
W -->|yes| SCALE["Add storage or reduce write burst"]
W -->|no| REC{"Just finished recovery?"}
REC -->|yes| RV["Expect catch-up after RV; watch progress"]
REC -->|no| ENG["Check storage engine health Redwood or SSD"]
与恢复的交叠:epoch 切换后 Storage 可能丢弃高于 RV 的内存版本再从新 TLog 拉——短时「落后」是预期,应观察是否收敛,而不是立刻当硬件故障。
5.3 读等待与「假冲突」
客户端若在 SS 尚未追上时频繁重试整笔事务,可能把等待可见版本放大成冲突与超时混合物。排障时应先看:
- 错误码是否主要是冲突类,还是读超时 / 版本不可用类;
- 落后是否只在部分 SS(局部磁盘/网络)还是全局写爆;
- Ratekeeper 是否已在限速(第 16 篇)——限速时加压重试会更糟。
六、把排障接回测试与运维
| 手段 | 作用 |
|---|---|
| 第 14 篇 模拟 | 正确性与恢复竞态;不解释你集群的磁盘尾延迟 |
| 第 16 篇 画像 | 扩哪类角色、备份/DR 边界 |
| 本篇决策树 | 线上症状分流 |
三者一起用:模拟保证「这类故障恢复逻辑存在」,运维保证「角色资源大致匹配」,排障保证「当前告警落到具体机制」。
6.1 最小取证清单
在改配置或扩容前,尽量留下:
- 错误码分布(
transaction_too_old/not_committed/ 超时); - 是否与发布、排除进程、
configure变更同时段; status details中的恢复与角色异常(实跑记录,本站不伪造);- 冲突是否集中在已知热前缀或某一索引。
取证不足时,优先观察一个恢复/冲突窗口再动作,避免同时改键、加机器、关 Ratekeeper 导致无法归因。
6.2 四类问题的「先看什么」速查
| 类 | 先看 | 不要先做 |
|---|---|---|
| 超时 | 事务持有时长、读写集大小、是否恢复中 | 盲目加大客户端 timeout |
| 冲突 | 热 key、索引扇出、重试率 | 关掉冲突检测(不存在这种开关) |
| Sequencer 切换 | 是否变更/角色失败、切换频率 | 在窗口内人工双写补偿 |
| Storage 落后 | 局部 vs 全局、磁盘、是否刚恢复 | 立刻当「数据丢失」做还原 |
七、学术谱系、工程间隙与开放问题
谱系:OCC + 有界 MVCC 窗口(FDB 事务模型)→ 失败收敛到恢复(SIGMOD 2021)→ 日志与存储解耦带来的可见性间隙(同论文 §2.4)。
工程间隙:公开文档对「该看哪个指标面板」的描述随部署(裸机、Kubernetes Operator、托管)而变;本篇只钉机制分流,不绑定某一套 Grafana JSON。
开放问题:
- 冲突率与 Ratekeeper 限速同时升高时,缺少统一的「根因归因」标准信号。
- Storage lag 的用户可见 SLO 如何定义(P99 读最新 vs 允许读略旧)仍属产品策略。
- 频繁 epoch 切换的「健康阈值」无官方单一数字。
八、常见误解
误解一:所有超时都是网络问题。
先区分
transaction_too_old(窗口)、冲突重试耗尽、恢复写暂停三类。
误解二:Storage 落后说明提交丢失。
提交确认点在
TLog;落后影响的是读可见时机,不是默认丢提交(除非与 RV
回滚等恢复语义叠加,见第 13 篇)。
误解三:提高客户端 timeout
就能做长事务。
服务端 5 秒限制不会因客户端 timeout 变长而消失。
九、小结
三句话小结:
- 先用总决策树把症状分到超时、冲突、Sequencer 切换、Storage 落后四条机制链,再下钻。
- 超时绑定 5 秒窗口与事务大小限制;冲突风暴要拆热点、索引与重试放大;切换对应 epoch 写暂停;落后对应异步 apply。
- 排障不替代模拟与容量规划;无本站实测输出时,以官方错误码与
status实跑结果为准。
参考资料
- FoundationDB 7.x Known Limitations(5 秒、事务大小、读均衡限制)。
- Zhou J., et al. FoundationDB…. SIGMOD 2021. §2.4 事务与恢复;Figure 3 storage lag。
- 第 8–11、13、16 篇。
上一篇:运维与容量:角色资源画像
下一篇:选型与阅读地图
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【FoundationDB 内核】Unbundled 全景:事务、日志与存储为何拆开
以 SIGMOD 2021 为锚点,厘清 FoundationDB 控制面与数据面角色分工,说明一次事务穿过 Proxy、Sequencer、Resolver、TLog、Storage 的路径,并与站内 distributed/39、tikv-htap 划清边界。
【FoundationDB 内核】角色拓扑与数据流:读写总图与扩展边界
用一张读写总图串联 FoundationDB 各角色,标明哪些可水平扩展、哪些是逻辑单例,并与 TiKV 多组件分离作机制对照。
【FoundationDB 内核】Sequencer:read/commit version、逻辑单点与恢复
说明 Sequencer 如何分配 read version 与 commit version、为何是逻辑单点而非无高可用,以及世代恢复如何与版本推进衔接。
【FoundationDB 内核】写事务流水线:Client → Commit Proxy → Sequencer → Resolver → TLog
钉住 FoundationDB 一次写事务的提交路径:Client 经 Commit Proxy 取 commit version、Resolver 做 OCC、TLog 多数持久化后才向客户端返回成功;并划清「提交成功」与「Storage Server 可读」之间的边界。