admin管理员组

文章数量:1027919

深入理解 BlueStore存储引擎,只需四步

大家好我是小义同学,这是大厂面试拆解——项目实战系列的第5篇文章,

”走暗路、耕瘦田、进窄门、见微光” 告诉我 面试关键就 深入理解自己项目 这个才是最考察基本功的地方。

知识地图:KV存储引擎---BlueStore

Ceph分布式锁的设计哲学与工程实践 提到 为了支持海量并发,满足多客户端,主副本等多节点数据达成一致, 设计了分布式锁,分布式锁特点

  1. 根据不同状态自驱转换,减少用户操作复杂性
  2. 持久化存储(下一代对象存储引擎BlueStore

本文 主要介绍什么是BlueStore,如何快速理解BlueStore并且进行优化。

image.png

一、BlueStore出现的背景、初衷

看版本变化

Ceph 12.2.0 正式版本发布

Ceph 12.2.0 正式版本发布

  • 2016年4月21 Jewel版本10.2.0,首次引入 BlueStore 存储引擎
  • 2017年8月29,Ceph 12.2.0 正式版本发布, 代号 Luminous,BlueStore 成为默认存储引擎

BlueStore 是一个从头开始设计的存储后端,旨在解决使用本地文件系统后端所面临的挑战。

BlueStore 仅用两年时间就实现了所有这些目标, 并成为 Ceph 的默认存储后端

文件系统作为分布式存储后端:从 Ceph 十年进化中汲 取的教训

文件系统作为分布式存储后端:从 Ceph 十年进化中汲 取的教训

上图看出 ceph不停变换后端从FileStore到BlueStore

BlueStore 的一些主要目标包括:

  1. 快速元数据操作(第 4.1 节)
  2. 对象写入无一致性开销(第 4.1 节)
  3. 基于写时复制的克隆操作 (第 4.2 节)
  4. 无日志记录的双重写入(第 4.2 节)
  5. 优化了 HDD 和 SSD 的 I/O 模式(第 4.2 节)

对比如下:

BlueStore vs FileStore

FileStore (基于文件系统)

BlueStore (直接管理裸设备)

核心优势说明

系统架构

XFS + LevelDB

RocksDB + 块设备

绕过文件系统直接管理磁盘,降低软件栈复杂度

双写问题

存在

无(原子写操作)

消除写放大,提升性能

批量读取

通过 XFS 文件系统读取(百万级别)

RocksDB 元数据 + 直接块设备访问

减少 I/O 路径延迟

对象列举

需对 XFS 文件排序

RocksDB 预排序键值(LSM 树结构**)

列表操作快 10 倍以上

批量删除

逐个删除 XFS 文件

批量删除 RocksDB 键值,批量事务

删除速度提升 50-100 倍

对象读缓存

依赖 XFS 缓存机制

需用户态实现(如 LRU 缓存)

灵活性更高,可定制化

克服本地文件系统面临什么挑战
挑战 1:高效事务
挑战 2:快速元数据操作
  • Ceph 与 FileStore 后端的关键元数据 挑战之一来自在大目录上的缓慢目录枚举( readdir ) 操作,
  • 以及返回结果的缺乏排序。
挑战 3:支持新的存储硬件

二、这个技术的优势和劣势分别是什么

  • 还有更强的
# Crimson: Next-generation Ceph OSD for Multi-core Scalability

# Crimson: Next-generation Ceph OSD for Multi-core Scalability

Crimson 是基于 Seastar C++ 框架实现的 Ceph 下一代 OSD,用以提升多核可扩展性与 I/O 性能。

Crimson 被设计为高性能对象存储守护程序 (OSD),针对 NVMe 等快速存储设备进行了优化。

为了实现这些目标,Crimson 使用包括 SPDK、DPDK 和 C++ Seastar 框架在内的尖端技术从头开始构建。

Crimson 继续沿用 BlueStore 作为底层存储后端

并在未来计划通过原生 Seastore 存储后端摆脱对 BlueStore 的依赖

三、技术的组成部分和关键点。

架构如下:

BlueStore主要4个技术点:

用户态直接写快设备( BlockDevice.)
  1. BlueStore 直接读写原始块设备(如 SSD/NVMe)
  2. 在用户态使用linux aio直接操作块设备,去除了本地文件系统的消耗

聪明你可能你会疑问

  1. 绕过文件系统,在用户态,怎么完成IO读写?
  2. RocksDB本身并不支持对裸设备的操?还是使用文件系统?矛盾
  3. 远离文件系统不能更好支持 - 对全SSD及全NVMe SSD闪存适配?
轻量文件系统
  1. BlueFS基于裸设备模拟一个简易的用户态文件系统,用于支持RocksDB。
  2. 支持 SSD/NVMe新硬件

聪明你可能你会疑问 : 为了使用RocksDB,有写一个文件系统?

  1. POSIX文件系统作为通用的文件系统,其很多功能对于RocksDB来说并不是必须的,为了进一步提升RocksDB的性能,RocksDB的场景量身定制一套本地文件系统,BlueFS也就应运而
  2. BlueRocksEnv封装文件系统的抽象接
文件系统磁盘空间管理和缓存管理
  1. 失去默认文件系统支持,要一个磁盘的空间管理系统,Bluestore采用Allocator进行裸设备的空间管理,目前支持StupidAllocator和BitmapAllocator两种方式;
  2. BlueStore 实现为用户态并通过 DirectIO 直接访问裸盘,因此不实用 kernel 提供的 page cache,为了提升读的性能,需要自行管理Cache。
RocksDB 键值存储元数据:
  1. 慢速层(Block):存储对象数据,通常使用 HDD。
  2. 高速层(DB):存储 RocksDB 的 SST 文件,通常使用 SSD。
  3. 超高速层(WAL):存储 RocksDB 日志,通常使用 NVMe

BlueStore是基于RocksDB和BlockDevice实现的ceph的对象存储

四、技术的底层原理和关键实现

4.1 先测试,在了解

目的:假设你需要对BlueStore优化,必须了解 IO过程是什么

测试 方法1:测试你的磁盘
FIO测试NVMe SSD裸盘的性能,并观察iostat状态
代码语言:javascript代码运行次数:0运行复制
fio -name=iouring_test 
-filename=/mnt/vdd/testfile 
-iodepth=32//I/O 引擎若使用异步模式,保持队列深度
-thread 
-rw=randread 
//定义 IO 类型。
//随机读 randread、
//随机写 randwrite、顺序读 read、顺序写 write、顺序读写 
//rw readwrite ,随机混合读写 randrw

-ioengine=io_uring //IO 引擎。同步模式psync、异步模式io_uring
-sqthread_poll=1

-direct=1
//是否使用 direct io,测试过程不使用OS 自带的buffer,使测试磁盘的结果更真实 
//direct io,跳过缓存,直接读写SSD


-bs=4k  //IO 的块大小。默认 4k
-size=10G 
-numjobs=1//thread number
-runtime=120  告诉fio在指定的时间段后终止处理。
-group_reporting

测试结果:

  1. 32 io_uring iops: qps:80w 完全发挥NVMe特性
  2. fio的numjob,iodepth提高NVMe SSD的性能.
测试 方法2 测试您的 Ceph 集群

推荐的基准测试工具

代码语言:javascript代码运行次数:0运行复制
1. fio -ioengine=rbd -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -pool=rpool_hdd -runtime=60 -rbdname=testimg
2. fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg
3. fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg

测试方法1 绕过文件系统,读NVMe_ ssd进行fio的读盘操作 iops 10w-80w

针对测试CEPH集群的性能时,nvme ssd的读写iops总量不超过4w+ why?

方法1 和方法2为何差距这么大

首先的青铜猜想是:

  • 在 Ceph 在 HDD 上并不慢:
  • Bluestore 的理论单线程随机写入性能是驱动器 IOPS 的 66%(2/3),
  • Ceph 的线性读写速度并不慢
  • 当你用 SSD 替换 HDD 并使用快速网络时,Ceph 的速度应该会几乎一样快,天真了 ❎
  • Ceph 都很难实现低于 0.5 毫秒的随机读取延迟和低于 1 毫秒的随机写入延迟。[
  • 单线程下,这意味着随机读取 IOPS 和随机写入 IOPS 分别只有 2000 和 1000,即使能达到这个结果[0.5-1毫秒 一个请求,一个秒多少个?]
  • Ceph "软件栈"引入了额外的 I/O 打包、网络传输与协议层延迟,使得 OSD 在压力下无法压满 NVMe,
  • fio 只是本地落盘,时延极小,因此能将 SSD 压。

大师理解的猜想

image.png

Ceph OSD 多层软件栈开销

  • Ceph 默认在 BlueStore 层使用 RocksDB 存储元数据,写请求要先进入 WAL,再写入 MemTable,后台异步 Compaction 会带来 100–300 µs 级别的额外延迟
  • RADOS & PG 流程:每次写操作需要通过 RADOS 协议,将数据发送到 Primary OSD 并复制到 Secondary OSD 后才确认,网络 RTT 累加典型在 0.1–0.5 ms 范围,吞吐受限
  • TCP/IP vs RDMA:Ceph 原生使用 Kernel TCP/IP,产生 system CPU、iowait 和软中断开销;采用 RDMA(iWARP/RoCE)可减少复制延迟并降低 CPU 占用,使 4K 随机写 IOPS 提升 17%–
  • NUMA 与 CPU 亲和
4.2 事务特性 和延迟统计
  • BlueStore可以理解为一个支持ACID事物型的 本地日志文件系统。
  • 所有的读写都是以Transaction进行。
  • BlueStore通过状态机的方式控制整个IO流程。
  • queue_transactions接口 向 BlueStore 提交 事务组完成一系列写请
iBlueStore写状态机
新手视角

基本流程

  • 准备(Prepare):在内存中组装本次要执行的写入与元数据操作,事务尚未落盘。
  • 编码(Encode):将内存中的操作打包并转化为块设备可识别的 I/O 请求,包括预写日志(WAL)记录或直接写入命令。
  • 提交(Submit):通过同步或异步 I/O 接口,将事务操作写入底层存储设备。
  • 确认(Commit):等待 I/O 完成后,标记事务已持久化,确保断电或崩溃时数据不丢失。 [
  • 应用(Apply):把已提交的变更应用到内存中的索引或缓存,更新对象元数据 write transaction that Ceph will apply atomically 关注重点
  • 原子性与持久性:只要事务完成,用户无需关心具体底层细节;
大师视角
代码语言:javascript代码运行次数:0运行复制
const char *get_state_name() {
switch (state) {
case STATE_PREPARE: return"prepare"; 

//主要工作:
//该阶段主要是IO前的准备工作
//这个阶段会调用`_txc_add_transaction`将OSD层面的事物转换为BlueStore层面的事物

//延迟指标:
//l_bluestore_state_prepare_lat,从进入状态机到prepare阶段完成,

case STATE_AIO_WAIT: return"aio_wait";
//主要工作:
//该阶段等待aio的完成
//aio完成后在回调函数中将事务状态设置为STATE_IO_DONE

//延迟指标:
//l_bluestore_state_aio_wait_lat,从prepare阶段完成开始到AIO完成,
//平均延迟受限于设备,SSD 0.03ms左右。

case STATE_IO_DONE: return"io_done";

//主要工作:
//该阶段完对IO进行保序,保证kv事务的顺序性。
//按顺序设置事务状态为STATE_KV_QUEUED,将事务放入kv_queue

//通知kv_sync_thread进行,去同步IO和元数据
//kv_sync_thread 线程调用 db->submit_transaction 将批量更新写入 RocksDB
//IO保序可能会block。

//延迟指标:
//l_bluestore_state_io_done_lat,
//平均延迟在0.004ms,通常很小主要耗在对SimpleWrite的IO保序处理上。
//下个阶段:STATE_KV_QUEUED阶段


case STATE_KV_QUEUED: return"kv_queued";
//主要工作:
//1 该阶段主要deal kv_sync_thread线程中把aio的元数据写入kv数据库
//2 将状态设置为STATE_KV_SUBMITTED。
//3 然后将事务放入kv_committing_to_finalize队列,并通知_kv_finalize_thread线程处理

//延迟指标:
//l_bluestore_state_kv_queued_lat,
case STATE_KV_COMMITTING: return"kv_committing";

//主要工作:等待kv元数据和IO数据的Sync完成,回调finisher线程
//该阶段主要在 kv_finalize_thread线程中将状态设置为STATE_KV_DONE
//并将回调函数放入finisher队列,在finisher线程中给客户端返回应答

//延迟指标:
//l_bluestore_state_kv_done_lat

case STATE_KV_DONE: return"kv_done";

//主要工作
//如果没有延迟IO,则直接将状态设置为STATE_FINISHING;
//如果有延时IO,则将状态设置为STATE_DEFERRED_QUEUED

case STATE_WAL_QUEUED: return"wal_queued";

case STATE_WAL_APPLYING: return"wal_applying";

case STATE_WAL_AIO_WAIT: return"wal_aio_wait";

case STATE_WAL_CLEANUP: return"wal_cleanup";

case STATE_WAL_DONE: return"wal_done";

case STATE_FINISHING: return"finishing";

case STATE_DONE: return"done";

//延迟统计
enum {

 l_bluestore_state_prepare_lat,

 l_bluestore_state_aio_wait_lat,

 l_bluestore_state_io_done_lat,

 l_bluestore_state_kv_queued_lat,

 l_bluestore_state_kv_committing_lat,

 l_bluestore_state_kv_done_lat,

 l_bluestore_state_wal_queued_lat,

 l_bluestore_state_wal_applying_lat,

 l_bluestore_state_wal_aio_wait_lat,

 l_bluestore_state_wal_cleanup_lat,

 l_bluestore_state_finishing_lat,

}

技术点1:线程+队列
  • 线程+队列是BlueStore事物状态机的重要组成部分
  • aio_thread线程:属于KernelDevice模块的,主要作用写物理磁盘 。
  • kv_sync_thread:更新元数据k/v,这些必须按顺序操作。BlueStore::_kv_sync_thread
  • kv_finalize_thread:BlueStore::_kv_finalize_thread(),设置状态为STATE_KV_DONE
技术点2:保证IO的顺序性以及并发性
  • 因为BlueStore使用异步IO,后提交的IO可能比早提交的IO完成的早,所以更要保证IO的顺序

4.2 BlueStore IO流程

BlueStore IO流程

BlueStore IO流程

BlueStore IO流程:Simple Write
  • 对于simple write场景,先把数据写入新的block,然后把元数据写入k/v数据库中
  • 写新block状态转换:STATE_PREPARE -> STATE_AIO_WAIT -> STATE_IO_DONE -> STATE_KV_QUEUED
  • 元数据写k/v数据库状态转换:STATE_KV_QUEUED -> STATE_KV_SUBMITTED -> STATE_KV_DONE -> STATE_FINISHING -> STATE_DONE

在处理simple-write时, 需要考虑offset、length是否对齐到block_size(4KB)以进行补零对齐的操作。

BlueStore IO流程:Deferred Write

(.png)

  • 对于deferred write场景,延迟IO数据封装在k/v事务中,
  • 写入kv数据库后给客户端返回应答,然后在后台执行延迟IO数据的写操作。

写k/v日志:

STATE_PREPARE -> STATE_IO_DONE -> STATE_KV_QUEUED -> STATE_KV_SUBMITTED -> STATE_KV_DONE -> STATE_DEFERRED_QUEUE

写数据:

STATE_DEFERRED_QUEUE -> STATE_DEFERRED_CLEANUP -> STATE_FINISHING -> STATE_DONE

主要步骤:延迟写入的基本流程:
  1. 当写入请求到来时,BlueStore 首先将数据写入 KV 数据库(RocksDB),并立即返回成功给客户端
  2. 实际的数据写入被延迟到后台处理,主要涉及以下几个关键数据结构:
  • bluestore_deferred_op_t: 封装单个延迟写操作
  • bluestore_deferred_transaction_t: 包含多个延迟写操作的事务
  • DeferredBatch: 批量处理多个延迟写事务,将多个写操作合并处理
  • OpSequencer: 确保写操作按正确顺序执行

慢点集中在哪里?

  • ceph daemon osd.8 perf dump | egrep "wait|lat"

综合来看,RocksDB 同步提交(阶段4)AIO 等待(阶段2) 是占比最高的两部分, 共计可超过 80% 的

64K随机写入(QD=16场景)

  • 总延迟:2.268ms(其中Store层占比达93%)
    • state_aio_wait_lat:0.797ms(较QD=1增长14.7倍)
    • state_kv_queued_lat:0.544ms(元数据队列等待,增长107倍)
    • state_kv_commiting_lat:0.689ms(RocksDB提交耗时,增长9.5倍)
    • Store层细分
    • 瓶颈根源
    1. 单线程设计kv_sync_thread需串行处理元数据提交,导致高QD下队列堆积(如kv_queued_lat从0.005ms升至0.544ms
    2. 异步I/O竞争:Linux AIO的io_submit在高并发时需频繁上下文切换,占用CPU核心资源

小结(三步走)

  1. FIO压测 :即便在读客户端压力足够的情况下 软 件层不能给到下层足够的I/O压力,不能利用起NVME强大的硬件并发性能。工具:fio,iostat,vmstat,iotop
  2. 读请求各阶段耗时分析 降低延迟。工具:ceph daemon osd.10 perf dump/perf /gdbpmp,慢的原因在哪里能说清楚吗?性能优化:上千提升上万,过10万是不可能的?为什么
  3. 如何证明:Ceph "软件栈"引入了额外的 I/O 打包、网络传输与协议层延迟,使得 OSD 在压力下无法压满 NVMe。

参考

【1】 File Systems Unfit as Distributed Storage Backends: Lessons from 10 Years of Ceph Evolution
  • 文件系统作为分布式存储后端:从 Ceph 十年进化中汲 取的教训
  • .1145/3341301.3359656
【2】Ceph OSD Crimson: Next-generation Ceph OSD for Multi-core Scalabilit
  • /
  • ceph-osd-cpu-scaling
  • /
  • /
[5] io_uring: So Fast. It's Scary. - Paul Moore, Microsoft
  • IO uring gets Zero Copy network operations
  • 随着存储和网络设备性能越来越高,用户发现kernel那厚重的存储栈和网络栈效率越发低下,分分推出kernel bypass技术,但这类技术有一个通病,就是接口设计不统一,无法兼容,所以业界迫切期待内核推出一套成熟高效通用的异步编程框架,来缓解厚重模块带来的影响
  • io_uring只通过提供3个系统调用接口,就统一了网络和存储异步IO编程框架,使得上层开发人员无需过多关注其接口的可扩展性
  • 深入理解io_uring(一)设计初衷
  • 深入理解io_uring(二)设计原理
  • strace -c dd if=/dev/zero of=test bs=1M count=1000
  • 深入理解io_uring(七)零拷贝发送网络请求
  • 深入理解io_uring(三)一个完整请求
[6] Understanding BlueStore, Ceph's New Storage Backend - Tim Serong, SUSE
  • .php?mobileaction=toggle_view_desktop&title=Ceph_performance#Why_is_it_so_slow
  • 2018-May-29 :: Ceph Code Walkthrough: BlueStore part 1 [视频 ]
  • Ceph BlueStore的状态机
  • Block I/O Layer Tracing using blktrace
  • 你可以通过 iostat、blktrace 工具分析瓶颈是在应用层还是内核层、硬件层。其中 blktrace 是 blkio 层的磁盘 I/O 分析利器,它可记录 IO 进入通用块层、IO 请求生成插入请求队列、IO 请求分发到设备驱动、设备驱动处理完成这一系列操作的时间,帮助你发现磁盘 I/O 瓶颈发生的阶段
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-28,如有侵权请联系 cloudcommunity@tencent 删除存储测试事务数据文件系统

深入理解 BlueStore存储引擎,只需四步

大家好我是小义同学,这是大厂面试拆解——项目实战系列的第5篇文章,

”走暗路、耕瘦田、进窄门、见微光” 告诉我 面试关键就 深入理解自己项目 这个才是最考察基本功的地方。

知识地图:KV存储引擎---BlueStore

Ceph分布式锁的设计哲学与工程实践 提到 为了支持海量并发,满足多客户端,主副本等多节点数据达成一致, 设计了分布式锁,分布式锁特点

  1. 根据不同状态自驱转换,减少用户操作复杂性
  2. 持久化存储(下一代对象存储引擎BlueStore

本文 主要介绍什么是BlueStore,如何快速理解BlueStore并且进行优化。

image.png

一、BlueStore出现的背景、初衷

看版本变化

Ceph 12.2.0 正式版本发布

Ceph 12.2.0 正式版本发布

  • 2016年4月21 Jewel版本10.2.0,首次引入 BlueStore 存储引擎
  • 2017年8月29,Ceph 12.2.0 正式版本发布, 代号 Luminous,BlueStore 成为默认存储引擎

BlueStore 是一个从头开始设计的存储后端,旨在解决使用本地文件系统后端所面临的挑战。

BlueStore 仅用两年时间就实现了所有这些目标, 并成为 Ceph 的默认存储后端

文件系统作为分布式存储后端:从 Ceph 十年进化中汲 取的教训

文件系统作为分布式存储后端:从 Ceph 十年进化中汲 取的教训

上图看出 ceph不停变换后端从FileStore到BlueStore

BlueStore 的一些主要目标包括:

  1. 快速元数据操作(第 4.1 节)
  2. 对象写入无一致性开销(第 4.1 节)
  3. 基于写时复制的克隆操作 (第 4.2 节)
  4. 无日志记录的双重写入(第 4.2 节)
  5. 优化了 HDD 和 SSD 的 I/O 模式(第 4.2 节)

对比如下:

BlueStore vs FileStore

FileStore (基于文件系统)

BlueStore (直接管理裸设备)

核心优势说明

系统架构

XFS + LevelDB

RocksDB + 块设备

绕过文件系统直接管理磁盘,降低软件栈复杂度

双写问题

存在

无(原子写操作)

消除写放大,提升性能

批量读取

通过 XFS 文件系统读取(百万级别)

RocksDB 元数据 + 直接块设备访问

减少 I/O 路径延迟

对象列举

需对 XFS 文件排序

RocksDB 预排序键值(LSM 树结构**)

列表操作快 10 倍以上

批量删除

逐个删除 XFS 文件

批量删除 RocksDB 键值,批量事务

删除速度提升 50-100 倍

对象读缓存

依赖 XFS 缓存机制

需用户态实现(如 LRU 缓存)

灵活性更高,可定制化

克服本地文件系统面临什么挑战
挑战 1:高效事务
挑战 2:快速元数据操作
  • Ceph 与 FileStore 后端的关键元数据 挑战之一来自在大目录上的缓慢目录枚举( readdir ) 操作,
  • 以及返回结果的缺乏排序。
挑战 3:支持新的存储硬件

二、这个技术的优势和劣势分别是什么

  • 还有更强的
# Crimson: Next-generation Ceph OSD for Multi-core Scalability

# Crimson: Next-generation Ceph OSD for Multi-core Scalability

Crimson 是基于 Seastar C++ 框架实现的 Ceph 下一代 OSD,用以提升多核可扩展性与 I/O 性能。

Crimson 被设计为高性能对象存储守护程序 (OSD),针对 NVMe 等快速存储设备进行了优化。

为了实现这些目标,Crimson 使用包括 SPDK、DPDK 和 C++ Seastar 框架在内的尖端技术从头开始构建。

Crimson 继续沿用 BlueStore 作为底层存储后端

并在未来计划通过原生 Seastore 存储后端摆脱对 BlueStore 的依赖

三、技术的组成部分和关键点。

架构如下:

BlueStore主要4个技术点:

用户态直接写快设备( BlockDevice.)
  1. BlueStore 直接读写原始块设备(如 SSD/NVMe)
  2. 在用户态使用linux aio直接操作块设备,去除了本地文件系统的消耗

聪明你可能你会疑问

  1. 绕过文件系统,在用户态,怎么完成IO读写?
  2. RocksDB本身并不支持对裸设备的操?还是使用文件系统?矛盾
  3. 远离文件系统不能更好支持 - 对全SSD及全NVMe SSD闪存适配?
轻量文件系统
  1. BlueFS基于裸设备模拟一个简易的用户态文件系统,用于支持RocksDB。
  2. 支持 SSD/NVMe新硬件

聪明你可能你会疑问 : 为了使用RocksDB,有写一个文件系统?

  1. POSIX文件系统作为通用的文件系统,其很多功能对于RocksDB来说并不是必须的,为了进一步提升RocksDB的性能,RocksDB的场景量身定制一套本地文件系统,BlueFS也就应运而
  2. BlueRocksEnv封装文件系统的抽象接
文件系统磁盘空间管理和缓存管理
  1. 失去默认文件系统支持,要一个磁盘的空间管理系统,Bluestore采用Allocator进行裸设备的空间管理,目前支持StupidAllocator和BitmapAllocator两种方式;
  2. BlueStore 实现为用户态并通过 DirectIO 直接访问裸盘,因此不实用 kernel 提供的 page cache,为了提升读的性能,需要自行管理Cache。
RocksDB 键值存储元数据:
  1. 慢速层(Block):存储对象数据,通常使用 HDD。
  2. 高速层(DB):存储 RocksDB 的 SST 文件,通常使用 SSD。
  3. 超高速层(WAL):存储 RocksDB 日志,通常使用 NVMe

BlueStore是基于RocksDB和BlockDevice实现的ceph的对象存储

四、技术的底层原理和关键实现

4.1 先测试,在了解

目的:假设你需要对BlueStore优化,必须了解 IO过程是什么

测试 方法1:测试你的磁盘
FIO测试NVMe SSD裸盘的性能,并观察iostat状态
代码语言:javascript代码运行次数:0运行复制
fio -name=iouring_test 
-filename=/mnt/vdd/testfile 
-iodepth=32//I/O 引擎若使用异步模式,保持队列深度
-thread 
-rw=randread 
//定义 IO 类型。
//随机读 randread、
//随机写 randwrite、顺序读 read、顺序写 write、顺序读写 
//rw readwrite ,随机混合读写 randrw

-ioengine=io_uring //IO 引擎。同步模式psync、异步模式io_uring
-sqthread_poll=1

-direct=1
//是否使用 direct io,测试过程不使用OS 自带的buffer,使测试磁盘的结果更真实 
//direct io,跳过缓存,直接读写SSD


-bs=4k  //IO 的块大小。默认 4k
-size=10G 
-numjobs=1//thread number
-runtime=120  告诉fio在指定的时间段后终止处理。
-group_reporting

测试结果:

  1. 32 io_uring iops: qps:80w 完全发挥NVMe特性
  2. fio的numjob,iodepth提高NVMe SSD的性能.
测试 方法2 测试您的 Ceph 集群

推荐的基准测试工具

代码语言:javascript代码运行次数:0运行复制
1. fio -ioengine=rbd -direct=1 -name=test -bs=4M -iodepth=16 -rw=write -pool=rpool_hdd -runtime=60 -rbdname=testimg
2. fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=1 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg
3. fio -ioengine=rbd -direct=1 -name=test -bs=4k -iodepth=128 -rw=randwrite -pool=rpool_hdd -runtime=60 -rbdname=testimg

测试方法1 绕过文件系统,读NVMe_ ssd进行fio的读盘操作 iops 10w-80w

针对测试CEPH集群的性能时,nvme ssd的读写iops总量不超过4w+ why?

方法1 和方法2为何差距这么大

首先的青铜猜想是:

  • 在 Ceph 在 HDD 上并不慢:
  • Bluestore 的理论单线程随机写入性能是驱动器 IOPS 的 66%(2/3),
  • Ceph 的线性读写速度并不慢
  • 当你用 SSD 替换 HDD 并使用快速网络时,Ceph 的速度应该会几乎一样快,天真了 ❎
  • Ceph 都很难实现低于 0.5 毫秒的随机读取延迟和低于 1 毫秒的随机写入延迟。[
  • 单线程下,这意味着随机读取 IOPS 和随机写入 IOPS 分别只有 2000 和 1000,即使能达到这个结果[0.5-1毫秒 一个请求,一个秒多少个?]
  • Ceph "软件栈"引入了额外的 I/O 打包、网络传输与协议层延迟,使得 OSD 在压力下无法压满 NVMe,
  • fio 只是本地落盘,时延极小,因此能将 SSD 压。

大师理解的猜想

image.png

Ceph OSD 多层软件栈开销

  • Ceph 默认在 BlueStore 层使用 RocksDB 存储元数据,写请求要先进入 WAL,再写入 MemTable,后台异步 Compaction 会带来 100–300 µs 级别的额外延迟
  • RADOS & PG 流程:每次写操作需要通过 RADOS 协议,将数据发送到 Primary OSD 并复制到 Secondary OSD 后才确认,网络 RTT 累加典型在 0.1–0.5 ms 范围,吞吐受限
  • TCP/IP vs RDMA:Ceph 原生使用 Kernel TCP/IP,产生 system CPU、iowait 和软中断开销;采用 RDMA(iWARP/RoCE)可减少复制延迟并降低 CPU 占用,使 4K 随机写 IOPS 提升 17%–
  • NUMA 与 CPU 亲和
4.2 事务特性 和延迟统计
  • BlueStore可以理解为一个支持ACID事物型的 本地日志文件系统。
  • 所有的读写都是以Transaction进行。
  • BlueStore通过状态机的方式控制整个IO流程。
  • queue_transactions接口 向 BlueStore 提交 事务组完成一系列写请
iBlueStore写状态机
新手视角

基本流程

  • 准备(Prepare):在内存中组装本次要执行的写入与元数据操作,事务尚未落盘。
  • 编码(Encode):将内存中的操作打包并转化为块设备可识别的 I/O 请求,包括预写日志(WAL)记录或直接写入命令。
  • 提交(Submit):通过同步或异步 I/O 接口,将事务操作写入底层存储设备。
  • 确认(Commit):等待 I/O 完成后,标记事务已持久化,确保断电或崩溃时数据不丢失。 [
  • 应用(Apply):把已提交的变更应用到内存中的索引或缓存,更新对象元数据 write transaction that Ceph will apply atomically 关注重点
  • 原子性与持久性:只要事务完成,用户无需关心具体底层细节;
大师视角
代码语言:javascript代码运行次数:0运行复制
const char *get_state_name() {
switch (state) {
case STATE_PREPARE: return"prepare"; 

//主要工作:
//该阶段主要是IO前的准备工作
//这个阶段会调用`_txc_add_transaction`将OSD层面的事物转换为BlueStore层面的事物

//延迟指标:
//l_bluestore_state_prepare_lat,从进入状态机到prepare阶段完成,

case STATE_AIO_WAIT: return"aio_wait";
//主要工作:
//该阶段等待aio的完成
//aio完成后在回调函数中将事务状态设置为STATE_IO_DONE

//延迟指标:
//l_bluestore_state_aio_wait_lat,从prepare阶段完成开始到AIO完成,
//平均延迟受限于设备,SSD 0.03ms左右。

case STATE_IO_DONE: return"io_done";

//主要工作:
//该阶段完对IO进行保序,保证kv事务的顺序性。
//按顺序设置事务状态为STATE_KV_QUEUED,将事务放入kv_queue

//通知kv_sync_thread进行,去同步IO和元数据
//kv_sync_thread 线程调用 db->submit_transaction 将批量更新写入 RocksDB
//IO保序可能会block。

//延迟指标:
//l_bluestore_state_io_done_lat,
//平均延迟在0.004ms,通常很小主要耗在对SimpleWrite的IO保序处理上。
//下个阶段:STATE_KV_QUEUED阶段


case STATE_KV_QUEUED: return"kv_queued";
//主要工作:
//1 该阶段主要deal kv_sync_thread线程中把aio的元数据写入kv数据库
//2 将状态设置为STATE_KV_SUBMITTED。
//3 然后将事务放入kv_committing_to_finalize队列,并通知_kv_finalize_thread线程处理

//延迟指标:
//l_bluestore_state_kv_queued_lat,
case STATE_KV_COMMITTING: return"kv_committing";

//主要工作:等待kv元数据和IO数据的Sync完成,回调finisher线程
//该阶段主要在 kv_finalize_thread线程中将状态设置为STATE_KV_DONE
//并将回调函数放入finisher队列,在finisher线程中给客户端返回应答

//延迟指标:
//l_bluestore_state_kv_done_lat

case STATE_KV_DONE: return"kv_done";

//主要工作
//如果没有延迟IO,则直接将状态设置为STATE_FINISHING;
//如果有延时IO,则将状态设置为STATE_DEFERRED_QUEUED

case STATE_WAL_QUEUED: return"wal_queued";

case STATE_WAL_APPLYING: return"wal_applying";

case STATE_WAL_AIO_WAIT: return"wal_aio_wait";

case STATE_WAL_CLEANUP: return"wal_cleanup";

case STATE_WAL_DONE: return"wal_done";

case STATE_FINISHING: return"finishing";

case STATE_DONE: return"done";

//延迟统计
enum {

 l_bluestore_state_prepare_lat,

 l_bluestore_state_aio_wait_lat,

 l_bluestore_state_io_done_lat,

 l_bluestore_state_kv_queued_lat,

 l_bluestore_state_kv_committing_lat,

 l_bluestore_state_kv_done_lat,

 l_bluestore_state_wal_queued_lat,

 l_bluestore_state_wal_applying_lat,

 l_bluestore_state_wal_aio_wait_lat,

 l_bluestore_state_wal_cleanup_lat,

 l_bluestore_state_finishing_lat,

}

技术点1:线程+队列
  • 线程+队列是BlueStore事物状态机的重要组成部分
  • aio_thread线程:属于KernelDevice模块的,主要作用写物理磁盘 。
  • kv_sync_thread:更新元数据k/v,这些必须按顺序操作。BlueStore::_kv_sync_thread
  • kv_finalize_thread:BlueStore::_kv_finalize_thread(),设置状态为STATE_KV_DONE
技术点2:保证IO的顺序性以及并发性
  • 因为BlueStore使用异步IO,后提交的IO可能比早提交的IO完成的早,所以更要保证IO的顺序

4.2 BlueStore IO流程

BlueStore IO流程

BlueStore IO流程

BlueStore IO流程:Simple Write
  • 对于simple write场景,先把数据写入新的block,然后把元数据写入k/v数据库中
  • 写新block状态转换:STATE_PREPARE -> STATE_AIO_WAIT -> STATE_IO_DONE -> STATE_KV_QUEUED
  • 元数据写k/v数据库状态转换:STATE_KV_QUEUED -> STATE_KV_SUBMITTED -> STATE_KV_DONE -> STATE_FINISHING -> STATE_DONE

在处理simple-write时, 需要考虑offset、length是否对齐到block_size(4KB)以进行补零对齐的操作。

BlueStore IO流程:Deferred Write

(.png)

  • 对于deferred write场景,延迟IO数据封装在k/v事务中,
  • 写入kv数据库后给客户端返回应答,然后在后台执行延迟IO数据的写操作。

写k/v日志:

STATE_PREPARE -> STATE_IO_DONE -> STATE_KV_QUEUED -> STATE_KV_SUBMITTED -> STATE_KV_DONE -> STATE_DEFERRED_QUEUE

写数据:

STATE_DEFERRED_QUEUE -> STATE_DEFERRED_CLEANUP -> STATE_FINISHING -> STATE_DONE

主要步骤:延迟写入的基本流程:
  1. 当写入请求到来时,BlueStore 首先将数据写入 KV 数据库(RocksDB),并立即返回成功给客户端
  2. 实际的数据写入被延迟到后台处理,主要涉及以下几个关键数据结构:
  • bluestore_deferred_op_t: 封装单个延迟写操作
  • bluestore_deferred_transaction_t: 包含多个延迟写操作的事务
  • DeferredBatch: 批量处理多个延迟写事务,将多个写操作合并处理
  • OpSequencer: 确保写操作按正确顺序执行

慢点集中在哪里?

  • ceph daemon osd.8 perf dump | egrep "wait|lat"

综合来看,RocksDB 同步提交(阶段4)AIO 等待(阶段2) 是占比最高的两部分, 共计可超过 80% 的

64K随机写入(QD=16场景)

  • 总延迟:2.268ms(其中Store层占比达93%)
    • state_aio_wait_lat:0.797ms(较QD=1增长14.7倍)
    • state_kv_queued_lat:0.544ms(元数据队列等待,增长107倍)
    • state_kv_commiting_lat:0.689ms(RocksDB提交耗时,增长9.5倍)
    • Store层细分
    • 瓶颈根源
    1. 单线程设计kv_sync_thread需串行处理元数据提交,导致高QD下队列堆积(如kv_queued_lat从0.005ms升至0.544ms
    2. 异步I/O竞争:Linux AIO的io_submit在高并发时需频繁上下文切换,占用CPU核心资源

小结(三步走)

  1. FIO压测 :即便在读客户端压力足够的情况下 软 件层不能给到下层足够的I/O压力,不能利用起NVME强大的硬件并发性能。工具:fio,iostat,vmstat,iotop
  2. 读请求各阶段耗时分析 降低延迟。工具:ceph daemon osd.10 perf dump/perf /gdbpmp,慢的原因在哪里能说清楚吗?性能优化:上千提升上万,过10万是不可能的?为什么
  3. 如何证明:Ceph "软件栈"引入了额外的 I/O 打包、网络传输与协议层延迟,使得 OSD 在压力下无法压满 NVMe。

参考

【1】 File Systems Unfit as Distributed Storage Backends: Lessons from 10 Years of Ceph Evolution
  • 文件系统作为分布式存储后端:从 Ceph 十年进化中汲 取的教训
  • .1145/3341301.3359656
【2】Ceph OSD Crimson: Next-generation Ceph OSD for Multi-core Scalabilit
  • /
  • ceph-osd-cpu-scaling
  • /
  • /
[5] io_uring: So Fast. It's Scary. - Paul Moore, Microsoft
  • IO uring gets Zero Copy network operations
  • 随着存储和网络设备性能越来越高,用户发现kernel那厚重的存储栈和网络栈效率越发低下,分分推出kernel bypass技术,但这类技术有一个通病,就是接口设计不统一,无法兼容,所以业界迫切期待内核推出一套成熟高效通用的异步编程框架,来缓解厚重模块带来的影响
  • io_uring只通过提供3个系统调用接口,就统一了网络和存储异步IO编程框架,使得上层开发人员无需过多关注其接口的可扩展性
  • 深入理解io_uring(一)设计初衷
  • 深入理解io_uring(二)设计原理
  • strace -c dd if=/dev/zero of=test bs=1M count=1000
  • 深入理解io_uring(七)零拷贝发送网络请求
  • 深入理解io_uring(三)一个完整请求
[6] Understanding BlueStore, Ceph's New Storage Backend - Tim Serong, SUSE
  • .php?mobileaction=toggle_view_desktop&title=Ceph_performance#Why_is_it_so_slow
  • 2018-May-29 :: Ceph Code Walkthrough: BlueStore part 1 [视频 ]
  • Ceph BlueStore的状态机
  • Block I/O Layer Tracing using blktrace
  • 你可以通过 iostat、blktrace 工具分析瓶颈是在应用层还是内核层、硬件层。其中 blktrace 是 blkio 层的磁盘 I/O 分析利器,它可记录 IO 进入通用块层、IO 请求生成插入请求队列、IO 请求分发到设备驱动、设备驱动处理完成这一系列操作的时间,帮助你发现磁盘 I/O 瓶颈发生的阶段
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-28,如有侵权请联系 cloudcommunity@tencent 删除存储测试事务数据文件系统

本文标签: 深入理解 BlueStore存储引擎,只需四步