BlueStore对象存储与元数据管理分析

BlueStore对象存储与元数据管理分析

1. 概述

BlueStore是Ceph的默认对象存储后端,采用了一种创新的存储架构:

  • 数据直接存储在块设备上:避免传统文件系统的开销
  • 元数据存储在RocksDB中:提供高性能的元数据管理
  • 分离式设计:数据路径和元数据路径完全分离

2. 对象存储架构

2.1 存储层次结构

BlueStore采用多层次的存储抽象,从逻辑对象到物理存储的映射关系如下:

1
2
3
4
5
6
7
8
9
Object (Onode)

Extent (逻辑extent)

Blob (数据块)

PExtent (物理extent)

Block Device (块设备)

2.1.1 Onode (Object Node)

定义位置: BlueStore.h:1328

Onode是对象的内存表示,包含:

  • 对象标识符 (ghobject_t oid): 唯一标识一个对象
  • 对象元数据 (bluestore_onode_t onode): 存储在RocksDB中的元数据
  • ExtentMap (extent_map): 逻辑extent到Blob的映射
  • BufferSpace (bc): 缓存的数据缓冲区
1
2
3
4
5
6
7
struct Onode {
Collection *c; // 所属集合
ghobject_t oid; // 对象ID
bluestore_onode_t onode; // 元数据
ExtentMap extent_map; // extent映射
BufferSpace bc; // 缓冲区空间
};

元数据存储

  • Onode的元数据存储在RocksDB中,键为 PREFIX_OBJ + key
  • 包含对象大小、修改时间、扩展属性等信息

2.1.2 Extent (逻辑Extent)

定义位置: BlueStore.h:829

Extent将对象的逻辑偏移映射到Blob:

1
2
3
4
5
6
struct Extent {
uint32_t logical_offset; // 对象内的逻辑偏移
uint32_t blob_offset; // Blob内的偏移
uint32_t length; // 长度
BlobRef blob; // 指向的Blob
};

特点

  • Extent按logical_offset排序,存储在boost::intrusive::set
  • 一个对象可以有多个Extent,支持稀疏对象
  • Extent可以跨越多个Blob(通过spanning blob机制)

2.1.3 Blob (数据块)

定义位置: BlueStore.h:651bluestore_types.h:498

Blob是数据的逻辑容器,包含:

1
2
3
4
5
struct Blob {
bluestore_blob_t blob; // Blob元数据
bluestore_blob_use_tracker_t used_in_blob; // 引用计数跟踪
SharedBlobRef shared_blob; // 共享Blob引用(如果共享)
};

Blob元数据 (bluestore_blob_t):

1
2
3
4
5
6
7
8
struct bluestore_blob_t {
PExtentVector extents; // 物理extent列表
uint32_t logical_length; // 逻辑长度(压缩前)
uint32_t compressed_length; // 压缩后长度
uint32_t flags; // 标志位(压缩、校验和等)
uint8_t csum_type; // 校验和类型
buffer::ptr csum_data; // 校验和数据
};

Blob特性

  • 压缩支持: 可以存储压缩数据,通过FLAG_COMPRESSED标志
  • 校验和: 支持数据完整性校验,通过FLAG_CSUM标志
  • 共享Blob: 多个对象可以共享同一个Blob(写时复制)
  • 引用计数: 通过bluestore_blob_use_tracker_t跟踪使用情况

2.1.4 PExtent (物理Extent)

定义位置: bluestore_types.h:98

PExtent表示块设备上的实际物理位置:

1
2
3
4
struct bluestore_pextent_t {
uint64_t offset; // 块设备上的偏移
uint32_t length; // 长度
};

特点

  • 一个Blob可以包含多个PExtent(支持不连续存储)
  • PExtent由Allocator分配和管理
  • 支持对齐到块大小边界

2.2 数据写入流程

2.2.1 写入路径

  1. 接收写入请求

    • 客户端请求写入对象数据
    • BlueStore创建或获取Onode
  2. 分配空间

    • 通过Allocator分配物理空间(PExtent)
    • 创建或扩展Blob来容纳数据
  3. 数据准备

    • 可选:压缩数据(如果启用)
    • 可选:计算校验和
    • 准备写入缓冲区
  4. 写入块设备

    • 直接写入到块设备(绕过文件系统)
    • 使用异步I/O提高性能
  5. 更新元数据

    • 创建或更新Extent映射
    • 更新Blob元数据
    • 更新Onode元数据
  6. 提交事务

    • 将元数据变更写入RocksDB事务
    • 提交事务,确保一致性

2.2.2 关键代码路径

写入入口: BlueStore::_do_write()

  • 创建WriteContext管理写入操作
  • 调用Writer::do_write()执行实际写入

Writer类: Writer.hWriter.cc

  • 管理写入的数据块(blob_data_t)
  • 处理压缩、对齐等操作
  • 协调空间分配和数据写入

2.3 数据读取流程

  1. 查找Onode

    • 从RocksDB读取对象元数据
    • 加载到内存缓存
  2. 解析ExtentMap

    • 根据逻辑偏移查找对应的Extent
    • 确定需要读取的Blob和偏移
  3. 读取数据

    • 从块设备读取物理数据
    • 可选:验证校验和
    • 可选:解压缩数据
  4. 返回数据

    • 将数据返回给客户端
    • 可能缓存到BufferSpace中

3. 元数据管理

3.1 元数据存储架构

BlueStore使用RocksDB作为元数据存储引擎:

1
KeyValueDB *db = nullptr;  // RocksDB实例

3.1.1 元数据类型

1. 对象元数据 (Onode)

  • 键格式: PREFIX_OBJ + key
  • 值内容: 序列化的bluestore_onode_t
  • 包含信息:
    • 对象大小
    • 修改时间
    • 扩展属性
    • ExtentMap的编码(如果较小则内联)

2. Blob元数据

  • 存储位置: 内联在Onode中(小对象)或单独存储(大对象)
  • SharedBlob: 共享Blob的元数据单独存储
    • 键格式: PREFIX_SHARED_BLOB + sbid
    • 包含引用计数、物理extent等信息

3. 集合元数据 (Collection)

  • 键格式: PREFIX_COLL + cid
  • 值内容: 集合的元数据(如bits等)

4. OMap数据

  • 键格式: omap_prefix + onode_key + user_key
  • 值内容: 用户定义的键值对

3.2 元数据组织

3.2.1 ExtentMap编码

ExtentMap可以以两种方式存储:

1. 内联存储 (小对象)

  • ExtentMap直接编码在Onode中
  • 适合extent数量少的对象

2. 分片存储 (大对象)

  • ExtentMap分成多个shard
  • 每个shard独立编码和存储
  • 支持按需加载,减少内存占用

编码格式:

1
2
3
4
5
// Extent编码包含:
// - logical_offset (逻辑偏移)
// - blob_offset (Blob偏移)
// - length (长度)
// - blob_id (Blob ID或SharedBlob ID)

3.2.2 SharedBlob管理

目的: 支持写时复制(Copy-on-Write),多个对象可以共享数据

结构:

1
2
3
4
5
struct SharedBlob {
uint64_t sbid; // SharedBlob ID
bluestore_extent_ref_map_t ref_map; // 引用计数映射
bluestore_blob_t blob; // Blob元数据
};

引用计数:

  • 使用bluestore_extent_ref_map_t跟踪每个extent的引用数
  • 当引用计数为0时,可以释放物理空间

3.3 事务管理

3.3.1 TransContext

定义位置: BlueStore.h:276

每个事务由TransContext管理:

1
2
3
4
struct TransContext {
KeyValueDB::Transaction t; // RocksDB事务
// ... 其他事务相关数据
};

3.3.2 事务流程

  1. 开始事务

    • 创建TransContext
    • 创建RocksDB事务
  2. 记录变更

    • 修改Onode元数据
    • 更新ExtentMap
    • 记录Blob变更
  3. 提交事务

    • 将元数据变更写入RocksDB
    • 确保原子性
  4. 同步

    • 可选:同步RocksDB(fsync)
    • 确保数据持久化

3.4 缓存管理

3.4.1 Onode缓存

结构: OnodeCacheShard

  • 缓存Onode对象
  • 使用LRU策略管理
  • 支持分片(sharding)提高并发性

3.4.2 Buffer缓存

结构: BufferCacheShard

  • 缓存对象数据缓冲区
  • 管理Buffer对象的状态(EMPTY/CLEAN/WRITING)
  • 支持延迟写入(deferred write)

3.4.3 缓存策略

  • LRU: 最近最少使用
  • TwoQ: 两级队列(热数据和冷数据)
  • 优先级缓存: 根据访问模式调整优先级

4. 空间管理

4.1 Allocator (分配器)

BlueStore使用Allocator管理块设备上的空闲空间:

支持的分配器类型:

  • StupidAllocator: 简单的interval_set实现
  • BitmapAllocator: 基于位图的分配器
  • AvlAllocator: 基于AVL树的分配器
  • BtreeAllocator: 基于B树的分配器
  • Btree2Allocator: B树分配器的改进版
  • HybridAllocator: 混合分配器(主分配器+位图分配器)

分配流程:

  1. 根据请求大小和提示(hint)选择分配策略
  2. 从空闲空间中找到合适的extent
  3. 返回分配的PExtent列表

4.2 FreelistManager (空闲列表管理器)

作用: 持久化空闲空间信息到RocksDB

实现: BitmapFreelistManager

  • 使用位图跟踪空闲块
  • 支持合并操作符(XOR)进行增量更新
  • 在RocksDB中持久化空闲空间状态

5. 高级特性

5.1 压缩

支持: 通过Compression.hCompression.cc实现

压缩流程:

  1. Estimator: 估算压缩收益
  2. Scanner: 扫描可压缩的数据
  3. 压缩执行: 使用配置的压缩算法
  4. 元数据更新: 更新Blob的压缩标志和长度

压缩标志: bluestore_blob_t::FLAG_COMPRESSED

5.2 校验和

支持: 通过Checksummer实现

校验和类型:

  • CRC32C
  • XXHASH32
  • XXHASH64

存储: 校验和数据存储在bluestore_blob_t::csum_data

5.3 共享Blob (写时复制)

场景:

  • 对象克隆
  • 快照
  • 去重

机制:

  • 多个对象共享同一个Blob
  • 写入时创建新的Blob(写时复制)
  • 通过引用计数管理生命周期

6. 性能优化

6.1 延迟写入 (Deferred Write)

目的: 合并小写入,提高性能

机制:

  • 小写入先缓存到DeferredBatch
  • 延迟到合适时机批量写入
  • 减少I/O次数

6.2 对齐优化

块对齐:

  • 数据对齐到块大小边界
  • 提高I/O效率

分配对齐:

  • 根据分配单元对齐
  • 减少碎片

6.3 缓存优化

多级缓存:

  • Onode缓存(元数据)
  • Buffer缓存(数据)
  • 块设备缓存(操作系统级)

缓存策略:

  • 根据访问模式调整
  • 支持预热和预取

7. 数据一致性

7.1 事务保证

  • 原子性: 通过RocksDB事务保证
  • 持久性: 通过fsync保证
  • 一致性: 通过写前日志(WAL)保证

7.2 崩溃恢复

  • RocksDB恢复: 自动恢复未提交的事务
  • 空间一致性: 通过FreelistManager重建空闲空间
  • 元数据校验: 启动时验证元数据完整性

8. 总结

BlueStore的存储架构具有以下特点:

  1. 分离式设计: 数据和元数据分离存储,各自优化
  2. 直接I/O: 数据直接写入块设备,避免文件系统开销
  3. 灵活映射: 多层次的映射关系,支持稀疏对象和共享数据
  4. 高性能: 通过缓存、延迟写入、对齐等优化提高性能
  5. 可扩展: 支持压缩、校验和、共享Blob等高级特性

这种设计使得BlueStore能够提供高性能、高可靠性的对象存储服务,特别适合大规模分布式存储场景。

9. 关键数据结构关系图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
┌─────────────────┐
│ Object (Onode)│
│ - oid │
│ - onode (meta) │
│ - extent_map │
│ - buffer_space │
└────────┬────────┘

│ contains

┌─────────────────┐
│ Extent │
│ - logical_off │
│ - blob_offset │
│ - length │
│ - blob_ref │
└────────┬────────┘

│ references

┌─────────────────┐
│ Blob │
│ - blob (meta) │
│ - use_tracker │
│ - shared_blob │
└────────┬────────┘

│ contains

┌─────────────────┐
│ PExtent │
│ - offset │
│ - length │
└────────┬────────┘

│ maps to

┌─────────────────┐
│ Block Device │
└─────────────────┘

Metadata Storage (RocksDB):
┌─────────────────┐
│ Onode Metadata │───┐
│ (PREFIX_OBJ) │ │
└─────────────────┘ │

┌─────────────────┐ │
│ SharedBlob Meta │ │
│ (PREFIX_SHARED) │ │
└─────────────────┘ │

┌─────────────────┐ │
│ Collection Meta │ │
│ (PREFIX_COLL) │ │
└─────────────────┘ │

┌─────────────────┐ │
│ OMap Data │ │
│ (omap_prefix) │ │
└─────────────────┘ │


┌─────────────────┐
│ RocksDB │
└─────────────────┘

10. 参考代码位置

  • 核心类定义: cephMain/src/os/bluestore/BlueStore.h
  • 核心实现: cephMain/src/os/bluestore/BlueStore.cc
  • 类型定义: cephMain/src/os/bluestore/bluestore_types.h
  • 写入器: cephMain/src/os/bluestore/Writer.h/cc
  • 压缩: cephMain/src/os/bluestore/Compression.h/cc
  • 分配器: cephMain/src/os/bluestore/Allocator*.h/cc
  • 空闲列表: cephMain/src/os/bluestore/FreelistManager.h/cc

文章互动

阅读 --

留言

0 条留言

正在加载留言…