暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

微服务专栏(十五):基于FastDFS实现文件存储

修电脑的杂货店 2021-12-08
898

 散步促进我的思想。我的身体必须不断运动,脑筋才会开动起来。 —— 卢梭


1、前言

为什么需要使用分布式系统?做个大型项目的基本上都接触过分布式文件系统,我给大家举例子说清楚我们为什么需要使用分布式文件系统。

平时我们的文件如何存储呢?存在什么地方呢?据我真实接触过的项目,相信很多同学也接触过类似的项目,大概分以下几种情况来存储文件。

  • 方案一:把文件存储到数据库的 blob 字段里面

  • 方案二:把文件存储到项目的某个目录下,也就是 Tomcat 下面

  • 方案三:把文件存储到服务器的非 Tomcat 目录下,然后再通过 Tomcat、Nginx 做文件映射

  • 方案四:文件上传到 Ftp,再然后通过 Tomcat、Nginx 做文件映射,当然这种模式相比前三种来说,还是可以接受的

这四种模式我相信很多人都接触过,甚至当初自己就是这么干的,如果你还是停留在这四种模式上,那么希望本章内容对你能有一定的帮助。那么分析一下,以上四种模式的所存在的弊端到底是什么,为什么不提倡这么做。

方案一:存储数据库的弊端

  • 把文件存储到数据库将是灾难性的,严重占用数据库的存储空间,数据库很容易就会爆满;

  • 影响数据库的查询性能,试想一如果 100 个人同时下载 10g 的文件,也就是从数据库读取文件,将是什么样的后果;

  • 同时数据库的备份和还原都非常的麻烦,浪费很长的时间;

  • 无法横向扩展容量,数据库满了,则再也无法上传文件了。

方案二:存储把文件存储到项目的某个目录下的弊端

  • 容易丢失文件,项目重新部署,很容易就丢失文件

  • 无法支持集群

  • 无法横向扩展容量,如果服务器磁盘满了,则再也无法上传文件了

方案三:把文件存储到服务器的非 Tomcat 目录下的弊端

  • 无法支持集群

  • 无法横向扩展容量,如果服务器磁盘满了,则再也无法上传文件了

方案四:文件上传到 Ftp 的弊端

  • 这种模式支持集群,但是还是有弊端

  • 无法横向扩展容量,如果服务器磁盘满了,则再也无法上传文件了

  • 不支持高级特性,比如:副本冗余,负载均衡等;

这里,重点讲解一下无法支持集群的大概意思,具体如下图所示:

通过上面的架构图,大家应该能理解不使用分布式文件系统所存在的缺陷了,因此我们很有必要学习和使用分布式文件系统。它的好处很明显,给大家总结一下。

  • 第一:动态扩展服务器的容量,不需要一台特别牛逼的超级计算机,可以由若干普通服务器组成一个集群即可。

  • 第二:分布式文件系统支持冗余备份,或者叫副本冗余;就是把一份文件在不同服务器都备份一份,好处如下:

    • 容灾:如果其中一台服务器宕机了,其他节点还能正常对外提供服务,不至于整个集群瘫痪。

    • 负载:一个文件在不同的服务器都有备份,那么当用户下载这份文件时,可以从不同的服务器进行下载。

那么,市面上主流的分布式文件系统到底有哪些呢?

  • 常见的应用级别(不是系统级别)的文件系统有:GFS、HDFS、Lustre 、Ceph 、GridFS 、mogileFS、TFS、FastDFS、NFS、MFS。但是目前比较常用的主要是阿里开源的 FastDFS、Hadoop 生态里的 HDFS,FastDFS 主要应用电商行业比较多,用于存储商品的图片;HDFS 主要运用大数据领域比较多。

FastDFS和HDFS的简单对比:

类型FastDFSHDFS
开发语言c语言Java语言
切块不支持支持
文件大小500M以内不限制
领域一般用于电商领域一般用于大数据领域
社区及API完善的API,国内用户量比较大完善的API,用户群体比较大
性能读写速度比较快读写速度比较慢

既然FastDFS和 HDFS 都是主流,那么我们应该如何选择呢,带大家从以下几个方面来做选择。

  • 第一:FastDFS 不支持切块,大于 500M 的文件则读写性能比较差,但是 500M 以下性能非常的高。

  • 第二:HDFS 支持切块,无法高效的对大量小文件进行存储,原因是占用 NameNode 大量的内存来存储文件的目录和块信息,小文件存储的寻址时间会超过读取时间;不支持并发写入,一个文件只能有一个写,不允许多个线程同时写。

  • 那么由此,可知,如果想要速度快则选择 FastDFS,如果想上传大文件则选择 HDFS。由于我们的网盘是进行切块上传和切块存储的,单个切块不大(标准是5M),因此选择 FastDFS 是非常的合适的。


2、FastDFS的原理分析

FastDFS的架构图


FastDFS流程图

根据上面两张图,我们可以清晰的知道 FastDFS 主要有两个部分组成,分别是 Tracker Server 和 Storage Server,其中 Tracker Server 是追踪服务,也就是管理节点,专门管理文件的存储的地址信息的,同时它会和 Storage Server 保持心跳;Storage Server 是存储服务,真实的存储文件的数据。

文件上传流程剖析:

  • 第一步,客户端先去 Tracker Server 获取上传的服务器信息,Tracker Server 会根据那个 Storage 节点的文件数量比较少,哪个 Storage 比较空闲等,返回具体的 Storage Server 的服务器 IP 和 Port 信息给客户端。

  • 第二步,客户端再连接具体的 Storage Server 上传文件

文件下载流程剖析:

  • 第一步,根据文件的信息去 Tracker Server 查询文件存储的服务器信息,Tracker Server 会查询文件所在服务器,由于文件会存在副本,因此通过负载策略把 Storage Server 的服务器 IP 和 Port 信息返回给客户端。

  • 第二步,客户端再连接具体的Storage Server下载文件

通过上传、下载两个流程的分析,大家对 Storage Server 和 Tracker Server 的作用应该都能理解了吧。


3、FastDFS的安装

FastDFS 的安装步骤还是比较繁琐的,它主要包括五个部分的安装,依赖的基础环境、libfastcommon、FastDFS 的 tracker 和 storage、fastdfs-nginx-module(非必须)的安装。


3.1、基础环境

yum install make cmake gcc gcc-c++


3.2、libfastcommon

#1.下载:
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz

#2.解压:
tar -zxvf V1.0.7.tar.gz

#3.进入:
cd libfastcommon-1.0.7

#4.编译:
./make.sh

#5.安装:
./make.sh install

#6.拷贝文件
cp /usr/lib64/libfastcommon.so /usr/lib

#原因:libfastcommon安装好之后自动将库文件拷贝至/usr/lib64下,由于FastDFS程序引用/usr/lib目录,所以需要将/usr/lib64下的库文件拷贝至/usr/lib下




3.3、FastDFS-Tracker

1、Tracker的安装

#1.新建目录
mkdir -p /usr/local/java/fastdfs/trackerdata

#2.解压
wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
tar -zxvf V5.05.tar.gz -C /usr/local/java/fastdfs

#3.进入目录
cd /usr/local/java/fastdfs/fastdfs-5.05

#4.编译
./make.sh

#5.安装
./make.sh install

#6.安装自动生成/etc/fdfs目录,需要把文件拷贝到里面
cd /usr/local/java/fastdfs/fastdfs-5.05/conf
cp * /etc/fdfs

#7.进入目录
cd /etc/fdfs

#8.配置tracker.conf
vim /etc/fdfs/tracker.conf
base_path=/usr/local/java/fastdfs/trackerdata #软件运行产生的日志和数据

2、Tracker的配置

#进入目录
cd /etc/init.d

#创建文件夹
mkdir /usr/local/fdfs

#拷贝文件
cd /usr/local/java/fastdfs/fastdfs-5.05
cp stop.sh restart.sh /usr/local/fdfs/

#编辑(核心,一共7个地方需要修改)
vim fdfs_trackerd
PRG=/usr/bin/fdfs_trackerd #改成/usr/bin
stop.sh和restart.sh的路径

3、Tracker的启动

#启动(初次成功启动,会在/usr/local/java/fastdfs/trackerdata目录下创建data、logs两个目录)
/etc/init.d/fdfs_trackerd start

#状态:
ps -ef | grep fdfs

#停止:
/etc/init.d/fdfs_trackerd stop


3.4、FastDFS-Storage

提示:tracker和storage可以在安装在同一台机器上,也可以安装在不同机器上;这里主要是讲解分别安装在不同的机器上面。

1、Storage的安装

#1.新建目录
mkdir -p /usr/local/java/fastdfs/storedata

#2.解压
wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
tar -zxvf V5.05.tar.gz -C /usr/local/java/fastdfs

#3.进入目录
cd /usr/local/java/fastdfs/fastdfs-5.05

#4.编译
./make.sh

#5.安装
./make.sh install

#6.安装自动生成/etc/fdfs目录,需要把文件拷贝到里面
cd /usr/local/java/fastdfs/fastdfs-5.05/conf
cp * /etc/fdfs

#7.进入目录
cd /etc/fdfs

#8.配置storage.conf
vim /etc/fdfs/storage.conf
base_path=/usr/local/java/fastdfs/trackerdata #软件运行产生的日志和数据
store_path0=/usr/local/java/fastdfs/storedata #文件真实存储目录
tracker_server=192.168.1.8:22122 #IP是Tracker的IP


2、Storage的配置

#进入目录
cd /etc/init.d

#创建文件夹
mkdir /usr/local/fdfs

#拷贝文件
cd /usr/local/java/fastdfs/fastdfs-5.05
cp stop.sh restart.sh /usr/local/fdfs/

#编辑(核心,一共7个地方需要修改)
vim fdfs_storaged
PRG=/usr/bin/fdfs_storaged #改成/usr/bin
stop.sh和restart.sh的路径

3、Storage的启动

#启动:
/etc/init.d/fdfs_storaged start

#状态:
ps -ef | grep fdfs

#停止:
/etc/init.d/fdfs_storaged stop


4、FastDFS核心讲解

1、端口说明

  • Tracker 的端口,22122

  • Storage 需要连接 Tracker,保持心跳,方便 Tracker 管理 Storage

2、文件真实位置

  • store_path0=/usr/local/java/fastdfs/storedata #文件真实存储目录

  • Storage Server 安装好的时候,默认会生成很多的文件夹,自己可以进入目录查看

3、组的概念(核心)

FastDFS 对 Storage 进行分组,组名称相同,则存储的文件相同;组名称不同,则存储的文件不同。这句话可能光从字面意思理解会比较难理解,下面具体讲解。

/etc/fdfs/tracker.conf 里面的核心配置,具体如下:

store_lookup=2      #0轮询、1指定group、2剩余最多的group
store_group=group2 #如果store_lookup=1的时候,指定
store_server=0 #指定服务器(一个group里面有多个server)

  • store_lookup,表示文件上传时,tracker 寻址具体 group 的策略

  • store_group,指定组名,如果 store_lookup=1 时生效

  • 特殊业务场景使用,比如实现不同区域的用户上传的文件保存到其对应区域的服务器

参考下面的架构图分析:

  • 第一:每个红色框是一个组,FastDFS 集群可以有很多的组

  • 第二:每个组里面会有很多的 Storage Server 存储节点,同一个组下面的 Storage 之间会做文件同步,目的就是对文件生成副本,可以进行容错、负载等等。

  • 第三:不同的组存储的文件不一样,如果集群容量满了,可以通过扩展一个组来进行集群容量的扩展

  • 总结,分析到这里,大家应该都理解 FastDFS 集群的含义了吧

思考:通过上面的分析,那么FastDFS扩展集群有几种类型呢?

**解答:**会有两种模式

  • 给某个组新增 Storage 节点,做副本备份

  • 扩展一个组,扩展集群整体总容量


5、FastDFS快速入门

第一步:配置 Maven 坐标

<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>fastdfs-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>

第二步:配置 application.properties

#tracker地址
fdfs.tracker-list=192.168.1.8:22122
#连接超时时间
fdfs.connect-timeout=10000
#上传超时时间
fdfs.so-timeout=3000

第三步:上传代码

@Autowired
private FastFileStorageClient storageClient;

@Override
public String upload(String group,byte[] bytes, String fileName) {
String fileExtName = FilenameUtils.getExtension(fileName);
StorePath sp=storageClient.uploadFile(group, bytes, fileExtName);
return sp.getFullPath();
}

第四步:下载代码

@Autowired
private FastFileStorageClient storageClient;

@Override
public byte[] download(String group,String path) {
byte[] bytes=storageClient.downloadFile(group,path);
return bytes;
}

第五步:删除代码

@Autowired
private FastFileStorageClient storageClient;

@Override
public void delete(String path) {
storageClient.deleteFile(path);
}


6、网盘系统集成

第一步:首先在对应工程新建具体的类文件

utils-filestore			(文件存储组件工程)
|-- com.micro.store.service
| |-- StoreService.java (定义一个接口)
|-- com.micro.store.service.impl
| |-- StoreServiceFastDFS.java (实现类)
| |-- StoreServiceHDFS.java (实现类)
|-- com.micro.store.context
| |-- StoreContext.java (策略类)


项目结构核心分析:

  • 我们不能写死说只用 FastDFS 作为我们的分布式文件存储,如果万一哪天领导说要换成 HDFS、换成 TFS 呢?所以我们需要使用策略模式去把它做灵活了,底层怎么切换,都不会影响到我们上层业务。

  • 那么,我们为什么把文件存储独立一个工程呢?为什么不在 Service 工程里面编写代码呢?文件存储这种是比较常用的功能,很多系统都会用的到的,那么我们尽量封装起来,哪个项目用到直接导入 jar 就能使用,而不是单纯的封装工具类。

第二步:集成(坐标)

在 netdisk-service-provider 工程的 pom.xml 导入坐标

<dependency>
<groupId>com.micro</groupId>
<artifactId>utils-filestore</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

第三步:策略模式的实现

思考:使用策略模式去调用底层的分布式文件系统,那么如何实现策略模式呢?

@Component
public class StoreContext{
@Autowire
private SpringContentUtils springContentUtils;

@NacosValue("${uploadtype}")
private String uploadtype; //核心

//上传
public String upload(String group,byte[] bytes,String fileName){
//核心,根据uploadtype去Spring容器查询具体实现类
Object obj=springContentUtils.getBean(uploadtype);
if(obj!=null){
StoreService storeService=(StoreService)obj;
storeService.upload(group,bytes,fileName);
}
}
//其他接口省略了
}

  • 上传类型
    的标识放到 Nacos 配置中心,这样的话我们切换底层,只需要在 Nacos 后台修改,项目都不用启动,非常的灵活。

第四步:策略类的调用

@Component
public class FileServiceImpl implements FileService{
@Autowire
private StoreContext storeContext;

public void upload(String group,byte[] bytes,String fileName){
storeContext.upload(group,bytes,fileName);
}
}


7、小结

本章节内容还是比较核心的,主要讲解了不用分布式文件系统所存在的缺点(重点理解)、主流分布式文件系统的比较、FastDFS 的原理、安装、使用、以及最后使用策略模式集成 FastDFS;大家尽量按照我上面的步骤搭建一遍 FastDFS,相对来说 FastDFS 的安装会比其他软安装复杂很多;

纸上得来终觉浅,绝知此事要coding...

文章转载自修电脑的杂货店,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论