前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JuiceFS 源码阅读-上

JuiceFS 源码阅读-上

作者头像
用户1260683
发布2021-07-20 10:19:19
1.8K0
发布2021-07-20 10:19:19
举报

JuiceFS 源码阅读-上

最近研究文件系统,把近期比较火的JuiceFS代码翻出来看了一下,研究为啥其性能要比CephFS要好。

背景知识

参考资源:https://mp.weixin.qq.com/s/HvbMxNiVudjNPRgYC8nXyg

FUSE 是一个用来实现用户态文件系统的框架,这套 FUSE 框架包含 3 个组件:

  • 内核模块 fuse.ko :用来接收 vfs 传递下来的 IO 请求,并且把这个 IO 封装之后通过管道发送到用户态;
  • 用户态 lib 库 libfuse :解析内核态转发出来的协议包,拆解成常规的 IO 请求;
  • mount 工具 fusermount ;

背景:一个用户态文件系统,挂载点为 /tmp/fuse ,用户二进制程序文件为 ./hello ;当执行 ls -l /tmp/fuse 命令的时候,流程如下: IO 请求先进内核,经 vfs 传递给内核 FUSE 文件系统模块; 内核 FUSE 模块把请求发给到用户态,由 ./hello 程序接收并且处理。处理完成之后,响应原路返回;

JuiceFS架构简介

JuiceFS 由三个部分组成:

  1. JuiceFS 客户端:协调对象存储和元数据存储引擎,以及 POSIX、Hadoop、Kubernetes、S3 Gateway 等文件系统接口的实现;
  2. 数据存储:存储数据本身,支持本地磁盘、对象存储;
  3. 元数据引擎:存储数据对应的元数据,支持 Redis、MySQL、SQLite 等多种引擎;

JuiceFS 依靠 Redis 来存储文件的元数据。Redis 是基于内存的高性能的键值数据存储,非常适合存储元数据。与此同时,所有数据将通过 JuiceFS 客户端存储到对象存储中。

任何存入 JuiceFS 的文件都会被拆分成固定大小的 "Chunk",默认的容量上限是 64 MiB。每个 Chunk 由一个或多个 "Slice" 组成,Slice 的长度不固定,取决于文件写入的方式。每个 Slice 又会被进一步拆分成固定大小的 "Block",默认为 4 MiB。最后,这些 Block 会被存储到对象存储。与此同时,JuiceFS 会将每个文件以及它的 Chunks、Slices、Blocks 等元数据信息存储在元数据引擎中。

使用 JuiceFS,文件最终会被拆分成 Chunks、Slices 和 Blocks 存储在对象存储。因此,你会发现在对象存储平台的文件浏览器中找不到存入 JuiceFS 的源文件,存储桶中只有一个 chunks 目录和一堆数字编号的目录和文件。不要惊慌,这正是 JuiceFS 高性能运作的秘诀!

补充一下源码中,每个blocks的命名规则定义,也就是最终存储在对象存储系统中的对象key名称。

代码语言:javascript
复制
func (c *rChunk) key(indx int) string {
    if c.store.conf.Partitions > 1 {
        return fmt.Sprintf("chunks/%02X/%v/%v_%v_%v", c.id%256, c.id/1000/1000, c.id, indx, c.blockSize(indx))
    }
    return fmt.Sprintf("chunks/%v/%v/%v_%v_%v", c.id/1000/1000, c.id/1000, c.id, indx, c.blockSize(indx))
}

从命名规则里面也能看出,数据是支持按partition进行分区存储的,也就是说最终存储数据的bucket可以是多个,这样有助于提高并发能力,特别是AWS S3每个bucket是有TPS性能上限的。

JuiceFS文件系统golang抽象接口组成

文件系统定义核心数据结构

代码语言:javascript
复制
type FileSystem struct {
    conf   *vfs.Config
    reader vfs.DataReader
    writer vfs.DataWriter
    m      meta.Meta
    logBuffer chan string
}

下图为个人理解所画的抽象接口结构图

  • 整个JuiceFS文件系统实现主要拆分为VFS抽象实现和相关的config配置管理两大部分。
  • 任意文件File操作都涉及到数据和元数据两部分内容,因此代码中包含数据处理相关的DataReader和DataWriter两个抽象接口,用来处理数据的读取和写入两类请求。而元数据抽象出Meta一个数据库相关的接口,基于这个接口目前官方实现了dbMeta也就是兼容SQL相关的元数据实现,以及redisMeta实现(基于redis)。从性能表现来看,redis比MySQL性能要好3~5倍左右。具体可以参考这个
  • 所有的数据读写操作都要和本地缓存进行交互(Chunk->Slice->block(page)三个层级进行管理),缓存目前主要实现了基于本地文件系统diskStore和基于内存缓存cacheStore(堆空间)两种类型。数据写入和读取最终都是由对应的缓存模块同步到远程的ObjectSotrage。
  • config主要负责对本地缓存、元数据引擎连接信息等相关的配置。

JuiceFS支持的数据列表:

https://github.com/juicedata/juicefs/blob/main/docs/zh_cn/databases_for_metadata.md

JuiceFS元数据redis与MySQL性能对比测试:

https://github.com/juicedata/juicefs/blob/main/docs/en/metadata_engines_benchmark.md

下图是源码中对ChunkStore的抽象接口定义,通过NewReader和NewWriter生成对应的Reader读取抽象和Writer抽象,实现数据的读写相关原子接口。

任何厂家的对象存储产品,只要实现下面的接口抽象,即可实现与JuiceFS的对接。

数据读取抽象接口

下图是数据读取抽象接口的继承组合关系

最终的数据读取关联到rChunk这个struct的相关method方法。

数据写入抽象接口

下图是数据写入抽象接口的继承组合关系

最终的数据读取关联到wChunk这个struct的相关method方法。

小节

至此,基本理清了JuiceFS的基本构架和核心数据结构,下节开始对其读写具体接口流程进行剖析。

打个小广告,团队持续招聘存储开发和运维同学,感兴趣的可以看看之前公众号网易游戏招聘相关内容。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Ceph对象存储方案 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JuiceFS 源码阅读-上
    • 背景知识
      • JuiceFS架构简介
        • JuiceFS文件系统golang抽象接口组成
          • 数据读取抽象接口
            • 数据写入抽象接口
              • 小节
              相关产品与服务
              对象存储
              对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档