分布式文件系统 fastDFS SpringBoot+FastDFS

分布式文件系统 fastDFS SpringBoot+FastDFS

一.什么是分布式文件系统

1.1 技术应用场景

​ 千峰的扣钉学堂拥有大量优质的视频教程,并且免费提供给用户去下载,文件太多如何高效存储?用户访问量大如何保证下载速度?今天讲解的分布式文件系统将解决这些问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SZAYQKS9-1586337969078)(C:\Users\张大奇\AppData\Roaming\Typora\typora-user-images\1572867804892.png)]

1.2 什么是分布式文件系统

1.2.1 什么是文件系统

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​ **总结:**文件系统是负责管理和存储文件的系统软件,它是操作系统和硬件驱动之间的桥梁,操作系统通过文件系统提供的接口去存取文件,用户通过操作系统访问磁盘上的文件。如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iLjPnfzu-1586337969081)(C:\Users\张大奇\AppData\Roaming\Typora\typora-user-images\1572869121448.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wpjj2X2p-1586337969082)(C:\Users\张大奇\AppData\Roaming\Typora\typora-user-images\1572869155146.png)]

1.2.2 什么是分布式文件系统

​ 分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经满足不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,另外我们还要要做好数据备份、数据安全等。
​ 采用分布式文件系统可以将多个地点的文件系统通过网络连接起来,组成一个文件系统网络,结点之间通过网络进行通信,一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算共同传输。如下图:

好处:
1、一台计算机的文件系统处理能力扩充到多台计算机同时处理。
2、一台计算机挂了还有另外副本计算机提供数据。
3、每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度。

1.3 分布式文件服务提供商

1)阿里的OSS

2)七牛云存储

3)百度云存储

二.什么是fastDFS

2.1 fastDSF介绍

​ FastDFS是用c语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。FastDFS专为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

为什么要使用fastDFS呢?

​ 上边介绍的NFS、GFS都是通用的分布式文件系统,通用的分布式文件系统的优点的是开发体验好,但是系统复杂性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。fastDFS非常适合存储图片等那些小文件,fastDFS不对文件进行分块,所以它就没有分块合并的开销,fastDFS网络通信采用socket,通信速度很快。​

​ 利用主从数据库来实现读写分离,从而分担主数据库的压力。在多个服务器上部署mysql,将其中一台认为主数据库,而其他为从数据库,实现主从同步。其中主数据库负责主动写的操作,而从数据库则只负责主动读的操作(slave从数据库仍然会被动的进行写操作,为了保持数据一致性),这样就可以很大程度上的避免数据丢失的问题,同时也可减少数据库的连接,减轻主数据库的负载。

2.2 fastDSF工作原理

2.2.1 fastDSF架构

FastDFS架构包括 Tracker server和Storage server。客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。所以Tracker server他不上传和下载

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XA0N628k-1586337969084)(C:\Users\张大奇\AppData\Roaming\Typora\typora-user-images\1572869955475.png)]

1)Tracker
​ Tracker Server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。
​ FastDFS集群中的Tracker server可以有多台,Tracker server之间是相互平等关系同时提供服务,Tracker server不存在单点故障。客户端请求Tracker server采用轮询方式,如果请求的tracker无法提供服务则换另一个tracker。
2)Storage
​ Storage Server作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的
​ 文件系统而是使用操作系统的文件系统来管理文件。可以将storage称为存储服务器。
Storage集群采用了分组存储方式。storage集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,组内的Storage server之间是平等关系,不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的。一个组的存储容量为该组内存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是
一致的。
​ 采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由tracker进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。
3)Storage状态收集
​ Storage server会连接集群中所有的Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。

2.2.2 文件上传流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V9uHSoJU-1586337969085)(C:\Users\张大奇\AppData\Roaming\Typora\typora-user-images\1572870168262.png)]

客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。

**组名:**文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。
**虚拟磁盘路径:**storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。
**数据两级目录:**storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
**文件名:**与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

2.2.3 文件下载流程

tracker根据请求的文件路径即文件ID 来快速定义文件。比如请求下边的文件:

1.通过组名tracker能够很快的定位到客户端需要访问的存储服务器组是group1,并选择合适的存储服务器提供客户端访问。
2.存储服务器根据“文件存储虚拟磁盘路径”和“数据文件两级目录”可以很快定位到文件所在目录,并根据文件名找到客户端需要访问的文件。

三.fastDFS单机环境的搭建

1. 工具的准备

建议直接从官方地址下载

libfastcommon
* 从 FastDFS 和 FastDHT 中提取出来的公共 C 函数库,基础环境
* 在安装 FastDFS 前需要先安装这个
* 下载地址址:https://github.com/happyfish100/libfastcommon/releases

FastDFS
* FastDFS 安装包
* 下载地址:https://github.com/happyfish100/fastdfs/releases

fastdfs-nginx-module
* 为了实现通过 HTTP 服务访问和下载 FastDFS 服务器中的文件
* 可以重定向文件链接到源服务器取文件,避免同一组 Storage 服务器同步延迟导致文件访问错误
* 下载地址:https://github.com/happyfish100/fastdfs-nginx-module/releases
* 注:这个目前最新版是 V1.20,不过由于配置时出了点问题,故这里改为使用 V1.16 版本

Nginx
* 实现 HTTP 访问,负载均衡和缓存等功能
* 下载地址:http://nginx.org/en/download.html

2. FastDFS 安装与配置

2.1 libfastcommon

libfastcommon 安装依赖于 gcc 和 perl,故要先安装这两个
# 在线安装 gcc
yum install make cmake gcc gcc-c++
# 在线安装 perl
yum -y install perl*
# 进入 root 目录下
cd /root
# 解压 libfastcommon 压缩包
tar zxvf libfastcommon-1.0.38.tar.gz
# 进入 libfastcommon 文件夹中,编译 libfastcommon 以及安装
cd libfastcommon-1.0.38
./make.sh && ./make.sh install
# 由于 libfastcommon 安装的路径在 /usr/lib64/ 
# 但是 FastDFS 主程序设置的 lib 目录是在 /usr/local/lib,所以需要创建软链接
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so 
ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so 
ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so 
ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so

2.2 安装 FastDFS

cd /root
# 解压 FastDFS 压缩包,编译以及安装
tar zxvf fastdfs-5.11.tar.gz
cd fastdfs-5.11
./make.sh && ./make.sh install

2.3 配置 Tracker

# 创建 Tracker 的存储日志和数据的根目录
mkdir -p /home/fastdfs/tracker
cd /etc/fdfs
cp tracker.conf.sample tracker.conf
# 配置 tracker.conf
vi tracker.conf

在这里,tracker.conf 只是修改一下 Tracker 存储日志和数据的路径

# 启用配置文件(默认为 false,表示启用配置文件)
disabled=false
# Tracker 服务端口(默认为 22122)
port=22122
# 存储日志和数据的根目录
base_path=/home/fastdfs/tracker

2.4 配置 Storage

# 创建 Storage 的存储日志和数据的根目录
mkdir -p /home/fastdfs/storage
cd /etc/fdfs
cp storage.conf.sample storage.conf
# 配置 storage.conf
vi storage.conf

在这里,storage.conf 只是修改一下 storage 存储日志和数据的路径

# 启用配置文件(默认为 false,表示启用配置文件)
disabled=false
# Storage 服务端口(默认为 23000)
port=23000
# 数据和日志文件存储根目录
base_path=/home/fastdfs/storage
# 存储路径,访问时路径为 M00
# store_path1 则为 M01,以此递增到 M99(如果配置了多个存储目录的话,这里只指定 1 个)
store_path0=/home/fastdfs/storage
# Tracker 服务器 IP 地址和端口,单机搭建时也不要写 127.0.0.1
# tracker_server 可以多次出现,如果有多个,则配置多个
tracker_server=192.168.229.166:22122
# 设置 HTTP 访问文件的端口。这个配置已经不用配置了,配置了也没什么用
# 这也是为何 Storage 服务器需要 Nginx 来提供 HTTP 访问的原因
http.server_port=8888

2.5 启动 Tracker 和 Storage 服务

# 启动 Tracker 服务
# 其它操作则把 start 改为 stop、restart、reload、status 即可。Storage 服务相同
/etc/init.d/fdfs_trackerd start
# 启动 Storage 服务
/etc/init.d/fdfs_storaged start
# 可以通过 fdfs_monitor 查看集群的情况
# 查看 Storage 是否已经注册到 Tracker 服务器中
# 当查看到 ip_addr = 192.168.229.166 (localhost.localdomain)  ACTIVE
# ACTIVE 表示成功
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf

2.6 测试上传文件

# 修改 Tracker 服务器客户端配置文件
cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf
vi /etc/fdfs/client.conf
client.conf 中修改 base_path 和 Tracker 服务器的 IP 地址与端口号即可

# 存储日志文件的基本路径
base_path=/home/fastdfs/tracker
# Tracker 服务器 IP 地址与端口号
tracker_server=192.168.229.166:22122
拷贝一张图片到 root 目录下
# 存储到 FastDFS 服务器中
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /root/test.png

当返回文件 ID 号,如 group1/M00/00/00/wKjlpltF-K-AZQQsAABhhboA1Kk469.png 则表示上传成功

以上则完成了 FastDFS 的安装与配置,可以使用 api 来完成文件的上传、同步和下载。

当然,接下来我们还会安装 Nginx。目的如下:

Storage 安装 Nginx,为了提供 http 的访问和下载服务,同时解决 group 中 Storage 服务器的同步延迟问题
Tracker 安装 Nginx,主要是为了提供 http 访问的反向代理、负载均衡以及缓存服务

3. 安装与配置 Nginx

# 安装 GCC
yum install -y gcc-c++ 
# 安装 PCRE
yum install -y pcre pcre-devel
# 安装 zlib
yum install -y zlib zlib-devel
# 安装 openssl
yum install -y openssl openssl-devel

# 以上命令也可以使用一条命令来安装
yum install gcc gcc-c++ make automake autoconf libtool pcre* zlib openssl openssl-devel

3.2 配置 fastdfs-nginx-module 模块

** 所有 storage 节点都要安装 fastdfs-nginx-module 模块**

这里我使用的是 1.16 版本的 fastdfs-nginx-module。使用最新版本(1.20)时,你们自己百度,

cd /root
# 解压 fastdfs-nginx-module 模块
tar zxvf fastdfs-nginx-module_v1.16.tar.gz
# 修改 fastdfs-nginx-module 的 config 配置文件
vi fastdfs-nginx-module/src/config

将 CORE_INCS="$CORE_INCS /usr/local/include/fastdfs /usr/local/include/fastcommon/"
中的 local 去掉,修改为 CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"

编译安装 nginx
cd /root
tar zxvf nginx-1.15.1.tar.gz
cd nginx-1.15.1
# 给 Nginx 添加 fastdfs-nginx-module 模块
./configure --add-module=/root/fastdfs-nginx-module/src
make && make install

fastdfs-nginx-module 和 FastDFS 配置文件修改
# 复制 FastDFS 的部分配置文件到 /etc/fdfs
cd /root/fastdfs-5.11/conf/
cp http.conf mime.types /etc/fdfs/
# 复制 fastdfs-nginx-module 源码中的配置文件到  /etc/fdfs 中
cp /root/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/
vi /etc/fdfs/mod_fastdfs.conf

# Tracker 服务器IP和端口修改
tracker_server=192.168.229.166:22122
# url 中是否包含 group 名称,改为 true,包含 group
url_have_group_name = true
# 配置 Storage 信息,修改 store_path0 的信息
store_path0=/home/fastdfs/storage
# 其它的一般默认即可,例如
base_path=/tmp
group_name=group1 
storage_server_port=23000 
store_path_count=1

配置 Nginx
vi /usr/local/nginx/conf/nginx.conf
# 配置为支持 group0-group9,以及 M00-M99,以便于以后扩容
# 本单机环境下其实配置为 ~/group1/M00 就可以了
location ~/group([0-9])/M([0-9])([0-9]) {
    ngx_fastdfs_module;
}
启动 Nginx
# 启动 Nginx
/usr/local/nginx/sbin/nginx
# 重启 Nginx
/usr/local/nginx/sbin/nginx -s reload
# 停止 Nginx
/usr/local/nginx/sbin/nginx -s stop

四.文件上传下载测试

4.1 搭建环境

这里我们使用javaApi测试文件的上传。
java版本的fastdfs-client地址在:https://github.com/happyfish100/fastdfs-client-java,参考此工程编写测试用例。

1)创建maven工程
2)添加依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring‐boot‐starter‐web</artifactId>
    </dependency>
    <!‐‐ https://mvnrepository.com/artifact/net.oschina.zcx7878/fastdfs‐client‐java ‐‐>
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs‐client‐java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
 <!--依赖大部分情况下会出现无法导入的情况:
 	https://www.cnblogs.com/mlq2017/p/10076084.html
 	她的截图有问题,需要进入到文件内部然后在 mvn clean install
 	然后我的fastdfs‐client‐java没在net.oschina.zcx7878下,反而在org.csource.下面,所以建议仓库全局搜索寻找
 	
 	我的就变成了这样
 	<dependency>
            <groupId>org.csource</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27-SNAPSHOT</version>
    </dependency>
 	
 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring‐boot‐starter‐test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons‐io</artifactId>
        <version>1.3.2</version>
    </dependency>
</dependencies>

3) 配置 文件

在classpath:config下创建fastdfs-client.properties文件


## fastdfs-client.properties
#连接的超时时间
fastdfs.connect_timeout_in_seconds = 5
#网络的超时时间
fastdfs.network_timeout_in_seconds = 30
#编码方式
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80

#tracker_servers服务器的地址
fastdfs.tracker_servers = 122.51.42.29:22122

4.2 上传文件

//测试文件的上传
    @Test
    public void testUpload(){
        //通过fastDFS的client代码访问tracker和storage

        try {
            //加载fastDFS配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
            System.out.println("charset=" + ClientGlobal.g_charset);


            //创建tracker的客户端
            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;

            //定义storage的客户端
            StorageClient1 client = new StorageClient1(trackerServer, storageServer);


            //文件元信息
            NameValuePair[] metaList = new NameValuePair[1];
            metaList[0] = new NameValuePair("fileName", "2.png");


            //最关键   执行上传
            String fileId = client.upload_file1("C:\\Users\\张大奇\\Desktop\\2.png", "png", metaList);
            System.out.println("upload success. file id is: " + fileId);

//            int i = 0;
//            while (i++ < 10) {
//                byte[] result = client.download_file1(fileId);
//                System.out.println(i + ", download result is: " + result.length);
//            }
            //关闭tracker server的连接
            trackerServer.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

4.3 查询上传的文件

//查询 文件上传
    @Test
    public void testQuery(){
        try {
            //加载fastDFS配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
            System.out.println("charset=" + ClientGlobal.g_charset);


            //创建tracker的客户端
            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;

            //定义storage的客户端
            StorageClient1 client = new StorageClient1(trackerServer, storageServer);

            //查询的两种方法
            FileInfo group1 = client.query_file_info("group1","M00/00/02/rBEAEF3WWTuAIRiNAAC8Qze7IA0632.png");
            FileInfo fileInfo = client.query_file_info1("group1/M00/00/02/rBEAEF3WWTuAIRiNAAC8Qze7IA0632.png");
            System.out.println(group1);
            System.out.println("fileInfo = " + fileInfo);

            //查询文件元信息
            NameValuePair[] metadata1 = client.get_metadata1("group1/M00/00/02/rBEAEF3WWTuAIRiNAAC8Qze7IA0632.png");
            System.out.println(metadata1);
//            int i = 0;
//            while (i++ < 10) {
//                byte[] result = client.download_file1(fileId);
//                System.out.println(i + ", download result is: " + result.length);
//            }
            //关闭tracker server的连接
            trackerServer.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

4.4 下载文件

 //下载文件
    @Test
    public void testDownload(){
        try {
            //加载fastDFS配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
            System.out.println("charset=" + ClientGlobal.g_charset);


            //创建tracker的客户端
            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;

            //定义storage的客户端
            StorageClient1 client = new StorageClient1(trackerServer, storageServer);

            byte[] bytes = client.download_file1("group1/M00/00/00/rBEAEF3K3VSAZBlEAAC9qcc0Gck587_big.jpg");

            File file =new File("d:/test/小姐姐.png");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);

            fileOutputStream.close();
//            int i = 0;
//            while (i++ < 10) {
//                byte[] result = client.download_file1(fileId);
//                System.out.println(i + ", download result is: " + result.length);
//            }
            //关闭tracker server的连接
            trackerServer.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
ile("d:/test/小姐姐.png");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);

            fileOutputStream.close();
//            int i = 0;
//            while (i++ < 10) {
//                byte[] result = client.download_file1(fileId);
//                System.out.println(i + ", download result is: " + result.length);
//            }
            //关闭tracker server的连接
            trackerServer.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值