谈谈BlueFS

目录

    • 前言
    • 数据结构
      • 标识一个文件
      • 文件系统的全局记录
      • 事务记录
      • 超级块
    • 启动流程
    • 磁盘管理
    • 读写流程
      • 创建文件流程
      • 为文件写数据
      • 把数据下刷到磁盘
      • 读流程
    • 参考资料

前言

BlueFS具体是个什么东西呢?
在这里插入图片描述
如上图,在Ceph里,使用BlueStore作为默认的存储引擎。
作为存储引擎,它说白了就是存储文件的,但是一般情况下,文件分为原始数据与元数据。如上图,对于原始数据,BlueStore是直接操作裸盘进行存储的;对于元数据则使用RocksDB来进行保存。
单独看RocksDB,它是一个kv存储引擎,它里面存储的数据是需要进行持久化的,理论上来说吧Rocksdb的数据也直接写到裸盘上就行,但是实际上,Rocksdb本身不能直接操作裸盘,它需要一个文件系统来作为自己和裸盘的中间层,来提供文件的读写服务。
而咱们得BlueFS就是上面提到的中间层,向下把数据通过Allocator写到磁盘上,向上通过BlueRocksENV为Rocksdb提供文件的存储与读取。
至此,咱们对BlueFC就可以下一个定义了:BlueFC是一个专门为RocksDB提供文件读写支持的文件系统。
去掉各种定语,BlueFC就是一个文件系统

数据结构

咱们从下往上讲:

标识一个文件

// 物理磁盘的位移和长度,代表块设备的一个存储区域
class AllocExtent {public:uint64_t offset; // BlockDevice的物理地址uint32_t length; // 长度
};class bluefs_extent_t : public AllocExtent{public:// 属于哪个block device// block device 包括以下几种:/*static constexpr unsigned BDEV_WAL = 0;static constexpr unsigned BDEV_DB = 1;static constexpr unsigned BDEV_SLOW = 2;static constexpr unsigned BDEV_NEWWAL = 3;static constexpr unsigned BDEV_NEWDB = 4;*/uint8_t bdev; 
};// 文件的inode
truct bluefs_fnode_t {uint64_t ino; // inode编号uint64_t size; // 文件大小utime_t mtime; // 修改时间uint8_t prefer_bdev; // 优先使用哪个block device// 注意这是一个vector! 一块数据在磁盘上,可能因为碎片的问题// 分布在多个并不相连的区域上mempool::bluefs::vector<bluefs_extent_t> extents; // 文件对应的磁盘空间uint64_t allocated; // 文件实际占用的空间大小,extents的length之和。应该是小于等于size
};

文件系统的全局记录

上面的代码说明了一个文件在BlueFC里面的标识,那具体作为一个文件系统,还得知道他自己管理的系统下,都有哪些文件,哪些文件夹嘛,这部分代码如下:

class BlueFS {public:// 文件系统支持不同种类的块设备static constexpr unsigned MAX_BDEV = 3;static constexpr unsigned BDEV_WAL = 0;static constexpr unsigned BDEV_DB = 1;static constexpr unsigned BDEV_SLOW = 2;enum {WRITER_UNKNOWN,WRITER_WAL, // RocksDB的log文件WRITER_SST, // RocksDB的sst文件};// 文件struct File : public RefCountedObject {bluefs_fnode_t fnode; // 文件inodeint refs; // 引用计数uint64_t dirty_seq; // dirty序列号bool locked;bool deleted;boost::intrusive::list_member_hook<> dirty_item;// 读写计数std::atomic_int num_readers, num_writers;std::atomic_int num_reading;};// 目录struct Dir : public RefCountedObject {mempool::bluefs::map<string,FileRef> file_map; // 目录包含的文件};// 文件系统的内存映像// dir_map的可以就是文件夹路径 DirRef里面放着一个file_mapmempool::bluefs::map<string, DirRef> dir_map; // 所有的目录// file_map 的key就是文件的fnodemempool::bluefs::unordered_map<uint64_t,FileRef> file_map; // 所有的文件map<uint64_t, dirty_file_list_t> dirty_files; // 脏文件,根据序列号排列// 文件系统超级块和日志......// 结构体FileWriter/FileReader/FileLock,用来对一个文件进行读写和加锁......vector<BlockDevice*> bdev; // BlueFS能够使用的所有BlockDevice,包括wal/db/slowvector<IOContext*> ioc; // bdev对应的IOContextvector<interval_set<uint64_t> > block_all;  // bdev对应的磁盘空间vector<Allocator*> alloc; // bdev对应的allocator......
};

事务记录

这里关于数据结构还需要一个逻辑,就是假定一个空的文件系统启动了,然后新建了3个目录,再加了5个文件。然后系统断电关闭了。那启动的时候,那之前新建的目录和文件去哪里找呢?
BlueFC针对上面的问题,使用了WAL的方式来解决。具体来说,就是把用户的每次操作都记录成日志写到磁盘上,然后每次系统启动的时候,就读一下那文件,就知道系统之前都有哪些文件了。
那具体的操作记录是什么样子的呢?

struct bluefs_transaction_t {typedef enum {OP_NONE = 0,OP_INIT,        ///< initial (empty) file system marker// 给文件分配和释放空间OP_ALLOC_ADD,   ///< add extent to available block storage (extent)OP_ALLOC_RM,    ///< remove extent from availabe block storage (extent)// 创建和删除目录项OP_DIR_LINK,    ///< (re)set a dir entry (dirname, filename, ino)OP_DIR_UNLINK,  ///< remove a dir entry (dirname, filename)// 创建和删除目录OP_DIR_CREATE,  ///< create a dir (dirname)OP_DIR_REMOVE,  ///< remove a dir (dirname)// 文件更新OP_FILE_UPDATE, ///< set/update file metadata (file)OP_FILE_REMOVE, ///< remove file (ino)// bluefs日志文件的compaction操作OP_JUMP,        ///< jump the seq # and offsetOP_JUMP_SEQ,    ///< jump the seq #} op_t;uuid_d uuid;          ///< fs uuiduint64_t seq;         ///< sequence numberbufferlist op_bl;     ///< encoded transaction ops
};

对了有一个问题,需要说明大家想想,如果我把所有的操作记录一直保存着,那不管系统多大,都放不下这么多日志。那怎么办呢?假定对一个文件,首先创建,然后多次append,最终删除了。最开始肯定是有多个操作记录的,那请问文件最终都已经删除了,还保留那么多操作有意义么?
答案是肯定的,保留已经删除的问题的操作记录是没有意义的。所有每当操作记录的体积大于某个阈值,系统就会进行操作记录的合并。所谓合并就是删除哪些不需要的操作记录。那什么是不需要的操作n呢,上面说的已经删除的文件之前的操作记录就是不需要保留的操作。

超级块

再往前追一步,系统重启了,磁盘的什么地方存放上面的操作日志呢?
如果熟悉文件系统的小伙伴应该知道,就是超级块。他固定就存放在BlueFC接管的第二个4K块里。其结构如下:

struct bluefs_super_t {uuid_d uuid; // 唯一的uuiduuid_d osd_uuid; // 对应的osd的uuiduint64_t version; // 版本uint32_t block_size; // 块大小bluefs_fnode_t log_fnode; // 记录文件系统日志的文件
};

看完之后,咱们就可以看一下整个文件系统的静态数据结构图了:
在这里插入图片描述
journal就是我们的操作流水的记录。

启动流程

刚才已经提到超级块了,那大家就算猜也能猜出来,那这个BlueStore启动到BlueFS的时候,第一步就是去读那个超级块,然后读之前用户的操作记录流水,一步步恢复全局的dir_map和file_map。
代码基本的大致调用流程是:

BlueStore::mkfs()->
BlueStore::_open_db->
BlueFS::mount()

BlueFS::mount()的具体代码如下:

int BlueFS::mount()
{// 读取超级块int r = _open_super();......// 初始化allocator为磁盘所有的空间_init_alloc();......// 回放文件系统日志,日志项即为上面的事务OP,针对每个事务进行回放,文件系统的dir_map/file_map就会被更新r = _replay(false);for (auto& p : file_map) {for (auto& q : p.second->fnode.extents) {alloc[q.bdev]->init_rm_free(q.offset, q.length); // 将文件已经占用的内容从allocator中删除}}......
}

上面的get_super_offset 和get_super_length 代码如下:
看 写死了,都是4K

  // always put the super in the second 4k block.  FIXME should this be// block size independent?unsigned get_super_offset() {return 4096;}unsigned get_super_length() {return 4096;}

磁盘管理

文件系统对外的功能就是文件的读写与删除。但是从内部讲,来了一段数据,系统把它应该放在磁盘的哪个位置呢?这部分逻辑说白了就是文件系统的磁盘管理功能。
从逻辑上来说,BlueStore的磁盘管理使用的是位图法。

所谓位图法,就是借助一系列的比特流来表示磁盘上一个块的占据情况,例如0表示空闲,1表示已经被占用。

从实现上来说:

空闲空间列表用BitmapFreeListManager来管理
已分配空间列表用BitmapAllocator来管理

磁盘管理这块的内容比较细碎,这就不过多涉及了,大家可以参考:
https://zhuanlan.zhihu.com/p/643938193

读写流程

创建文件流程

本次分析的BlueFS的源码来自Ceph 17.2.5。
我们知道BlueFS虽然是一个文件系统,但是他的用户很单一,就只有一个RocksDB。所以写流程的起点就在Rocksdb里面。
具体调用链如下:

BlueRocksEnv::NewWritableFile
BlueFS::open_for_write

我尽量不直接贴代码,就用语言描述这个流程吧。
首先看,头文件的描述,英文写的很简单,我就不翻译了。

  // Create an object that writes to a new file with the specified// name.  Deletes any existing file with the same name and creates a// new file.  On success, stores a pointer to the new file in// *result and returns OK.  On failure, stores nullptr in *result and// returns non-OK.//// The returned file will only be accessed by one thread at a time.rocksdb::Status NewWritableFile(const std::string& fname,std::unique_ptr<rocksdb::WritableFile>* result,const rocksdb::EnvOptions& options) override;

NewWritableFile里面本身很薄,就是把fname分割成目录名和文件名,再就是把open_for_write的返回结果包装成BlueRocksWritableFile。
open_for_write里面
1 判断目录和文件是否存在,然后更新file_map
2 在操作流水里记录一个OP_DIR_LINK
3 创建文件句柄

为文件写数据

其实只是把数据写到了缓存

BlueRocksWritableFile::Append->
BlueFS::append_try_flush->
FileWriter::append->
ceph::buffer::list::page_aligned_appender::append
再强调一点,BlueFS的使用者是Rocksdb。所以append的最开始也是来源于rocksdb的append。

把数据下刷到磁盘

BlueRocksWritableFile::Sync->
BlueFS::fsync->
BlueFS::_flush_F->
BlueFS::_flush_range_F->
BlueFS::_flush_data->
KernelDevice::write

特殊的在上面的_flush_range_F里面如果发现为文件分配的大家不够了,那就需要找Allocate重新从磁盘上申请空间。

读流程

由于BlueFS的元数据都在内存中,所以读流程很简单,从内存中获取请求数据的物理位置和物理设备进行读取即可,不存在读放大。
代码流程如下:

BlueRocksRandomAccessFile::Read->
BlueFS::read_random->
BlueFS::_read_random
BlueFS::_bdev_read_random
KernelDevice::read_random

参考资料

https://blog.wjin.org/posts/ceph-bluestore-bluefs.html
https://blog.csdn.net/u014104588/article/details/87886764
https://zhuanlan.zhihu.com/p/46362124
https://zhuanlan.zhihu.com/p/643938193

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/662605.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day06-Linux下目录命令讲解及重要文件讲解

Day06-Linux下目录命令讲解及重要文件讲解 1. Linux目录文件1.1 Linux系统目录结构介绍1.1.1 Linux与Windows目录结构对比 1.2 重要的Linux配置文件介绍1.2.1 /etc系统初始化及设置相关重要文件1.2.2 /usr目录的重要知识介绍------应用程序目录1.2.3 /var目录下的路径知识-----…

Shell中正则表达式与sed编辑器

目录 一、正则表达式 1.1.正则表达式介绍 1.2.正则表达式分类 1.3.元字符 1.4.扩展正则表达式元字符 二、sed编辑器 2.1.sed编辑器是什么 2.2.sed编辑器的工作流程 2.3.sed命令格式 一、正则表达式 1.1.正则表达式介绍 1、正则表达式---通常用于判断语句中&#xff0…

Redis单机-主从集群-哨兵集群-分片集群 搭建教程

Redis集群 本章是基于CentOS7下的Redis集群教程&#xff0c;包括&#xff1a; 单机安装RedisRedis主从Redis分片集群 1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tclredis-6.2.4.tar.gz 然后将Redis安装包上传到虚拟机的任意目录&am…

Vue3 vant4 解决引入的Toast和dialog样式丢失的bug

情景再现&#xff1a; 正确做法&#xff1a; 在main.ts中单独引入 import vant/es/toast/style import vant/es/dialog/style import { Toast, Dialog } from vantapp.use(Toast) app.use(Dialog)效果如下 轻松拿下。

故障诊断 | 一文解决,CNN-SVM卷积神经网络-支持向量机组合模型的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,CNN-SVM卷积神经网络-支持向量机组合模型的故障诊断(Matlab) 模型描述 卷积神经网络(Convolutional Neural Network,CNN)和支持向量机(Support Vector Machine,SVM)是两种常用的机器学习算法,它们在不同领域和任务中都表现出…

2023_12蓝桥杯STEMA 考试 Scratch 中级试卷解析

2023蓝桥杯STEMA 考试 Scratch 中级试卷(12 月)解析 由于没有原始文件,这里使用的角色和背景和实际题目会有所差异,已经尽量还原原题,以下代码仅供参考。吐槽一句:蓝桥杯越来越变态了!\(`Δ’)/\(`Δ’)/\(`Δ’)/孩子学习速度永远也赶不上内卷的速度。 一、选择…

重写Sylar基于协程的服务器(3、协程模块的设计)

重写Sylar基于协程的服务器&#xff08;3、协程模块的设计&#xff09; 重写Sylar基于协程的服务器系列&#xff1a; 重写Sylar基于协程的服务器&#xff08;0、搭建开发环境以及项目框架 || 下载编译简化版Sylar&#xff09; 重写Sylar基于协程的服务器&#xff08;1、日志模…

“IT行业的黄金证书:你必须了解的顶级认证“

文章目录 每日一句正能量前言一、网络方向&#xff1a;思科认证/软考二、华为认证三、系统方向&#xff1a;红帽认证四、数据库方向&#xff1a;Oracle认证五、信息安全方向&#xff1a;CISP/CISSP认证六、管理方向&#xff1a;PMP认证IT行业证书的价值和作用后记 每日一句正能…

树——二叉搜索树

二叉搜索树 概述 随着计算机算力的提升和对数据结构的深入研究&#xff0c;二叉搜索树也不断被优化和扩展&#xff0c;例如AVL树、红黑树等。 特性 二叉搜索树&#xff08;也称二叉排序树&#xff09;是符合下面特征的二叉树&#xff1a; 树节点增加 key 属性&#xff0c;用来…

手游反抓帧解决方案

随着游戏用户规模趋于稳定&#xff0c;游戏行业已迈入存量市场阶段&#xff0c;厂商之间的竞争愈发激烈&#xff0c;研发成本也随之激增。据数据统计&#xff1a;游戏研发成本占收入比约在 15%-35%&#xff0c;而研发成本中&#xff0c;美术资源投入占比达到了50-70%。 游戏厂商…

Java进击框架:Spring-综合(十)

Java进击框架&#xff1a;Spring-综合&#xff08;十&#xff09; 前言Rest ClientsWebClientRestTemplateHTTP接口 JMS (Java消息服务)使用Spring JMS发送消息接收消息注释驱动的侦听器端点 JMXEmail任务执行和调度Spring TaskExecutor 抽象Spring TaskScheduler 抽象支持调度…

C++算法学习心得七.贪心算法(3)

1.根据身高重建队列&#xff08;406题&#xff09; 题目描述&#xff1a; 假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 …

微服务入门篇:Ribbon负载均衡(原理,均衡策略,饥饿加载)

目录 1.负载均衡原理2.负载均衡策略3.饥饿加载 1.负载均衡原理 在使用 LoadBalanced 注解后&#xff0c;Spring Cloud Ribbon 将会为 RestTemplate 添加负载均衡的能力。 负载均衡的流程如下&#xff1a; 当使用 RestTemplate 发送请求时&#xff0c;会先判断请求的 URL 是否包…

双目相机立体匹配基础

双目匹配就是用左相机和右相机去拍摄同一个点&#xff0c;目的是找到三维世界的同一个点&#xff0c;也就是在左相机和右相机中的成像点之间的像素差&#xff08;视差&#xff09;&#xff0c;根据视差去求解深度&#xff0c;那么找到左相机点到右相机的同一个对应点这个过程就…

c++设计模式之观察者模式(发布-订阅模式)

介绍 观察者模式主要关注于对象的一对多关系&#xff0c;其中多个对象都依赖于一个对象&#xff0c;当该对象的状态发生改变时&#xff0c;其余对象都能接收到相应的通知。 如&#xff0c;现在有 一个数据对象三个画图对象&#xff0c;分别wield曲线图、柱状图、饼状图三个对象…

数据结构与算法面试系列-03

1. 一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高? 程序代码 package com.jingxuan.system;public class Sphere {public static void main(String[] args) {double s = 0;double t = 100;for (int i…

Qt6入门教程 15:QRadioButton

目录 一.简介 二.常用接口 三.实战演练 1.径向渐变 2.QSS贴图 3.开关效果 4.非互斥 一.简介 QRadioButton控件提供了一个带有文本标签的单选按钮。 QRadioButton是一个可以切换选中&#xff08;checked&#xff09;或未选中&#xff08;unchecked&#xff09;状态的选项…

Flink 1.18.1的基本使用

系统示例应用 /usr/local/flink-1.18.1/bin/flink run /usr/local/flies/streaming/SocketWindowWordCount.jar --port 9010nc -l 9010 asd asd sdfsf sdf sdfsdagd sdf单次统计示例工程 cd C:\Dev\IdeaProjectsmvn archetype:generate -DarchetypeGroupIdorg.apache.flink -…

maven代码规范检查(checkstyle、findbugs)

maven代码规范检查 前言一、使用checkstyle插件1. maven-checkstyle-plugin 介绍2. 接入方式3. 如何排除某个类、包下面的文件不进行检查使用suppressionsLocation 4. 如何关闭 二、使用findbugs插件1.findbugs-maven-plugin介绍2. 接入方式3. 如何排除某个类、包下面的文件不进…

TraceRoute 跟踪路由工具

随着企业网络需求的不断增长&#xff0c;组织发现监控和管理其网络基础设施变得越来越困难&#xff0c;网络管理员正在转向其他工具和资源&#xff0c;这些工具和资源可以使他们的工作更轻松一些&#xff0c;尤其是在故障排除方面。 目前&#xff0c;网络管理员主要使用简单、…