C++项目实战:SPDK文件系统

news2024/10/7 18:25:56

目录

  • 一、Blobstore设计框架
  • 二、Cache机制
  • 三、Blob FS I/O操作
  • 四、SPDK FUSE (Filesystem in Userspcae)

前言

Blob FS是spdk面向于用户态的轻量级的文件系统

SPDK通过绕过内核(kernel bypass)的方案,构筑了用户态驱动,并利用异步轮询、无锁机制等,极大地提升了I/O性能。然而,正因为采用了kernel bypass的设计,使得原本内核中的文件系统不能使用。因此,SPDK提供了Blobstore用来支持上层存储服务,并基于此封装了Blob FS(Blob Filesystem)文件系统。

一、Blobstore设计框架

Blob FS被设计为面向Blobstore的轻量级文件系统,它提供给用户基本的文件操作: read、write、open、delete等。在介绍Blob FS的框架之前,首先介绍两个概念spdk_io_device和spdk_io_channel,在SPDK的早期设计中,spdk_io_device被设计为存储设备的抽象,并将特定线程的队列抽象为spdk_io_channel。这样的好处是为了避免竞争以及其带来的全局锁定,在SPDK线程模型中,每个spdk_thread通过各自的spdk_io_channel对spdk_io_device进行访问,这样不同的spdk_thread被隔离。这种类似的设计被推广,spdk_io_device被抽象成任何地址,不仅仅是底层存储设备的映射,也包含了对线程资源的逻辑管理结构。spdk_io_channel也随之被抽象成与spdk_io_device相关联的线程上下文,通过spdk_get_io_channel()函数,可以很方便的获取某个spdk_io_device上对应的channel。在SPDK中,所有的spdk_io_device会通过RB_TREE来维护,这有利于查找。

Blob FS在工作状态下会注册两个spdk_io_device,分别是blobfs_md以及blobfs_sync,前者带有md后缀,在Blob FS框架下,这被设计为与元数据(metadata)的操作有关,例如create,后者则是与I/O(read & write)操作有关。两个spdk_io_device绑定在一个reactor 0上,相当于对外提供了两个交互通道。根据前文所述,不同的spdk_thread没有办法共用一个spdk_channel,这就保证了只有reactor 0才能Blob FS进行交互,有效避免了多线程之间的竞争以及同步问题,例如对元数据的操作只能经由reactor 0实现,其他用户线程或者绑定在其他线程中的reactor对元数据的操作均需要通过SPDK中的消息机制来实现,交由reactor 0来进行处理,这种设计与SPDK的run-to-completion理念相符,所以工作流程可总结如下图所示。

二、Cache机制

为了加速文件的I/O性能,Blob FS提供了一套cache机制。DPDK提供的大页管理是SPDK实现零拷贝机制的基础,实际上这也是Blob FS中cache机制的基础。借助DPDK内存池对大页的管理,一次性申请到了一块较大的缓冲区mempool,该区域除了头部以外主要由固定大小的内存单元组成,并构成了ring队列,可方便的用于存取数据。

针对内存池对大页的管理,DPDK用到的接口主要有三个,SPDK对其进行了封装:

在Blob FS中,固定大小的内存单元其大小被设置为CACHE_BUFFER_SIZE,该值体现了cache机制中基本的存储单元,内存单元的数量可以采用默认值也可以通过Blob FS预留的接口进行重新设置。为了方便管理整个cache机制中的内存,Blob FS创建了一个新的spdk_thread线程g_cache_pool_thread。它主要维护了g_caches和g_cache_pool两个数据结构,前者维护了所有拥有cache的文件列表,后者则指向了前文提到的借助DPDK大页管理所申请到的内存池。与此同时,在该线程上还注册了一个poller函数用于监测内存池的使用情况,当内存池中空闲内存单元数量下降到20%以下时,会对已缓存的内存池对象进行清理释放,将内存单元返还给内存池,并且会优先释放低优先级的文件缓存,用户程序可根据需要调整缓存文件的优先级。

Blob FS对文件的管理依赖了spdk_file数据结构,在spdk_file中利用了cache_tree数据结构来对该文件的cache进行管理。cache tree由多层树状节点构成,维护了两种数据节点: tree node和buffer node,其中tree node充当了索引的作用,他可以根据根节点以及对应的offset,自上而下查找对应的buffer node;buffer node是实际缓存文件数据的节点,他位于整个cache tree的最底层,buffer node中用于缓存文件数据的空间实际上就是前文中提到的借助内存池申请到的一个个内存单元,因此单个buffer node中所能缓存文件数据的大小也就是CACHE_BUFFER_SIZE,在默认情况下,该值为256KB。

三、Blob FS I/O操作

尽管Blob FS中提供了同步和异步两种I/O操作,但当前集成并使用的是同步读。

1. spdk_file_read

首先,Blob FS会依据本次读取数据的大小进行判断,当读取数据大于CACHE_READAHEAD_THRESHOLD(默认情况下,该值为128KB)时,触发异步预读(readahead)操作,提前将一部分数据读取到内存中,随后对读取的数据进行切分,使得每次读取数据不超过buffer node的大小,即CACHE_BUFFER_SIZE的值。切分以后的读取,会先根据当前offset的值在cache tree中查询对应的buffer node,如果可以找到对应的buffer node节点,即说明缓存命中,直接将其缓存的文件数据执行memcpy拷贝到payload中,否则则需要通过Blobstore提供的异步读取直接从存储设备读取,并利用sem信号量进行同步,直到所有的读取完成,一次性返回整个payload,所以整个读取过程需要等待所有的payload准备完成才会返回。

2. spdk_file_write

目前SPDK主分支中的Blob FS提供的写入接口当前仅支持append类型,即不支持覆盖写入操作(注1)。对于append类型写入,Blob FS会首先检查其是否满足cache机制条件,如果不满足则借助Blobstore提供的写入接口,直接写入存储设备中。而一旦满足cache机制,则利用spdk_mempool_get函数向内存池中申请一个内存单元作为buffer node用于存储文件数据,随后将写入的payload进行切分,保证每次写入数据不超该buffer node的大小,并利用memcpy拷贝至buffer node中,当当前buffer node已被写满但存储文件还未被完全写入时,会将当前buffer node添加到cache tree中,再重新申请内存单元,重复上述操作,直到所有的payload都被写入buffer node中。随后触发异步flush操作,将cache tree中存储的文件数据利用Blobstore写入到存储设备中,并更新内存中的元数据。

从上述I/O过程可以发现,cache机制起到的加速作用主要体现在两点:

Read阶段中利用预读机制,先将当前offset附近的部分数据从存储设备中读入到内存中,方便下次直接从内存中读取,而不借助Blobstore,从而提升效率。

Write阶段中将payload优先写入到cache tree中,再利用异步flush操作写入到存储设备中,write本身不需要等待在落盘结束。

值得注意的是,分析Blob FS中cache的默认参数配置以及机制设计,可以发现Blob FS提供的cache机制更适用于大文件的读取。

注1:Blob FS对随机写的支持可参考 https://review.spdk.io/gerrit/c/spdk/spdk/+/5420,但是对目前的Blob FS cache机制有影响。更多Blob FS的patch,也可以关注https://review.spdk.io/。

四、SPDK FUSE (Filesystem in Userspcae)

SPDK提供了FUSE插件,可以将Blob FS像内核文件系统一样挂载,方便测试。可利用本地NVMe设备,基于SPDK FUSE挂载Blob FS,方法可参考以下步骤:

1.  ./configure --with-fuse && make  
2.  scripts/gen_nvme.sh --json-with-subsystems > config.json 
3.  ./test/blobfs/mkfs/mkfs config.json Nvme0n1 
4.  mkdir /mnt/fuse 
5.  ./test/blobfs/fuse/fuse config.json Nvme0n1 /mnt/fuse 

当然,也可以借助rpc框架,调用bdev子系统中Malloc Bdev模块,启用Blob FS文件系统,启用方法如下:

1.  ./build/bin/spdk_tgt  //  Terminal A
2.  ./scripts/rpc.py bdev_malloc_create 512 4096  // Terminal B
3.  ./scripts/rpc.py blobfs_create Malloc0 
4.  ./scripts/rpc.py blobfs_mount Malloc0 /mnt/fuse 

注意:Blobstore本身提供了持久化存储服务,但是这也要求面向的Bdev对象提供持久化存储,例如NVMe Bdev,而前文rpc调用的Malloc Bdev并不能提供持久化存储,因此基于Malloc Bdev模块的Blobstore不具有持久化存储能力。

总结

本文对SPDK提供的用户态存储服务Blobstore以及Blob FS进行了更为深入的探讨,对其设计细节进行了补充,并结合cache机制,分析了Blob FS所提供的I/O操作的流程,最后提供了借助FUSE插件对Blob FS进行调试分析的两种方法。

粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

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

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

相关文章

函数依赖-函数依赖、平凡函数依赖、完全与部分函数依赖、传递函数依赖

一、引言 函数依赖是关系模式中属性与属性之间存在的一种重要数据依赖 1、将关系模式R的模式结构改为 R(SNO,CNO,SN,SD,DD,GRADE) 并对属性列进行重命名 R(学生学号&#xff0c…

msvcp100.dll已加载但找不到入口点的处理方法,分析比较靠谱的msvcp100.dll解决方法

用户在日常使用中有时会遇到一个错误提示:“已加载 msvcp100.dll,但找不到入口点”。这一信息不仅引发了使用上的不便,也对软件的稳定性产生了质疑。理解并解决该问题不仅对确保计算机正常运行至关重要,也对维护软件的长期稳定性和…

油猴 脚本如何添加包含哪个网址 执行脚本

油猴 脚本如何添加包含哪个网址 执行脚本 在这里面加上就可以 // include *://blog.csdn.net/*/article/details/* // include *.blog.csdn.net/article/details/*

【随手记】贴一段matplotlib绘图的多图拼接代码

二维: import numpy as np import matplotlib.pyplot as pltpic_names ["pic1", "pic2", "pic3", "pic4", "pic5", "pic6", "pic7", "pic8", "pic9", "pic10&qu…

代理四川公司疑难商标办理商标异议复审办理

申请商标注册或者办理其他商标事宜,可以自行办理,也可以委托依法设立的商标代理机构办理。外国人或者外国企业在中国申请商标注册和办理其他商标事宜的,应当委托依法设立的商标代理机构办理,按照被代理人的委托办理商标注册申请或…

BEV 中 multi-frame fusion 多侦融合(一)

文章目录 参数设置align_dynamic_thing:为了将动态物体的点云数据从上一帧对齐到当前帧流程旋转函数平移公式filter_points_in_ego:筛选出属于特定实例的点get_intermediate_frame_info: 函数用于获取中间帧的信息,包括点云数据、传感器校准信息、自车姿态、边界框及其对应…

EasyCVR/EasyDSS无人机直播技术助力野生动物监测:开启野生动物保护新篇章

近日有新闻报道,一名挖掘机师傅在清理河道时,意外挖出一只稀有的扬子鳄,挖机师傅小心翼翼地将其放在一边,扬子鳄也顺势游回一旁的河道中。 随着人类对自然环境的不断探索和开发,野生动物及其栖息地的保护显得愈发重要。…

压测怎么做?如何自动化?盘点各大公司全链路压测方案与实践

本文综合盘点各大公司团队的全链路压测技术方案和实践路径,供大家参考。 一、什么是全链路压测? 全链路压测指的是基于实际的生产业务场景、系统环境,模拟海量的用户请求和数据对整个业务链进行压力测试,并持续调优的过程。常用…

PyMuPDF 操作手册 - 01 从PDF中提取文本

文章目录 一、打开文件二、从 PDF 中提取文本2.1 文本基础操作2.2 文本进阶操作2.2.1 从任何文档中提取文本2.2.2 如何将文本提取为 Markdown2.2.3 如何从页面中提取键值对2.2.4 如何从矩形中提取文本2.2.5 如何以自然阅读顺序提取文本2.2.6 如何从文档中提取表格内容2.2.6.1 提…

为啥找对象千万别找大厂男,还好我不是大厂的。。

网上看到一大厂女员工发文说:找对象千万别找大厂男,理由说了一大堆,无非就是大厂男为了逃避带娃,以加班为由宁愿在工位上玩游戏也不愿回家。当然这种观点有的人赞同有的人反对。 网友精彩评论: --------------下面是今…

视频太大了怎么缩小内存

我们在分享视频的时候,有时候会遇到过视频文件太大,无法发送或者上传的情况,别担心,今天我就来给大家分享一个简单有效的方法,让你的视频变得更小,更方便分享! 打开 “51视频处理官网 的网站。上…

vue引入aos.js实现滚动动画

aos.js官方网站:http://michalsnik.github.io/aos/ aos.js介绍 AOS (Animate on Scroll) 是一个轻量级的JavaScript库,用于实现当页面元素随着用户滚动进入可视区域时触发动画效果。它不需要依赖 jQuery,可以很容易地与各种Web开发框架&#…

高压线防外破警示灯在电力安全发挥的作用_鼎跃安全

高压输电线路往往跨越城市、乡村和野外,覆盖范围广泛。随着城乡建设和交通运输的快速发展,高压线路周围的活动频繁,外部破坏风险增加。车辆撞击电线杆、施工机械误碰线路以及人为破坏等事件时有发生,严重影响电力供应的稳定性和安…

Linux---rpm/yum包管理器

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 一.RPM概述 RPM(Red Hat Package Manager)是Linux中的一种软件包管理格式也可以称为软件包管理器;它可以将软件包以二进制形式打包,并提供工具来安…

记录一个利用winhex进行图片隐写分离的

前提 是一次大比武里面的题目,属实给我开了眼,跟我之前掌握的关于隐写合并的操作都不一样。 它不是直接在文件里面进行输入文件隐写,叫你输入密码,或者更改颜色,或者偏移位置; 它不是单纯几个文件合并&a…

【GD32定时器】高级定时器生成PWM波+定时器外设配置DMA使用

基本定时器和系统时钟配置可以参考以下文章, 文章链接为: 【GD32系列–基本定时器Timer + 定时1ms 灯光间隔1s闪烁例程】 【GD32】_时钟架构及系统时钟频率配置 【GD32】 TIMER通用定时器学习+PWM输出占空比控制LED 目录标题 一 、DMA简介1 DMA 操作2 中断3 DMA 请求映射二、…

sharePoint-基于sharepoint列表中的其他列值自动更新值列

首先进入网站,点击网站内容 点击想要操作的数据表后面的按钮,点击设置 点击创建栏 填写栏名,类型选择计算值,公式用于对列表或库中的值执行计算,然后点击右下角的确定就添加成功了 公式参考: 公式SharePoi…

观察者模式-委托(大话设计模式)C/C++版本

观察者模式-委托 先看该常规的没有委托概念的代码&#xff0c;如下&#xff1a; 非委托 #include <iostream> #include <string> #include <list> using namespace std;class Subject; // 前向声明// 抽象观察者 class Observer { protected:string name;…

上证50etf期权的手续费要多少钱?期权懂分享

今天带你了解上证50etf期权的手续费要多少钱&#xff1f;上证50ETF期权的开户一般交易手续费默认为7元一张。在进行期权开户之前&#xff0c;建议提前联系一名券商的客户经理&#xff0c;协商期权手续费优惠事宜。 上证50etf期权的手续费要多少钱&#xff1f; 上证50ETF期权的…

Spring是如何设计IOC容器的?BeanFactory ApplicationContext

BeanFactory是Spring框架中最底层的接口&#xff0c;用于实例化、配置和管理bean。它使用控制反转&#xff08;IOC&#xff09;模式&#xff0c;将对象的创建、管理和装配的职责从应用程序代码中转移给Spring容器。这样&#xff0c;应用程序代码就无需关心对象如何创建和装配&a…