# SpringCloud-FastDFS **Repository Path**: binflying/SpringCloud-FastDFS ## Basic Information - **Project Name**: SpringCloud-FastDFS - **Description**: 文件上传微服务的使用 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2020-06-04 - **Last Updated**: 2021-11-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1 项目介绍 - `ys-parent`:父工程(依赖管理) - `ys-utils`:通用的工具类 - `ys-common`:通用类 - `ys-model`:模型类 - `ys-service-api`:api接口 # 2 FastDFS 简介 ## 什么是分布式文件系统 分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。 通俗来讲: - 传统文件系统管理的文件就存储在本机。 - 分布式文件系统管理的文件存储在很多机器,这些机器通过网络连接,要被统一管理。无论是上传或者访问文件,都需要通过管理中心来访问。 >总结:文件系统是`负责管理和存储文件的系统软件`,它是操作系统和硬件驱动之间的桥梁,操作系统通过文件系统提供的接口去存取文件,用户通过操作系统访问磁盘上的文件。 如下图: ![在这里插入图片描述](./readme.assets/21.png) 常见的文件系统:`FAT16/FAT32、NTFS、HFS、UFS、APFS、XFS、Ext4等` 。 ## 2.1 主流的分布式文件系统 ### 2.1.1 NFS ![在这里插入图片描述](./readme.assets/22.png) ![在这里插入图片描述](./readme.assets/23.png) 1)在客户端上映射NFS服务器的驱动器。 2)客户端通过网络访问NFS服务器的硬盘完全透明。 ### 2.1.2 GFS ![在这里插入图片描述](./readme.assets/24.png) 1)GFS采用主从结构,一个GFS集群由一个master和大量的chunkserver组成。 2)master存储了数据文件的元数据,一个文件被分成了若干块存储在多个chunkserver中。 3)用户从master中获取数据元信息,从chunkserver存储数据。 ### 2.1.3 HDFS ![在这里插入图片描述](./readme.assets/25.png) 1)HDFS采用主从结构,一个HDFS集群由一个名称结点和若干数据结点组成。名称结点存储数据的元信息,一个完整的数据文件分成若干块存储在数据结点。 2)客户端从名称结点获取数据的元信息及数据分块的信息,得到信息客户端即可从数据块来存取数据。 ## 2.2 分布式文件服务提供商 1)阿里的OSS ![在这里插入图片描述](./readme.assets/26.png) 2)百度云存储 ## 2.3 什么是FastDFS FastDFS 是由淘宝的余庆先生所开发的一个轻量级、高性能的开源分布式文件系统。用纯C语言开发,功能丰富: - `文件存储` - `文件同步` - `文件访问(上传、下载)` - `存取负载均衡` - `在线扩容` 适合有大容量存储需求的应用或系统。同类的分布式文件系统有谷歌的GFS、HDFS(Hadoop)、TFS(淘宝)等。 ### 为什么要使用 FastDFS 呢? 上边介绍的NFS、GFS都是通用的分布式文件系统,通用的分布式文件系统的优点的是开发体验好,但是系统复杂性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。`FastDFS 非常适合存储图片等那些小文件,FastDFS 不对文件进行分块,所以它就没有分块合并的开销,FastDFS 网络通信采用 socket,通信速度很快`。 ## 2.4 FastDFS 的架构 FastDFS架构包括 Tracker server和Storageserver。客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。 如下图: ![在这里插入图片描述](./readme.assets/27.png) FastDFS 两个主要的角色:`Tracker Server` 和 `Storage Server` 。 - `Tracker Server`作用是`负载均衡和调度`,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。 FastDFS集群中的Tracker server可以有多台,Tracker server之间是相互平等关系同时提供服务,Tracker server不存在单点故障。客户端请求Tracker server采用`轮询`方式,如果请求的tracker无法提供服务则换另一个tracker。 - `Storage Server`作用是`文件存储`,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的文件系统而是使用操作系统的文件系统来管理文件。可以将storage称为存储服务器。 Storage集群采用了`分组存储`方式。storage集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。`一个组由一台或多台存储服务器组成,组内的Storage server之间是平等关系,不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的`。一个组的存储容量为该组内的存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。 采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由tracker进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。 - `Group`:文件组,多台Storage Server的集群。上传一个文件到同组内的一台机器上后,FastDFS会将该文件即时同步到同组内的其它所有机器上,起到备份的作用。不同组的服务器,保存的数据不同,而且相互独立,不进行通信。 - `Tracker Cluster`:跟踪服务器的集群,有一组Tracker Server(跟踪服务器)组成。 - `Storage Cluster` :存储集群,有多个Group组成。 ### 上传和下载流程 #### 上传 ![在这里插入图片描述](./readme.assets/28.png) 客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。 ![在这里插入图片描述](./readme.assets/29.png) - `组名`:文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。 - `虚拟磁盘路径`:storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。 - `数据两级目录`:storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。 - `文件名`:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。 #### 下载 ![在这里插入图片描述](./readme.assets/291.png) tracker根据请求的文件路径即文件ID 来快速定义文件。 比如请求下边的文件: ![在这里插入图片描述](./readme.assets/292.png) 1.通过组名tracker能够很快的定位到客户端需要访问的存储服务器组是group1,并选择合适的存储服务器提供客户端访问。 2.存储服务器根据“文件存储虚拟磁盘路径”和“数据文件两级目录”可以很快定位到文件所在目录,并根据文件名找到客户端需要访问的文件。 # 3 Docker 安装 FastDFS 1.首先下载FastDFS文件系统的docker镜像 ```bash docker search fastdfs ``` ![在这里插入图片描述](./readme.assets/1.png) ```bash docker pull delron/fastdfs ``` ![在这里插入图片描述](./readme.assets/2.png) 2.使用docker镜像构建tracker容器(跟踪服务器,起到调度的作用): ```bash docker run -d --network=host --name tracker -v /var/fdfs/tracker:/var/fdfs delron/fastdfs tracker ``` ![在这里插入图片描述](./readme.assets/3.png) 3.使用docker镜像构建storage容器(存储服务器,提供容量和备份服务): ```bash docker run -d --network=host --name storage -e TRACKER_SERVER=120.78.134.111:22122 -v /var/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage ``` ![在这里插入图片描述](./readme.assets/4.png) 上面需要填写你的tracker服务的ip地址,端口默认是22122。 4.此时两个服务都以启动,进行服务的配置。 进入storage容器,到storage的配置文件中配置http访问的端口,配置文件在/etc/fdfs目录下的storage.conf。 ```bash docker exec -it storage /bin/bash ``` ![在这里插入图片描述](./readme.assets/5.png) ```bash vi storage.conf ``` 默认端口是8888,可以不进行更改。 ![在这里插入图片描述](./readme.assets/6.png) 5.配置nginx,在/usr/local/nginx目录下,修改nginx.conf文件 ```bash cd /usr/local/nginx/ ``` ![在这里插入图片描述](./readme.assets/7.png) 配置如下: ![在这里插入图片描述](./readme.assets/8.png) 此处展示了FastDFS文件系统的存储结构,在服务器中storage目录下的data中创建了这么多的文件夹进行文件的存储。 ![在这里插入图片描述](./readme.assets/11.png) 6.测试 将一张照片(1.png)放置在 `/var/fdfs/storage` 目录下,进入storage容器,进入`/var/fdfs`目录,运行下面命令: ```bash /usr/bin/fdfs_upload_file /etc/fdfs/client.conf 1.png ``` 此时将该图片已上传至文件系统,并在执行该语句后返回图片存储的uri: ![在这里插入图片描述](./readme.assets/9.png) 通过url访问 http://120.78.134.111:8888/group1/M00/00/00/rBE6E1yt_KyAcQHQABLxJtmi5AA793.png ,即可查看到图片。 ![在这里插入图片描述](./readme.assets/10.png) # 4 文件微服务开发 这里我们使用javaApi测试文件的上传,java版本的fastdfs-client地址在:[https://github.com/happyfish100/fastdfs-client-java](https://github.com/happyfish100/fastdfs-client-java) ,参考此工程编写测试用例。 下图是课程管理中上传图片处理流程: ![在这里插入图片描述](./readme.assets/31.png) 执行流程如下: 1、管理员进入管理前端,点击上传图片。 2、图片上传至文件系统服务,文件系统请求fastDFS上传文件。 3、文件系统将文件入库,存储到文件系统服务数据库中。 4、文件系统服务向前端返回文件上传结果,如果成功则包括文件的Url路径。 5、课程管理前端请求课程管理进行保存课程图片信息到课程数据库。 6、课程管理服务将课程图片保存在课程数据库。 ## 创建文件系统服务工程 1)MongoDB 数据库搭建 创建 ys_fs 数据库: ![在这里插入图片描述](./readme.assets/32.png) 导入集合: ![在这里插入图片描述](./readme.assets/33.png) 打开窗口,选择第一个 json。 2)工程目录结构 ![在这里插入图片描述](./readme.assets/34.png) 3)Api 接口开发 ① `模型类`: 系统的文件信息(图片、文档等小文件的信息)在mongodb中存储,下边是文件信息的模型类。 ```java /** * 文件实体类 */ @Data @ToString @Document(collection = "filesystem") public class FileSystem { @Id private String fileId; //文件请求路径 private String filePath; //文件大小 private long fileSize; //文件名称 private String fileName; //文件类型 private String fileType; //图片宽度 private int fileWidth; //图片高度 private int fileHeight; //用户id,用于授权 private String userId; //业务key private String businesskey; //业务标签 private String filetag; //文件元信息 private Map metadata; } ``` 说明: fileId:fastDFS返回的文件ID。 filePath:请求fastDFS浏览文件URL。 filetag:文件标签,由于文件系统服务是公共服务,文件系统服务会为使用文件系统服务的子系统分配文件标签,用于标识此文件来自哪个系统。 businesskey:文件系统服务为其它子系统提供的一个业务标识字段,各子系统根据自己的需求去使用,比如:课程管理会在此字段中存储课程id用于标识该图片属于哪个课程。 metadata:文件相关的元信息。 ② `Api 接口`: ```java @Api(value = "文件管理接口", description = "文件管理接口,提供文件的增、删、改、查") public interface FileSystemControllerApi { // 上传文件 @ApiOperation("上传文件接口") public UploadFileResult upload(MultipartFile multipartFile, String filetag, String businesskey, String metadata); } ``` ③ Dao 将文件信息存入数据库,主要存储文件系统中的文件路径。 ④ Service ⑤ Controller ## 测试 使用swagger-ui进行测试: 启动工程,浏览器输入:[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html) ![在这里插入图片描述](./readme.assets/35.png) ## 保存图片 图片上传到文件系统后,其它子系统如果想使用图片可以引用图片的地址,课程管理模块使用图片的方式是将图片地址保存到课程数据库中。 业务流程如下: 1、上传图片到文件系统服务 2、保存图片地址到课程管理服务 在课程管理服务创建保存课程与图片对应关系的表 course_pic。 ![在这里插入图片描述](./readme.assets/36.png) 3、在course_pic保存图片成功后方可查询课程图片信息。 通过查询course_pic表数据则查询到某课程的图片信息。 >注意:课程图片与课程是一一对应的。先查询课程图片,如果为空,则新建对象,保存课程图片。 ## 图片查询 根据课程id查询课程图片 ## 图片删除 课程图片上传成功后,可以重新上传,方法是先删除现有图片再上传新图片。 >注意:此删除只删除课程数据库的课程图片信息,不去删除文件数据库的文件信息及文件系统服务器上的文件,由于课程图片来源于该用户的文件库,所以此图片可能存在多个地方共用的情况,所以要删除文件系统中的文件需要到图片库由用户确认后再删除。