转摘JuiceFS分布式文件系统源码分析(Java层)

允若彤阅读量 22

文章目录

  • 01 引言
  • 02 JuiceFS Hadoop Java API
  • 2.1 如何使用?
  • 2.2 入口
  • 2.2.1 getFileSystem方法
  • 2.2.2 小结
  • 2.3 JuiceFS源码
  • 2.3.1 从hadoop-api到juicefs-api
  • 2.3.2 JuiceFS底层库
  • 03 总结
  • 04 文末

01 引言

在前面的博客​​《JuiceFS-开源分布式文件系统入门(一篇就够了)》​​,我们大致了解了JuiceFS的一些基本概念,它的架构图大致如下:

![JuiceFS分布式文件系统源码分析(Java层)_大数据](https://s2.51cto.com/images/blog/202211/12004128_636e7b38b4b2a72943.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


本文主要针对​​Hadoop​​​的​​Java API​​来分析下它的源码。

02 JuiceFS Hadoop Java API

官方使用教程:​[​《在 Hadoop 生态使用 JuiceFS 存储》​](https://www.juicefs.com/docs/zh/community/hadoop_java_sdk)

2.1 如何使用?

使用​​Hadoop Java API​​去调用JuiceFS是很简单的,一般分为如下几个步骤。

STEP1:引入依赖

复制代码
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>版本号</version>
</dependency>

<dependency>
    <groupId>io.juicefs</groupId>
    <artifactId>juicefs-hadoop</artifactId>
    <version>版本号</version>
</dependency>

STEP2:代码使用,只需要修改下Configuration就可以了

复制代码
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class JuiceFSDemo {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.set("fs.jfs.impl", "io.juicefs.JuiceFileSystem");
        conf.set("juicefs.meta", "redis://127.0.0.1:6379/0");  // JuiceFS 元数据引擎地址
        Path p = new Path("jfs://{JFS_NAME}/");  // 请替换 {JFS_NAME} 为正确的值
        FileSystem jfs = p.getFileSystem(conf);
        FileStatus[] fileStatuses = jfs.listStatus(p);
        // 遍历 JuiceFS 文件系统并打印文件路径
        for (FileStatus status : fileStatuses) {
            System.out.println(status.getPath());
        }
    }
}

STEP3:接下来,直接使用hadoop-common的java api即可使用JuiceFS系统了。

可以看得出,操作是十分简单的,只要引入了hadoop-common 以及juicefs-hadoop的依赖,修改一下配置,即可使用。那么其底层的代码又是怎么走的呢?接下来讲讲。

2.2 入口

从上面的代码,我们可以知道,仅仅是配置了两项,然后指定了地址,即可使用JuiceFS文件系统了,如下代码:

复制代码
Configuration conf = new Configuration();
conf.set("fs.jfs.impl", "io.juicefs.JuiceFileSystem");
conf.set("juicefs.meta", "redis://127.0.0.1:6379/0");  // JuiceFS 元数据引擎地址
Path p = new Path("jfs://{JFS_NAME}/");  // 请替换 {JFS_NAME} 为正确的值
FileSystem jfs = p.getFileSystem(conf);

其中主要核心是 ​​p.getFileSystem(conf)​​ 这一段代码。

2.2.1 getFileSystem方法

跟着断点走,会进入到++org.apache.hadoop.fs.FileSystem.Cache#getInternal++方法:

![JuiceFS分布式文件系统源码分析(Java层)_大数据_02](https://s2.51cto.com/images/blog/202211/12004128_636e7b38e382f40773.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


其中较为核心的是++createFileSystem++方法,进去看看:

![JuiceFS分布式文件系统源码分析(Java层)_JuiceFS_03](https://s2.51cto.com/images/blog/202211/12004129_636e7b3919bbf72475.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


可以看到,createFileSystem 方法主要做了获取类的元数据对象以及初始化操作,我们主要看卡++getFileSystemClass++方法:

![JuiceFS分布式文件系统源码分析(Java层)_JuiceFS_04](https://s2.51cto.com/images/blog/202211/12004129_636e7b393d09367954.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


该方法会加载所有的文件系统,对应的方法为++loadFileSystems++,继续断点:

![JuiceFS分布式文件系统源码分析(Java层)_hadoop_05](https://s2.51cto.com/images/blog/202211/12004129_636e7b396847118665.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


当然到这里,并没有我们需要的JuiceFS系统,继续走下一步:

![JuiceFS分布式文件系统源码分析(Java层)_分布式文件系统_06](https://s2.51cto.com/images/blog/202211/12004129_636e7b39937af12095.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


可以看到红框的那一行,原来是通过拼接scheme 来去动态加载JuiceFileSystem的对象,也就是对应前面设置的:

复制代码
conf.set("fs.jfs.impl", "io.juicefs.JuiceFileSystem");

2.2.2 小结

hadoop-common初始化JuiceFS文件系统的流程:

  • 首先会解析地址获取scheme,如:(​jfs://{JFS_NAME}/​,它的​scheme​​jfs​);
  • 接着​hadoop-common​里面的++org.apache.hadoop.fs.FileSystem#getFileSystemClass++ 方法通过拼接++"fs." + scheme + ".impl"++作为key值去获取config的内容,即:
复制代码
//conf.set("fs.jfs.impl", "io.juicefs.JuiceFileSystem");
conf.get("fs.jfs.impl", null);
  • 最后即可实例化​JuiceFS​文件系统了。

2.3 JuiceFS源码

到这里我们知道了hadoop-common api对接JuiceFS的方式了,那么JuiceFS里的代码是如何的呢?

2.3.1 从hadoop-api到juicefs-api

我们可以从实际的业务入手,如下示例:

复制代码
private void initHdfsPath() {
        Path path = new Path(RESOURCE_UPLOAD_PATH);
        try {
            if (!fs.exists(path)) {
                fs.mkdirs(path);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

断点看看​​fs.exists​​方法:

![JuiceFS分布式文件系统源码分析(Java层)_hadoop_07](https://s2.51cto.com/images/blog/202211/12004129_636e7b39b40b992086.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


从断点可以看到,当前的文件系统为​​JuiceFileSystem​​了,继续断点进去:

![JuiceFS分布式文件系统源码分析(Java层)_hadoop_08](https://s2.51cto.com/images/blog/202211/12004129_636e7b39d7abf99450.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


会发下,这里会进入++org.apache.hadoop.fs.FileSystem#exists++ 方法,其中里面有一个​​getFileStatus​​方法,点击查看:

![JuiceFS分布式文件系统源码分析(Java层)_文件系统_09](https://s2.51cto.com/images/blog/202211/12004130_636e7b3a08f322508.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


原来它是一个抽象方法,由子类实现:

![JuiceFS分布式文件系统源码分析(Java层)_hadoop_10](https://s2.51cto.com/images/blog/202211/12004130_636e7b3a2723a53324.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


![JuiceFS分布式文件系统源码分析(Java层)_文件系统_11](https://s2.51cto.com/images/blog/202211/12004130_636e7b3a50a6e65617.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")

它有多个子类实现,当然也包括我们目前的​​JuiceFileSystemImpl​​,进入看看:

![JuiceFS分布式文件系统源码分析(Java层)_大数据_12](https://s2.51cto.com/images/blog/202211/12004130_636e7b3a72cf823056.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


终于进来了,接着继续看++io.juicefs.JuiceFileSystemImpl#getFileStatusInternal++方法:

![JuiceFS分布式文件系统源码分析(Java层)_大数据_13](https://s2.51cto.com/images/blog/202211/12004130_636e7b3a9395928976.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


可以看到,原来查询是否存在,JuiceFS 是使用了​​lib​​​去查,这个​​lib​​其实是调用到了底层的库了(JNI技术)。

2.3.2 JuiceFS底层库

我们通过搜索++io.juicefs.JuiceFileSystemImpl#lib++变量:

![JuiceFS分布式文件系统源码分析(Java层)_大数据_14](https://s2.51cto.com/images/blog/202211/12004130_636e7b3ab434f13478.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


可以看到它是在++io.juicefs.JuiceFileSystemImpl#loadLibrary++方法初始化了,看看里面的代码:

![JuiceFS分布式文件系统源码分析(Java层)_文件系统_15](https://s2.51cto.com/images/blog/202211/12004130_636e7b3ad56cb81387.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


可以看到它是通过识别当前操作系统来去加载JuiceFS 的底层​​so​​库的,那么底层库的接口支持哪些呢?看看:

![JuiceFS分布式文件系统源码分析(Java层)_文件系统_16](https://s2.51cto.com/images/blog/202211/12004131_636e7b3b0a6e021009.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/resize,m_fixed,w_1184 "在这里插入图片描述")


其实就是支持文件系统的CURD这些,也没啥好看的了。

简单的说,++它的核心并不在java代码,而是通过JNI来调用底层的库来实现的++。

03 总结

通过阅读本文,我们可以知道,JucieFS对接hadoop-common api的流程如下:

  1. hadoop-common 里面的​FileSystem​类首先会解析地址获取​scheme​,如:(​jfs://{JFS_NAME}/​,它的​scheme​​jfs​);
  • 接着​hadoop-common​里面的getFileSystemClass方法通过拼接++"fs." + scheme + ".impl"++作为​key​值去获取​config​的内容并实例化​JuiceFS​文件系统了;
  • JuiceFS 文件系统对象是继承​FileSystem​对象实现的,所以使用​FileSystem​的接口去调用,最终由​JuiceFS​文件系统来实现;
  • JuiceFS 文件系统的​java​代码最终是调用了底层的​so​库去实现。

其实关键的核心还是在JuiceFS 的底层库,不知道有无开源呢?感兴趣的小伙伴可以去参考它的源码:​[​https://github.com/juicedata/juicefs​](https://github.com/juicedata/juicefs)

04 文末

本文主要讲解了​​hadoop-common java api​​层面JuiceFS的实现流程,希望能帮助到大家,谢谢大家的阅读,本文完!


复制代码
    ```
    

    ===========================
    【来源: 51CTO】
    【作者: 阿甘兄_】
    【原文链接】 https://blog.51cto.com/u_15294985/5848271
    声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。
    ```
标签: 大数据
0/300
全部评论0
0/300