分布式文件系统(FastDFS)

news2025/1/21 15:25:25

🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

🍓 更多文章请点击
在这里插入图片描述在这里插入图片描述

文章目录

  • 一、 FastDFS简介
  • 二、 FastDFS内部结构
  • 三、 FastDFS存储策略
  • 四、 工作原理
    • 4.1 上传流程
    • 4.2 下载流程
  • 五、 收成文件名解读
  • 六、 使用步骤
    • 6.1 引入依赖
    • 6.2 配置文件application.yml
    • 6.3 测试
    • 6.4 工具类

在这里插入图片描述

一、 FastDFS简介

项目开源地址 :https://github.com/happyfish100/fastdfs
官方论坛: http://bbs.chinaunix.net/forum-240-1.html

  • FastDFS是基于互联网应用的开源分布式文件系统,主要用于大中型网站存储资源文件,如图片、文档、音频、视频等。
  • FastDFS 是基于 C 语言开发的,是一个轻量级开源的高性能分布式文件系统。主要功能有:文件存储、文件同步、文件访问(文件上传/下载),解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。

二、 FastDFS内部结构

FastDFS 架构包括 Tracker ServerStorage Server

  • Storage Server : 存储服务器,负责文件存储,文件同步/备份,提供文件访问接口,文件元数据管理。以 group 为单位,每个 group 内可以有多台 Storage Server,数据互为备份,达到容灾的目的。每个 Storage 在启动以后会主动连接 Tracker,告知自己所属 group 等存储相关信息,并保持周期性心跳。

  • Tracker Server:  跟踪调度服务器,调度存储服务,负责文件访问的调度和负载均衡,负责管理所有的 Storage Server 和 group 组/卷。

  • Group: 组, 也可称为 Volume 卷。同组内服务器上的文件是完全相同的,同一组内的 Storage Server 之间是对等的,文件上传、删除等操作可以在任意一台 Storage Server 上进行。

三、 FastDFS存储策略

  • 扩容分组可以解决单一Storage Server 容量限制问题
  • 组内构建存储服务器,解决单一节点故障问题
  1. 为了支持大容量存储,Storage 存储服务器采用了分组(或分卷)的方式。存储系统由一个或多个组组成,组与组之间的文件是相互独立的,所有组的文件容量累加就是整个存储系统中的文件容量。一个组可以由一台或多台存储服务器组成,一个组下的存储服务器中的文件都是相同的,组中的多台存储服务器起到了冗余备份和负载均衡的作用。

  2. 当组中增加了新的服务器时,系统会自动同步已有的文件,同步完成后,系统自动将新增的服务器切换至线上提供服务。

  3. 当存储空间不足时,可以动态添加组,只需要增加一台或多台服务器,并将它们配置为一个新的组,即可扩大存储系统的容量。当你的某个应用或者模块(对应的 group)的并发过高的时候,可以直接在 group 中增加若干个 Storage 来实现负载均衡。

四、 工作原理

4.1 上传流程

在这里插入图片描述

4.2 下载流程

在这里插入图片描述

五、 收成文件名解读

生成文件名 : 文件名由 group名称/存储目录/两级子目录/file_id.后缀名 拼接而成。

例如: group/M00/00/00/wkiIoGjXKDSAE030aaCXPfGRATQ725.jpg

解读:

  • group1组名/卷名。文件上传成功以后所在的 Storage 组名称,由 Storage 服务器返回。
  • M00虚拟磁盘路径
  • /00/00数据两级目录 Storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
  • wkiIoGjXKDSAE030aaCXPfGRATQ725file_id,由 Storage Server IP、文件创建时间、文件大小、文件 crc32 和一个随机数组成,然后将这个二进制串进行 base64 编码,转换为字符串。

六、 使用步骤

6.1 引入依赖

<dependency>
    <groupId>com.github.tobato</groupId>
    <artifactId>fastdfs-client</artifactId>
    <version>1.26.7</version>
    <exclusions>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
    </exclusions>
</dependency>

6.2 配置文件application.yml


fdfs:
  so-timeout: 1500
  connect-timeout: 600
  #缩略图生成参数
  thumb-image:
    width: 150
    height: 150
  #TrackerList参数,支持多个
  tracker-list: 192.168.136.150:22122
  ## 可选,主要用于路径拼接
  web-server-url: http://192.168.136.150:8888/ 

6.3 测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TanhuaServerApplication.class)
public class TestFastDFS {

    //从调度服务器获取一个目标存储服务器,上传
    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private FdfsWebServer webServer;// 获取存储服务器的请求URL 对应配置文件中的 web-server-url

    @Test
    public void testFileUpdate() throws FileNotFoundException {
         //1、指定文件
        File file = new File("D:\\test.jpg");
        //2、文件上传
        StorePath path = client.uploadFile(new FileInputStream(file),
                file.length(), "jpg", null);
        //3、拼接访问路径
        String url = webServer.getWebServerUrl() + path.getFullPath();
    }
}


6.4 工具类

  1. 接口
public interface FdfsService {

    String uploadFile(MultipartFile file);

    String downloadFile(String fileUrl);

    Boolean deleteFile(String fileUrl);

    byte[] downloadMultipartFile(String fileUrl);
}
  1. 实现类
@Service
@Slf4j
public class FdfsServiceImpl implements FdfsService {

    @Autowired
    private FastDFSClientWrapper fastDFSClientWrapper;

    /**
     * 文件上传
     * 最后返回fastDFS中的文件名称;group/M00/00/00/wkiIoGjXKDSAE030aaCXPfGRATQ725.jpg
     */
    @Override
    public String uploadFile(MultipartFile file) {
        byte[] bytes = new byte[0];
        try {
            bytes = file.getBytes();
        } catch (IOException e) {
            log.error("获取文件错误");
            e.printStackTrace();
        }
        //获取源文件名称
        String originalFileName = file.getOriginalFilename();
        //获取文件后缀
        String extension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        String fileName = file.getName();
        //获取文件大小
        long fileSize = file.getSize();
        return fastDFSClientWrapper.uploadFile(bytes, fileSize, extension);
    }

    /**
     * 文件下载
     *
     * @param fileUrl  当前对象文件名称
     * @param response HttpServletResponse 内置对象
     * @throws IOException
     */
    public void downloadFile(String fileUrl, HttpServletResponse response) throws IOException {
        byte[] bytes = fastDFSClientWrapper.downloadFile(fileUrl);
        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("test.jpg", "UTF-8"));
        response.setCharacterEncoding("UTF-8");
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Boolean deleteFile(String fileUrl) {
        try {
            fastDFSClientWrapper.deleteFile(fileUrl);
        } catch (IOException e) {
            log.error("文件删除失败",e);
            return false;
        }
        return true;
    }

    @Override
    public byte[] downloadMultipartFile(String fileUrl) {
        byte[] bytes = new byte[0];
        MultipartFile file = null;
        try {
            bytes = fastDFSClientWrapper.downloadFile(fileUrl);
        } catch (IOException e) {
            log.error("文件下载失败",e);
        }
        return bytes;
    }

    /**
     * 文件下载
     * @param fileUrl  当前对象文件名称
     * @throws IOException
     */
    @Override
    public String downloadFile(String fileUrl)  {
        byte[] bytes = new byte[0];
        try {
            bytes = fastDFSClientWrapper.downloadFile(fileUrl);
        } catch (IOException e) {
            log.error("文件下载失败",e);
        }
        return Base64.getEncoder().encodeToString(bytes);
    }


}

  1. 客户端包装类
@Component
@Slf4j
public class FastDFSClientWrapper {

    @Autowired
    private FastFileStorageClient fastFileStorageClient;

    /**
     * 文件上传
     * 最后返回fastDFS中的文件名称;group/M00/00/00/wkiIoGjXKDSAE030aaCXPfGRATQ725.jpg
     *
     * @param bytes     文件字节
     * @param fileSize  文件大小
     * @param extension 文件扩展名
     * @return fastDfs路径
     */
    public String uploadFile(byte[] bytes, long fileSize, String extension) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        StorePath storePath = fastFileStorageClient.uploadFile(byteArrayInputStream, fileSize, extension, null);
        System.out.println(storePath.getGroup() + "==" + storePath.getPath() + "======" + storePath.getFullPath());
        return storePath.getFullPath();
    }

    /**
     * 下载文件
     *  返回文件字节流大小
     * @param fileUrl 文件URL
     * @return 文件字节
     */
    public byte[] downloadFile(String fileUrl) throws IOException {
        String group = fileUrl.substring(0, fileUrl.indexOf("/"));
        String path = fileUrl.substring(fileUrl.indexOf("/") + 1);
        DownloadByteArray downloadByteArray = new DownloadByteArray();
        byte[] bytes = fastFileStorageClient.downloadFile(group, path, downloadByteArray);
        return bytes;
    }

    public boolean deleteFile(String fileUrl) throws IOException {
        String group = fileUrl.substring(0, fileUrl.indexOf("/"));
        String path = fileUrl.substring(fileUrl.indexOf("/") + 1);
        fastFileStorageClient.deleteFile(group,path);
        return true;
    }

}

在这里插入图片描述在这里插入图片描述

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

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

相关文章

吐血整理,接口自动化测试-接口依赖/上传接口处理(项目实例)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 常见的两种接口依…

Docker容器与虚拟化技术:Docker资源控制、数据管理

目录 一、理论 1.资源控制 2.Docker数据管理 二、实验 1.Docker资源控制 2.Docker数据管理 三、问题 1.docker容器故障导致大量日志集满&#xff0c;造成磁盘空间满 2、当日志占满之后如何处理 四、总结 一、理论 1.资源控制 (1) CPU 资源控制 cgroups&#xff0…

什么是前端框架?怎么学习? - 易智编译EaseEditing

前端框架是一种用于开发Web应用程序界面的工具集合&#xff0c;它提供了一系列预定义的代码和结构&#xff0c;以简化开发过程并提高效率。 前端框架通常包括HTML、CSS和JavaScript的库和工具&#xff0c;用于构建交互式、动态和响应式的用户界面。 学习前端框架可以让您更高效…

Centos8安装docker并配置Kali Linux图形化界面

鉴于目前网上没有完整的好用的docker安装kali桌面连接的教程&#xff0c;所以我想做一个。 准备工作 麻了&#xff0c;这服务器供应商提供的镜像是真的纯净&#xff0c;纯净到啥都没有。 问题一&#xff1a;Centos8源有问题 Error: Failed to download metadata for repo ap…

Redis基础概念和数据类型详解

目录 1.什么是Redis&#xff1f; 2.为什么要使用Redis&#xff1f; 3.Redis为什么这么快&#xff1f; 4.Redis的使用场景有哪些&#xff1f; 5.Redis的基本数据类型 5.1 5种基础数据类型 5.1.1 String字符串 5.1.2 List列表 5.1.3 Set集合 5.1.4 Hash散列 5.1.5 Zset有序集…

【hive】hive分桶表的学习

hive分桶表的学习 前言&#xff1a; 每一个表或者分区&#xff0c;hive都可以进一步组织成桶&#xff0c;桶是更细粒度的数据划分&#xff0c;他本质不会改变表或分区的目录组织方式&#xff0c;他会改变数据在文件中的分布方式。 分桶规则&#xff1a; 对分桶字段值进行哈…

玩转 VS code 之下载篇

VSCode 简介 Visual Studio Code (简称 VS Code / VSC)&#xff0c;是2015 年由微软公司推出的一款免费开源的现代化轻量级代码编辑器&#xff0c;支持几乎所有主流的开发语言的语法高亮、智能代码补全、GIT 等特性&#xff0c;支持插件扩展等等 可用于 Windows&#xff0c;ma…

使用 Visual Studio GoogleTest编写 C/C++ 单元测试——入门篇

入门教程 Visual Studio 新建 GoogleTest项目&#xff0c;一路选默认参数 pch.h #pragma once#include "gtest/gtest.h"int add(int a, int b);pch.cpp #include "pch.h"int add(int a, int b) {return a b; }test.cpp #include "pch.h"TES…

LoRA微调方法详解

本文要介绍的是大模型的微调训练方法之一----LoRA。 0 背景 现在大模型非常火爆&#xff0c;大家都在想方设法应用大模型。 当前很多大模型虽说可以zero-shot直接使用&#xff0c; 但是在具体应用上一般还是微调一下效果更好&#xff0c; 也就是常说的finetune。 在小模型时代…

栈存储结构详解

目录 栈存储结构详解 进栈和出栈 栈的具体实现 栈的应用 什么是队列&#xff08;队列存储结构&#xff09; 栈存储结构详解 同顺序表和链表一样&#xff0c;栈也是用来存储逻辑关系为 "一对一" 数据的线性存储结构&#xff0c;如图 1 所示。 图 1 栈存储结构示意…

【string】基本用法

目录 前言: string常用接口 一、string的创建,拼接与拷贝构造 1.创建 2.拼接 3.拷贝构造 二、string遍历 方式一&#xff1a;operator[ ]重载 方式二&#xff1a;迭代器 1.正向迭代器&#xff1a; 2.反向迭代器 3.const正向迭代器 4.const反向迭代器 方式三&#…

PyQt5资源的加载和使用,即如何使用Pyrcc

1、打开QtDesigner&#xff0c;选择编辑资源 2、新建资源文件&#xff0c;随便找个地方保存 3、按照自己的喜好命名&#xff0c;然后添加资源 4、保存并退出 5、我们创建一个QLabel&#xff0c;在这里添加资源 6、我们保存界面文件&#xff0c;并编译为py文件&#xff0c;然后…

【C语言】调试技巧

目录 一、什么是bug? 二、调试 1.一般调试的步骤 2.Debug 和 Release 三、调试环境准备 四、调试时要查看的信息 1.查看临时变量的值 2.查看内存信息 3.查看调用堆栈 4.查看反汇编信息 5.查看寄存器 五、练习 六、常见的coding技巧 七、const的作用 八、编程常见…

时序预测 | MATLAB实现基于RF随机森林的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于RF随机森林的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于RF随机森林的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 MATLAB实现基于RF随机森林的时间序列预测-递归预测未来…

Linux命令200例:kill用来终止或者结束进程(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

服务链路追踪

一、基础概念 1.背景 对于一个大型的几十个、几百个微服务构成的微服务架构系统&#xff0c;通常会遇到下面一些问题&#xff0c;比如&#xff1a; 如何串联整个调用链路&#xff0c;快速定位问题&#xff1f;如何理清各个微服务之间的依赖关系&#xff1f;如何进行各个微服…

uniapp-微信小程序篇

uniapp-微信小程序篇 一、创建项目(以Vue3TS 项目为示例) 可以通过命令行的方式创建也可以通过HBuilderX进行创建&#xff08;通过HBuilderX创建的项目建议选择最简单的模板&#xff09;&#xff0c;个人建议使用命令行方式。 (1) 命令行方式&#xff1a; npx degit dcloudio…

WebRTC音视频通话-WebRTC视频自定义RTCVideoCapturer相机

WebRTC音视频通话-WebRTC视频自定义RTCVideoCapturer相机 在之前已经实现了WebRTC调用ossrs服务&#xff0c;实现直播视频通话功能。但是在使用过程中&#xff0c;RTCCameraVideoCapturer类提供的方法不能修改及调节相机的灯光等设置&#xff0c;那就需要自定义RTCVideoCaptur…

认识excel篇2之如何快速输入数据

一、快速输入数据&#xff08;快捷键功能的使用&#xff09; 1、鼠标左键填充&#xff1a;复制填充、等差序列填充&#xff08;行、列是一样的&#xff09; 步骤&#xff1a;选中单元格&#xff0c;鼠标放置到单元格右下角待鼠标箭头变成实心十字架&#xff0c;左键向下拖拽&…