FastDFS图片服务器

前言

最初在学习java的时候,学习文件的上传下载,都是将文件上传到项目上的,这样时间一久,项目就会非常的臃肿,后来了解到FastDFS,从开始搭建到使用Java程序上传文件到FastDFS服务器,有了一个初步的了解,觉得有必要记录一下。

1、FastDFS介绍

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

2、为什么使用FastDFS

fastDFS非常适合存储图片等那些小文件,fastDFS不对文件进行分块,所以它就没有分块合并的开销,fastDFS网络通信采用socket,通信速度很快。所以如果要专门存储图片的话,使用FastDFS是个非常不错的选择。

3、FastDFS工作原理

(1)架构

FastDFS架构包括 Tracker server和Storage server。客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。
FastDFS图片服务器
(2)Tracker

Tracker Server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。FastDFS集群中的Tracker server可以有多台,Tracker server之间是相互平等关系同时提供服务,Tracker server不存在单点故障。客户端请求Tracker server采用轮询方式,如果请求的tracker无法提供服务则换另一个tracker。

(3)Storage

Storage Server作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的文件系统而是使用操作系统的文件系统来管理文件。可以将storage称为存储服务器。

Storage集群采用了分组存储方式。storage集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,组内的Storage server之间是平等关系,不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的。一个组的存储容量为该组内的存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。

采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由tracker进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。

(4)Storage状态收集

Storage server会连接集群中所有的Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。

(5)文件的上传流程

FastDFS图片服务器

  • storage定时向tracker上传状态信息
  • Client向tracker上传连接请求
  • tracker查询可用的storage
  • tracker向client返回信息(storage的ip和端口)
  • client向storage上传文件(file content和metadata)
  • storage生成一个file_id
  • storage将上传内容写入磁盘
  • storage向client返回file_id(文件名和文件存储的路径信息)
  • client完成文件信息的存储

(6)文件下载流程
FastDFS图片服务器

  • storage定时向tracker上传状态信息
  • client向tracker提交下载连接请求
  • tracker查询可用的storage
  • tracker向client返回信息(storage的ip和端口)
  • client向storage提交信息file_id(组名、路径、文件名)
  • storage查看文件
  • storage返回file_content给client

4、搭建FastDFS

FastDFS是只支持Linux的,在Linux系统上搭建,这里用的是阿里云的centOS7.0版本。先用PUTTY连上我的阿里云主机:
FastDFS图片服务器
(1)建立目录
FastDFS图片服务器
我在根路径下的usr/local文件夹中建立了一个空的文件夹fastdfs,我待会儿下载的包会放在这里。

(2)下载

cd fastdfs进入包中,运行命令进行下载:

wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz
FastDFS图片服务器
下载完毕,查看fastdfs文件夹:
FastDFS图片服务器
下载的压缩包保存在这里。

(3)解压

运行命令进行解压:tar -zxvf V1.0.7.tar.gz
FastDFS图片服务器
可以查看解压后的文件夹:
FastDFS图片服务器
(4)编译和安装

进入解压后的文件夹,然后运行命令:
./make.sh
./make.sh install
进行安装和编译。安装好之后cd /usr/lib64进入lib64目录,查看是否有
libfastcommon.so。
FastDFS图片服务器
那么安装和编译就成功了。

(5)创建软链接

安装好之后可以看到 libfastcommon.so 安装到了/usr/lib64/libfastcommon.so,但是FastDFS主程序设置的lib目录是/usr/local/lib,所以需要创建软链接,也可以自己创建/usr/local/lib,然后把libfastcommon.so复制到期目录下,但是推荐创建软连接。如下4条命令:
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
FastDFS图片服务器
(6)下载FastDFS

进入开始创建的文件夹,然后运行命令下载:
wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
FastDFS图片服务器
查看:
FastDFS图片服务器
(7)解压

运行命令解压刚下载的文件:
tar -zxvf V5.05.tar.gz
FastDFS图片服务器
解压得到如图圈出的文件夹。

(8)安装和编译

进入解压后的文件夹,运行命令:
./make.sh
./make.sh install
进行编译和安装。

(9)查看配置文件

编译和安装完成之后执行命令:cd /etc/fdfs进入fdfs目录,然后ls命令查看:
FastDFS图片服务器
可以看到有3个配置文件:
client.conf.sample
storage.conf.sample
tracker.conf.sample
待会儿会配置。

(10)查看bin目录
执行命令:cd /usr/bin进入bin目录,会看到bin目录下生成了许多文件,都是以fdfs_开头的。
FastDFS图片服务器
(11)创建软链接

修改命令路径,由于FastDFS 服务脚本设置的bin目录是 /usr/local/bin, 但实际命令安装在 /usr/bin/ 下,所以需要创建软链接:
ln -s /usr/bin/fdfs_trackerd /usr/local/bin
ln -s /usr/bin/fdfs_storaged /usr/local/bin
ln -s /usr/bin/stop.sh /usr/local/bin
ln -s /usr/bin/restart.sh /usr/local/bin
FastDFS图片服务器
(12)配置tracker

cd /进入根目录,然后mkdir fastdfs在根目录下创建新的文件夹fastdfs,进入新文件夹:cd /fastdfs,然后创建四个新的文件夹:mkdir tracker、mkdir storage、mkdir file、mkdir client。
FastDFS图片服务器
tracker是FastDFS跟踪器(Tracker),比较重要。这里进行配置,先进入目录cd /etc/fdfs,然后命令:
cp tracker.conf.sample tracker.conf复制一份tracker的配置文件重命名为tracker.conf。
FastDFS图片服务器
接下来编辑这个配置文件,命令vim tracker.conf修改配置文件:

FastDFS图片服务器
标记的地方是我添加或修改的。

比较重要的配置信息如下:
#表示配置文件是否生效,false为和生效
disabled=false
#提供服务的端口
port=22122
#http端口
http.server_port=80
#Tracker数据和日志的目录地址
base_path=/fastdfs/tracker

(13)启动tracker

service fdfs_trackerd start启动,然后netstat -unltp|grep fdfs查看是启动成功。
FastDFS图片服务器
如图显示说明22122端口启动成功了。当tracker server 启动成功后,会在创建的base_path目录下创建data和log两个目录,分别存放数据和日志。
FastDFS图片服务器

(14)配置storage

进入 /etc/fdfs 目录,复制 FastDFS 存储器样例配置文件 storage.conf.sample,并重命名为 storage.conf,命令:cp storage.conf.sample storage.conf
FastDFS图片服务器
vim storage.conf命令修改这个文件:
FastDFS图片服务器
FastDFS图片服务器
标记的地方是我添加或修改的。

比较重要的配置信息如下:
#配置文件是否生效
disabled=false
#指定此storage server所在组(卷)
group_name=group1
#指定storage server的端口服务
port=23000
#指定storage的数据和日志目录
base_path=/fastdfs/storage
#配置store_path_count路径,索引号基于0
store_path0=/fastdfs/file
#tracker_server的列表,会主动连接到tracker_server
tracker_server=47.99.206.82:22122(外网ip:端口)
#HTTP的访问端口
http.server_port=80

(15)启动storage

service fdfs_storaged start启动storage服务,然后netstat -unltp|grep fdfs查看是否启动成功。
FastDFS图片服务器
可以看到23000端口启动成功了,storage服务启动后,cd /fastdfs/storage进入目录,然后ls查看,会生成2个文件夹data和log,存放数据和日志文件。
FastDFS图片服务器
(16)查看storage和tracker是否在通信
运行命令:
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
FastDFS图片服务器
出现如下界面,说明tracker和storage端口是通信成功的。

(17)配置client.conf

cd /etc/fdfs进入目录,然后
cp client.conf.sample client.conf复制一个文件。
FastDFS图片服务器
vim client.conf编辑client的配置文件:
FastDFS图片服务器
标记的地方是我修改的地方。

重要配置信息如下:
#client的数据和日志记录
base_path=/fastdfs/client
#tracker端口
tracker_server=47.99.206.82:22122

(18)开放端口

使用阿里云的ECS实例,一定要配置安全组开放端口:
FastDFS图片服务器
FastDFS图片服务器
刚才配置的22122端口、23000端口、80端口一定要开放,否则会出问题。

(19)测试图片上传

cd /进入根目录,然后mkdir data建立一个新的文件夹,在该文件夹下下载一张图片:
FastDFS图片服务器
现在测试传这张图片。
cd /data进入data文件夹,执行命名:
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf t01e69f5dc79f806791.jpg
FastDFS图片服务器
会返回一个图片的保存路径:
group1/M00/00/00/rBwObF_l5OuAIZ8ZAABiQ6LjEdA231.jpg
说明图片上传成功了。

以上步骤已经完成了fastdfs的搭建,然后需要安装Nginx来提供访问。

5、搭建Nginx

(1)前置环境
安装nginx前需要一些前置环境。运行以下命令:
yum install gcc-c++
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel

FastDFS图片服务器
FastDFS图片服务器
FastDFS图片服务器
FastDFS图片服务器
前置环境以及准备好了,下面准备安装Nginx。

(2)下载Nginx

cd /usr/local进入目录,然后mkdir nginx建立一个新的文件夹:
FastDFS图片服务器
然后cd nginx进入文件夹,下载命令:
wget -c https://nginx.org/download/nginx-1.12.1.tar.gz

FastDFS图片服务器
下载完成后多了一个压缩文件:
FastDFS图片服务器
(3)解压

运行命令:tar -zxvf nginx-1.12.1.tar.gz会得到一个文件夹nginx-1.12.1。
FastDFS图片服务器
(4)配置

cd nginx-1.12.1进入解压后的文件夹内,执行命令:
./configure
使用nginx的默认配置。
FastDFS图片服务器
(5)安装和编译

进入解压后的文件夹,运行命令:
make
make install
完成编译和安装。
FastDFS图片服务器
FastDFS图片服务器
(6)修改配置文件

命令cd /usr/local/nginx/conf进入目录,ls查看:
FastDFS图片服务器
vim nginx.conf修改配置文件:
FastDFS图片服务器
标记的地方是我添加的。

(7)启动Nginx

cd /usr/local/nginx/sbin/进入目录,然后./nginx 启动nginx。
查看是否启动成功,运行命令:/usr/local/nginx/sbin/nginx -V可以查看nginx的版本及模块。
FastDFS图片服务器
nginx默认是80端口,运行命令: netstat -ntulp |grep 80查看:
FastDFS图片服务器
说明启动成功。

(8)测试
浏览器中输入:
http://47.114.175.9/group1/M00/00/00/rBwObF_l5OuAIZ8ZAABiQ6LjEdA231.jpg

主机名+刚才上传图片返回的路径。
FastDFS图片服务器
可以正常访问,那么Nginx+FastDFS搭建的图片服务器到这里就全部完成了。下面会用Java程序进行测试。

6、Java程序测试

(1)pom依赖

<dependency>
    <groupId>net.oschina.zcx7878</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27.0.0</version>
</dependency>

(2)配置文件
FastDFS图片服务器
在项目的resources下建了一个config目录,目录下有一个fastdfs-client.properties配置文件,配置信息如下:

## 连接超时时间
fastdfs.connect_timeout_in_seconds = 5
## 网络超时时间
fastdfs.network_timeout_in_seconds = 30
## 编码格式
fastdfs.charset = UTF-8
## tracker地址
fastdfs.tracker_servers = 47.114.175.9:22122

也可以将这些信息整合到springboot的配置文件application.yml中,这里没有这样,配置在了单独的配置文件里。

(3)测试

我直接在测试包中写了:

@SpringBootTest
public class TestFastdfs {
    
    //测试图片上传
    @Test
    public void testUploadPic() {
        try {
            //加载配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            //定义Tracker Client对象,用于请求Tracker
            TrackerClient trackerClient = new TrackerClient();
            //连接到Tracker Server
            TrackerServer trackerServer = trackerClient.getConnection();
            //判断Tracker Server对象非空
            if(trackerServer == null) {
                System.out.println("tracker server is null!");
                return;
            }
            //获取Storage Server
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            //判断StorageServer非空
            if(storageServer == null) {
                System.out.println("Storage Server is null!");
                return;
            }
            //创建Storage Client
            StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);
            //本地图片文件的路径
            String picPath = "F:/Users/Administrator/Pictures/images/u=1251179480,1168307514&fm=173&app=49&f=JPEG.jpg";
            //上传图片,返回一个fileId
            String fileId = storageClient1.upload_file1(picPath, "jpg", null);
            if(fileId != null) {
                System.out.println("图片上传成功!文件ID是:" + fileId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

执行这个方法,控制台如下:
FastDFS图片服务器
复制返回的fileId,通过浏览器访问:
http://47.114.175.9/group1/M00/00/00/rBwObF_l_fKAe8EEAABIYoHNsrs099.jpg
FastDFS图片服务器
成功访问,说明图片上传到了图片服务器,上传成功。

下面来测一下图片的查询:

    //测试图片查询
    @Test
    public void testFindPicByFileId() {
        try {
            //加载配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            //定义Tracker Client对象,用于请求Tracker
            TrackerClient trackerClient = new TrackerClient();
            //连接到Tracker Server
            TrackerServer trackerServer = trackerClient.getConnection();
            //判断Tracker Server对象非空
            if(trackerServer == null) {
                System.out.println("tracker server is null!");
                return;
            }
            //获取Storage Server
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            //判断StorageServer非空
            if(storageServer == null) {
                System.out.println("Storage Server is null!");
                return;
            }
            //创建Storage Client
            StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);
            //查询
            FileInfo fileInfo = storageClient1.query_file_info("group1", "M00/00/00/rBwObF_l_fKAe8EEAABIYoHNsrs099.jpg");
            if(fileInfo != null) {
                System.out.println("查询的文件是:" + fileInfo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行这个方法,控制台输入:

查询的文件是:source_ip_addr = 172.28.14.108, file_size = 18530, create_timestamp = 2020-12-25 22:57:54, crc32 = -2117225797

查询成功。

最后再测试一下从图片服务器上下载图片:

    //测试从图片服务器下载图片
    @Test
    public void testDownloadPic() {
        try {
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getConnection();
            if(trackerServer == null) {
                System.out.println("tracker server is null!");
                return;
            }
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            if(storageServer == null) {
                System.out.println("Storage Server is null!");
                return;
            }
            StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);
            //下载,返回字节数组
            byte []bys = storageClient1.download_file1("group1/M00/00/00/rBwObF_l_fKAe8EEAABIYoHNsrs099.jpg");
            //保存文件对象
            File file = new File("F:/Users/Administrator/Desktop");
            //输出流
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            //写入
            fileOutputStream.write(bys);
            //关闭流
            fileOutputStream.close();
            System.out.println("图片下载完成!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行该方法,控制台输出:
FastDFS图片服务器
然后查看桌面:
FastDFS图片服务器
下载成功。

那么使用Java程序进行图片的上传、查询、下载就完成了,无论是上传、查询、还是下载总结为:

  • 加载配置文件
  • 获取TrackerClient对象
  • 通过TrackerClient对象来获取TrackerServer对象
  • 通过TrackerClient对象来获取StorageServer对象
  • 通过TrackerServer对象和StorageServer对象来获取StorageClient1对象
  • 上传的话执行upload_file1方法,查询执行query_file_info方法,下载执行download_file1方法

7、总结

本来开始是想直接使用阿里云的OSS来存储的,但是没接触过FastDFS,想自己从0开始搭建到可以正常访问,也可以熟悉一下过程,直接使用成品很简单,付费就可以直接用,自己搭建稍微复杂一点,有的地方不注意最后访问会有问题,再到使用Java程序测试图片的上传、查询、下载,虽然过程久了点,但是学到了东西,表示人间很值得。

上一篇:CentOS7-FastDFS&Nginx实现分布式文件服务器


下一篇:用FastDFS一步步搭建文件管理系统