Li Sheng | Backend / Distributed Storage Engineer Li Sheng | Backend / Distributed Storage Engineer
Home
Resume
Projects
Topics
Notes
GitHub (opens new window)
Home
Resume
Projects
Topics
Notes
GitHub (opens new window)
  • Go语言

  • C++

  • 算法题

  • 存储系统

    • 导航

    • 单机IO基础

    • IO语义与持久化

    • 块层与高速路径

    • Ceph

      • 架构与核心概念

      • 数据分布与一致性

      • 数据路径与存储引擎

        • Ceph数据路径总览
        • OSD上的数据管理
        • ceph分布式存储-集群通信
        • Ceph写请求确认路径
          • 1. 先记住一个最核心的事实
          • 2. 一次写请求最简化的流动顺序
          • 3. 为什么客户端通常只和 Primary OSD 交互
          • 4. Primary OSD 到底在协调什么
          • 5. 为什么“副本收到了”还不等于“已经安全”
          • 6. ack 为什么会直接影响延迟
          • 7. 为什么副本数量和 PG 状态会影响确认路径
          • 8. 为什么这篇要和底层 I-O 语义一起看
          • 9. 一个实用的判断框架
          • 10. 这篇最适合承接哪些后续专题
          • 11. 与当前笔记的关系
      • 运维与调优

      • 实验与性能测试

    • DAOS

    • 归档

  • CephFS

  • 分布式系统

  • 计算机网络

  • Redis与缓存

  • Kubernetes

  • 技术笔记
  • 存储系统
  • Ceph
  • 数据路径与存储引擎
lisheng
2026-04-27
目录

Ceph写请求确认路径

# Ceph写请求确认路径

Ceph 写请求里最容易混淆的几个词是:

  • 客户端把请求发出去了
  • Primary OSD 收到了
  • 副本 OSD 也收到了
  • Primary OSD 给客户端回 ack 了
  • 数据真正落到稳定存储了

这些不是一回事。

这篇文章的目标,就是把一次 Ceph 写请求从“客户端发出”到“客户端收到确认”的主路径拆开,并说明确认边界为什么会直接影响一致性语义和尾延迟。

# 1. 先记住一个最核心的事实

Ceph 的写确认不是“客户端把数据发给某个 OSD 就结束了”,而是:

Primary OSD 需要先协调副本 OSD,把一次写请求推进到系统认可的确认边界,然后才会对客户端返回成功。

所以写请求确认路径,本质上回答的是:

Ceph 在什么时点认为这次写可以算“成功”。

# 2. 一次写请求最简化的流动顺序

把路径先压缩成 6 步:

  1. 客户端根据对象名计算 PG 和目标 OSD 集合
  2. 客户端把请求发给 Primary OSD
  3. Primary OSD 接收请求并分配本次操作上下文
  4. Primary OSD 把写请求复制给副本 OSD
  5. 副本 OSD 返回各自的处理确认
  6. Primary OSD 在达到确认条件后,向客户端返回 ack

这 6 步里,真正复杂的不是“写数据”本身,而是:

  • Primary 和 replica 之间的确认语义
  • 什么时候算 enough replicas
  • ack 返回时,数据到底处在内存、日志还是稳定介质

# 3. 为什么客户端通常只和 Primary OSD 交互

Ceph 客户端虽然能自己通过 CRUSH 算出目标 OSD 集合,但一次写操作通常仍然由 Primary OSD 统一协调。

这么做的原因很直接:

  • 避免客户端自己协调多个副本
  • 把副本一致性逻辑收敛到 OSD 侧
  • 让 PG 维度的写顺序和状态管理更集中

你可以把 Primary OSD 理解成:

这次写操作在该 PG 上的“协调者”和“提交边界判断者”。

# 4. Primary OSD 到底在协调什么

Primary OSD 真正在做的事情,通常包括:

  • 校验本次写请求是否落在当前 PG 的有效映射上
  • 组织对象更新所需的本地和副本操作
  • 把更新发送给副本 OSD
  • 收集副本返回结果
  • 判断本次写是否达到 ack 条件

所以它不是单纯的“中转站”,而是整个写确认路径里最关键的控制点。

# 5. 为什么“副本收到了”还不等于“已经安全”

这是 Ceph 写路径里最关键的理解点之一。

副本 OSD 收到写请求,可能只意味着:

  • 请求已经进入 OSD 处理路径
  • 数据已经进入某种内存缓冲或事务上下文
  • 相关操作已经写入某种日志或待提交结构

但这不天然等于:

  • 数据已经进入稳定存储
  • 所有相关元数据都已经提交完成
  • 断电后一定还能恢复出刚刚这次写

所以看 Ceph 的确认路径时,一定要把下面几件事分开:

  1. 网络接收成功
  2. OSD 内部处理成功
  3. 副本确认成功
  4. 本地提交完成
  5. 稳定持久化完成

# 6. ack 为什么会直接影响延迟

因为 ack 返回得越早,客户端看见的延迟通常越低; 但 ack 返回得越早,系统承诺给客户端的“安全程度”通常就越弱。

所以确认路径其实就是一致性和性能的交叉点。

Ceph 的尾延迟很容易在这里被放大,因为一次写确认往往要等:

  • Primary OSD 本地处理
  • 网络发送到 replica
  • replica 处理
  • replica 返回确认
  • Primary 汇总确认再返回客户端

这条链路上的任何慢点,都可能让 ack 变慢。

# 7. 为什么副本数量和 PG 状态会影响确认路径

一次写请求不是在抽象世界里发生的,而是在某个具体 PG 上发生的。

所以确认路径天然会受这些因素影响:

  • 当前 PG 有多少副本
  • 哪个 OSD 是 Primary
  • 某个 replica 是否慢
  • PG 是否正在 peering、recovering 或 degraded

这也是为什么同样一条写请求,在集群健康和集群恢复期间,确认路径的表现会完全不同。

# 8. 为什么这篇要和底层 I-O 语义一起看

Ceph 的 ack 路径虽然是分布式系统问题,但最终又会落回单机存储语义问题:

  • OSD 内部什么时候算提交
  • BlueStore 什么时候算把修改推进到稳定边界
  • 本地 WAL / DB / 主数据设备之间的提交顺序是什么
  • 底层设备 flush 何时参与

所以 Ceph 写确认路径不能只从“副本复制”角度理解,还要继续往下接:

  • fsync、写回与刷盘语义
  • 文件系统日志与崩溃恢复
  • 块层与I-O调度总览

# 9. 一个实用的判断框架

以后看 Ceph 的写延迟或一致性问题,可以先问这几个问题:

  1. 这次写是在哪个 PG 上发生的?
  2. Primary OSD 和 replica OSD 的角色分配是什么?
  3. ack 返回时,系统实际承诺的是“收到”还是“提交到更稳定边界”?
  4. 是网络复制慢,还是某个 OSD 本地提交慢?
  5. 问题出在 Ceph 副本确认层,还是已经落到 BlueStore / 块层 / 设备层?

这套问题能帮助你迅速判断瓶颈是在“分布式复制协调”,还是已经深入到底层 I/O。

# 10. 这篇最适合承接哪些后续专题

在这篇之下继续拆,最自然的是:

  • 12.Ceph读路径与Primary OSD
  • 13.BlueStore提交路径
  • 14.PG状态变化如何影响数据路径
  • 15.Ceph尾延迟从哪几层来

其中下一篇最适合接的是 13.BlueStore提交路径,因为它可以继续回答:

Primary OSD 为什么敢回 ack,以及这个 ack 在本地存储语义上到底站在哪个边界。

# 11. 与当前笔记的关系

  • 数据路径入口:Ceph数据路径总览
  • OSD 内部管理:OSD上的数据管理
  • 映射关系入口:PG和PGP的区别
  • I-O语义与路径骨架:VFS层
Edit (opens new window)
Last Updated: 2026/04/28, 15:19:51
ceph分布式存储-集群通信
ceph分布式存储-对象存储(RGW)搭建

← ceph分布式存储-集群通信 ceph分布式存储-对象存储(RGW)搭建→

最近更新
01
待完成专题池
04-28
02
待完成专题池
04-28
03
为什么 Kubernetes CSI 插件架构要拆成 Controller、Node 与 Sidecar
04-28
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式