← 返回题目列表

一次分布式存储写入通常经历哪些步骤?

中等 第 22 / 27 题 更新于 2026/09/30
写路径WAL副本复制幂等
学习 AI 实战项目

简化版

写请求通常经过鉴权限流、分片路由与 epoch 校验、Leader/协调者排序、WAL 持久化、副本复制达到确认条件、提交并应用本地引擎,最后返回版本或提交水位。客户端超时不等于失败,重试必须带幂等 ID;“成功”还要明确是主节点落盘、远端落盘、多数提交还是状态机已应用。

详细版

网关先校验租户、配额和请求大小,再按 key 找到 shard。旧路由请求应收到 STALE_EPOCH 并刷新,旧 owner 不能继续接受写。

Leader 为命令分配 term/index 或协调者生成版本,追加 WAL 后复制到副本。三副本 Raft 通常在当前任期日志被 2 个副本持久化后推进提交,不必等待第三个。

提交与应用不同:commitIndex 已形成共识,appliedIndex 表示本地引擎已执行。是否在 apply 后才回复取决于 API 返回内容,但后续线性读必须等到相应应用水位。

若客户端 100 ms 超时,而服务器在 110 ms 提交,直接用新请求号重试可能重复扣款。应使用 clientId + requestSeq 或业务唯一键去重,并提供状态查询。

完整版教学

一、入口保护与路由

写入先做认证、授权、配额、大小限制和 deadline 校验,防止无效请求进入昂贵复制路径。路由元数据把 key 定位到 shard,客户端携带 epoch,服务端拒绝过期所有权。

client -> gateway -> shard leader -> WAL/log -> replicas -> commit -> apply -> ACK

二、排序与并发控制

Leader 模式由单一 Leader 给日志排序;无主系统由协调者向多个副本写版本,并在冲突时合并。条件写还要携带 expectedVersion,服务端用 CAS 防丢失更新。

写类型关键条件失败语义
普通 Put幂等请求号超时结果未知
CASexpectedVersion冲突需重读
事务写事务/锁时间戳可能需协调恢复
删除tombstone/version防旧值复活

三、WAL 与持久化边界

WAL 先顺序追加,让崩溃后可重放。写入 page cache 不等于断电持久,是否 fsync、组提交周期和设备写缓存策略共同决定 durable 语义。批量 fsync 可提高吞吐,却会增加等待和暴露窗口。

例如每 2 ms 组提交一次,100 个请求可共享一次 fsync;平均延迟增加约一个批次等待,但 IOPS 大幅降低。数字需结合设备 P99 压测,不能固定照搬。

四、副本复制与成功确认

三副本中 Leader 和一个 Follower 持久化即可形成多数,但 Raft 还要求当前任期提交规则。异步复制可能只等主节点;半同步可能等一个从库。API 文档必须明确 ACK 集合和故障后的 RPO。

少数派不可达时,共识写应失败或等待,而不是由旧 Leader 本地成功。超时发生在 ACK 前,写可能未发生、进行中或已提交,客户端必须按未知结果处理。

五、提交、应用与返回

共识提交后,各副本按日志顺序应用到 LSM/B+Tree。若命令包含外部副作用,apply 重放必须幂等;更好的做法是状态机只产生确定性本地状态,再由 Outbox 驱动外部动作。

返回最新对象时通常需等待本地 apply;只返回“已接受”可以更早,但 API 必须显式表示异步状态。不能用一个模糊的 success 同时代表多种完成层级。

六、超时、重试与背压

客户端携带稳定请求 ID,Leader 保存去重表或把业务唯一键写入状态机。重复请求返回原结果,而不是再次执行。去重记录的保留期必须覆盖最大重试窗口。

系统在 WAL 队列、复制窗口、apply backlog 或磁盘水位超标时应背压,拒绝比无限排队更可控。监控分解 route、queue、fsync、replication、commit、apply 各段延迟,以及 unknown-result、重试、去重命中和 stall。

记忆钩子:写路径的核心问题是“谁排序、写到哪里算成功、超时后如何不重复”,而不是只画一条主从复制箭头。

七、常见误区与追问

  • 误区:客户端超时就代表写失败。 请求可能已经提交,只是响应丢失。
  • 误区:WAL 写成功就代表多副本安全。 还要看远端确认和提交规则。
  • 误区:commitIndex 等于数据已可查询。 本地状态机可能尚未应用到该水位。
  • 追问:重试如何防重复扣款? 稳定请求 ID、业务唯一约束和状态机去重共同保护。
  • 追问:为什么要拒绝旧 epoch 写? 防止迁移后旧 owner 继续形成分叉。
  • 追问:写入慢如何定位? 分段看排队、fsync、复制、commit 和 apply,而非只看总延迟。

八、加强记忆

把写路径记成“校验路由、排序落 WAL、复制达门槛、提交再应用、携水位返回”。epoch 防写错分片,quorum 防已确认历史丢失,幂等 ID 处理未知结果,背压保护故障时资源。答清 ACK 的精确层级,才算讲清写入语义。