FastDFS分布式文件系统
文章目录
一:分布式文件系统
分布式文件系统(Distributed File System)是一个软件/软件服务器,这个软件可以用来管理文件
但是这个软件管理的文件通常不是在一个服务器的节点上,而是在多个服务器的节点上,这些服务器节点通过网络相连构成了一个庞大的文件存储服务器集群,这些服务器都用于存储文件资源,通过分布式文件管理系统来管理这些服务器上的文件。
常见的分布式文件系统有:FastDFS,GFS,HDFS,Lustre,Ceph,GridFS等等。
二:FastDFS简介
FastDFS是一个开源的轻量级分布式文件系统,为互联网应用量身定做,简单,灵活,高效,采用C语言开发,由阿里巴巴开发并开源
FastDFS主要对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题
特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS充分考虑了冗余备份、线性扩容等机制,并注重高可用,高性能等指标
使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务
github地址:https://github.com/happyfish100/fastdfs
FastDFS由跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)三个部分组成
主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。

三:FastDFS整体架构

FastDFS文件系统由两大部分构成,一个是客户端,一个是服务端。
客户端
客户端通常指我们的程序,比如我们的Java程序去连接FastDFS、操作FastDFS,那我们的Java程序就是一个客户端
FastDFS提供专有API访问,目前提供了C、Java和PHP几种编程语言的API,用来访问FastDFS文件系统
服务端
由两个部分构成:一个是跟踪服务器(Tracker server),一个是存储服务器(Storage server)
客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载
- Tracker server作用:
- 负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务
- Tracker Server负责管理所有的storage server和group
- 每个storage在启动后会连接 Tracker,告知自己所属 group 等信息,并保持周期性心跳。
- 多个Tracker之间是对等关系,不存在单点故障
- Storage server作用:
- 文件存储,客户端上传的文件最终存储在Storage服务器上
- Storage server没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。
- Storage Server可以分为多个group组( 卷1、卷2、卷n ),每个组之间保存的文件是不同的。
- 每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念
一个完整的FastDFS集群架构大概是这样的:

四:文件操作流程
1:文件上传流程

2:文件下载流程

3:文件删除流程

五:文件同步机制
同一组内的storage server之间是对等的,文件上传、删除等操作可以在任意一台storage server上进行
文件同步只在同组内的storage server之间进行,采用push方式,即源服务器同步给目标服务器【有个例外,就是新增加一台storage server时,由已有的一台storage server将已有的所有数据(包括源头数据和备份数据)同步给该新增服务器】
源头数据才需要同步,备份数据不需要再次同步,否则就构成环路了
六:环境搭建演示
1:下载安装 libfastcommon
libfastcommon是从 FastDFS 和 FastDHT 中提取出来的公共 C 函数库,基础环境,安装即可
mkdir fastdfs
cd fastdfs/ # 新建一个文件夹,一会所有的包都存储到这里
下载或者上传安装libfastcommon
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz
因为FastDFS是使用c语言开发,需要先安装gcc环境,否则之后运行类库的 ./make.sh 会报错
yum -y install gcc
yum -y install gcc-c++
解压libfastcommon
tar -zxvf libfastcommonV1.0.7.tar.gz
解压后,会生成libfastcommon-1.0.7文件夹,里面有make.sh编译脚本。使用这个脚本进行编译和安装
./make.sh # 编译
./make.sh install # 安装
libfastcommon.so 安装到了/usr/lib64/libfastcommon.so,而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:下载安装FastDFS
1:下载 -> 下载地址:https://sourceforge.net/projects/fastdfs/files/,我们会看到如下图所示界面


wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
然后下载这个V5.05即可【可能国内的网络比较卡,可能需要翻墙】,下载完成之后上传到服务器的fastDFS文件夹下,然后进行解压缩
tar -zxvf FastDFS_v5.05.tar.gz
解压缩之后,可以看到生成了FastDFS文件夹,里面有编译相关脚本:
$ ll
total 412
drwxr-xr-x. 10 8980 users 258 Dec 2 2014 FastDFS
-rw-r--r--. 1 root root 345400 Nov 9 14:39 FastDFS_v5.05.tar.gz
drwxrwxr-x. 3 root root 102 Nov 9 14:31 libfastcommon-1.0.7
-rw-r--r--. 1 root root 73148 Nov 9 14:30 libfastcommonV1.0.7.tar.gz
$ cd FastDFS/
$ ll
total 120
drwxr-xr-x. 3 8980 users 4096 Dec 2 2014 client
drwxr-xr-x. 2 8980 users 261 Dec 2 2014 common
drwxr-xr-x. 2 8980 users 146 Dec 2 2014 conf
-rw-r--r--. 1 8980 users 35067 Dec 2 2014 COPYING-3_0.txt
-rw-r--r--. 1 8980 users 2802 Dec 2 2014 fastdfs.spec
-rw-r--r--. 1 8980 users 31386 Dec 2 2014 HISTORY
drwxr-xr-x. 2 8980 users 48 Dec 2 2014 init.d
-rw-r--r--. 1 8980 users 7755 Dec 2 2014 INSTALL
-rwxr-xr-x. 1 8980 users 5813 Dec 2 2014 make.sh
drwxr-xr-x. 2 8980 users 4096 Dec 2 2014 php_client
-rw-r--r--. 1 8980 users 2380 Dec 2 2014 README.md
-rwxr-xr-x. 1 8980 users 1768 Dec 2 2014 restart.sh
-rwxr-xr-x. 1 8980 users 1680 Dec 2 2014 stop.sh
drwxr-xr-x. 4 8980 users 4096 Dec 2 2014 storage
drwxr-xr-x. 2 8980 users 4096 Dec 2 2014 test
drwxr-xr-x. 2 8980 users 4096 Dec 2 2014 tracker
[root@localhost FastDFS]#
执行编译、安装
./make.sh
./make.sh install
FastDFS默认服务脚本路径
/etc/init.d/fdfs_storaged # 存储
/etc/init.d/fdfs_trackerd # 调度
FastDFS相关配置文件示例
/etc/fdfs/client.conf.sample # 客户端配置示例
/etc/fdfs/storage.conf.sample # 存储端配置示例
/etc/fdfs/tracker.conf.sample # 调度端配置示例
FastDFS默认的脚本安装后放在/usr/bin下面,但是FastDFS 服务脚本设置的 bin 目录是 /usr/local/bin
所以还是需要建立 /usr/bin 到 /usr/local/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
3:配置tracker调度
编辑tracker.conf[vim tracker.conf],需要修改如下几个地方:
disabled=false-> 这个参数表示启用port=22122-> 这个参数指定了服务监听的端口号,这个注意在防火墙中开发,【如果是自己用着玩,可以直接关闭防火墙】base_path=/fastdfs/tracker-> 指定调度tracker的base路径,这个注意需要mkdir /fastdfs/trackerhttp.server_port=80-> 这个参数指定了HTTP服务器监听的端口号。80端口是HTTP协议的默认端口
然后启动tracker,启动成功后,会在 /fastdfs/tracker (配置的base_path)下创建 data、logs 两个目录,如下所示:
/etc/init.d/fdfs_trackerd start
Reloading systemd: [ OK ]
Starting fdfs_trackerd (via systemctl): [ OK ]
查看 FastDFS Tracker 是否已成功启动 ,22122端口正在被监听,则说明Tracker服务安装成功。
netstat -unltp | grep fdfs
设置Tracker开机启动
chkconfig fdfs_trackerd on
Tracker server目录及文件结构
Tracker服务启动成功后,会在base_path下创建data、logs两个目录。目录结构如下:
${base_path}
|__data
| |__storage_groups.dat # 存储分组信息
| |__storage_servers.dat # 存储服务器列表
|__logs
| |__trackerd.log: tracker server # 日志文件
4:配置storage存储
复制 storage.conf.sample,并重命名为 storage.conf
cp storage.conf.sample storage.conf
ll
total 36
-rw-r--r--. 1 root root 1461 Nov 9 14:42 client.conf.sample
-rw-r--r--. 1 root root 7829 Nov 9 15:41 storage.conf
-rw-r--r--. 1 root root 7829 Nov 9 14:42 storage.conf.sample
-rw-r--r--. 1 root root 7234 Nov 9 15:12 tracker.conf
-rw-r--r--. 1 root root 7102 Nov 9 14:42 tracker.conf.sample
编辑storage.conf,主要修改下面几个地方
disabled=false-> 表示该存储节点是启用的,即可以接收文件存储请求。如果设置为true,则节点会被禁用。group_name=group1-> 指定该存储节点所属的组名。在FastDFS中,文件通过组名和文件名进行唯一标识port=23000-> 指定存储节点监听的端口号,客户端和跟踪服务器(Tracker Server)通过此端口与存储节点进行通信heart_beat_interval=30-> 心跳包发送的时间间隔,单位为秒。存储节点会定期向跟踪服务器发送心跳包以维持连接状态base_path=/fastdfs/storage-> 存储节点的基路径,用于存放日志文件等store_path_count=1-> 指定存储路径的个数。FastDFS支持一个节点配置多个存储路径,以提高存储效率和可靠性store_path0=/fastdfs/file-> 具体的存储路径,用于存放实际文件。这里的0表示第一个存储路径subdir_count_per_path=256-> 每个存储路径下子目录的个数。FastDFS会在每个存储路径下创建多个子目录来存放文件,以提高文件访问性能tracker_server=192.168.179.133:22122-> 指定跟踪服务器的地址和端口sync_start_time=00:00-> 指定了文件同步的时间范围sync_end_time=23:59-> 指定了文件同步的时间范围http.server_port=80-> 这里指定了HTTP服务器监听的端口号为80
根据上面的配置修改,可能需要修改下面两个部分:
- 创建Storage基础数据目录,对应base_path目录
mkdir /fastdfs/storage&mkdir /fastdfs/file - 防火墙中打开存储器端口(默认的 23000),打开之后,别忘了重启防火墙
service iptables restart
启动 Storage,启动Storage前确保Tracker是启动的
/etc/init.d/fdfs_storaged start
Starting fdfs_storaged (via systemctl): [ OK ]
启动成功之后,会在 /fastdfs/storage 目录下创建 data、 logs 两个目录,同时可以使用命令查看是否启动成功
netstat -unltp | grep fdfs
设置storage开机自启动
chkconfig fdfs_storaged on
5:其他说明配置
查看Storage和Tracker是否在通信
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf

Storage目录结构
同 Tracker,Storage 启动成功后,在base_path 下创建了data、logs目录,记录着 Storage Server 的信息。
在 store_path0 目录下,创建了N*N个子目录:

6:文件上传测试
复制Tracker客户端配置文件,并取名"client.conf"
cp client.conf.sample client.conf
修改client.conf,主要修改下面几个地方:
base_path=/fastdfs/client-> 指定基路径,注意创建mkdir /fastdfs/clienttracker_server=192.168.179.133:22122-> 声明调度器的ip:port
进行上传测试
[root@localhost /]#
[root@localhost /]# ll
total 36
lrwxrwxrwx. 1 root root 7 Sep 18 2019 bin -> usr/bin
dr-xr-xr-x. 5 root root 4096 Sep 18 2019 boot
drwxr-xr-x. 20 root root 3260 Nov 9 14:25 dev
drwxr-xr-x. 3 root root 80 Oct 10 15:12 elasticsearch
drwxr-xr-x. 3 root root 80 Oct 10 15:50 es
drwxr-xr-x. 135 root root 8192 Nov 9 14:42 etc
drwxr-xr-x. 8 root root 166 Nov 9 16:05 fastdfs
drwxr-xr-x. 4 root root 27 Oct 10 15:13 home
lrwxrwxrwx. 1 root root 7 Sep 18 2019 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Sep 18 2019 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x. 3 root root 16 Sep 18 2019 opt
dr-xr-xr-x. 211 root root 0 Nov 9 14:25 proc
dr-xr-x---. 5 root root 262 Nov 9 16:04 root
drwxr-xr-x. 38 root root 1220 Nov 9 14:30 run
lrwxrwxrwx. 1 root root 8 Sep 18 2019 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x. 13 root root 0 Nov 9 14:25 sys
-rw-r--r--. 1 root root 12637 Nov 9 16:13 timg.png
drwxrwxrwt. 30 root root 4096 Nov 9 16:05 tmp
drwxr-xr-x. 13 root root 155 Sep 18 2019 usr
drwxr-xr-x. 20 root root 282 Sep 18 2019 var
[root@localhost /]# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf timg.png
group1/M00/00/00/wKizhV-o-jiAQ08WAAAxXVoV3i4602.png # <------ 注意返回结构
可以看到,文件上传成功,返回文件ID号:group1/M00/00/00/wKizhV-o-jiAQ08WAAAxXVoV3i4602.png
返回的文件ID由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。
group1:组名M00:磁盘00/00:目录wKizhV-o-jiAQ08WAAAxXVoV3i4602.png:文件名 & 后缀
七:整合nginx
前面已经成功实现了文件上传到Storage中,但我们暂时还不能下载文件,需要安装Nginx作为服务器以支持Http方式访问文件
一个tracker对应多个storage,通过nginx对storage负载均衡[所以Nginx只需要安装到StorageServer所在的服务器即可,用于访问文件。]

1:安装nginx
安装gcc-c++[前面已经安装过了]、 PCRE pcre-devel、zlib、OpenSSL
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel
下载nginx,以nginx-1.18.0.tar.gz为例。http://nginx.org/en/download.html

上传到服务器上之后,解压:
tar -zxvf nginx-1.18.0.tar.gz
使用默认的配置
./configure
编译,安装
[root@localhost nginx-1.18.0]# make
[root@localhost nginx-1.18.0]# make install
启动nginx
cd /usr/local/nginx/sbin/
./nginx
ps -ef | grep nginx # 查看是否启动
防火墙中打开Nginx端口(默认的 80),修改完成之后,重启防火墙
2:测试访问文件
我们需要修改一下nginx.conf,增加下面的配置:
# 将 /group1/M00 映射到 /fastdfs/file/data
location /group1/M00 {
alias /fastdfs/file/data; # 这个是上面storage中的具体的存储路径,用于存放实际文件的那个配置
}
修改完成之后,重启nginx:
/usr/local/nginx/sbin/nginx -s reload
重启完成之后,在浏览器访问之前上传的图片:http://xxx/group1/M00/00/00/wKizhV-o-jiAQ08WAAAxXVoV3i4602.png
3:整合fastdfs-nginx-module模块
前面已经通过安装Nginx实现了从浏览器访问FastDFS中的文件信息
在生产环境中,我们的存储服务storage一般都是有几台机器组成一个组,当上传一个文件后,同组存储服务器之间需要进行文件复制
此时可能存在同步延迟的问题。为了解决这个问题,FastDFS提供了 fastdfs-nginx-module的Nginx模块
fastdfs-nginx-module可以重定向文件链接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误。
以1.16版本为例进行安装:【https://sourceforge.net/projects/fastdfs/files】


将fastdfs-nginx-module_v1.16.tar.gz上传到服务器后[/fastdfs下],解压操作
[root@localhost fastdfs]# tar -zxvf fastdfs-nginx-module_v1.16.tar.gz
[root@localhost fastdfs]# ll
total 1448
drwxr-xr-x. 2 root root 6 Nov 9 16:05 client
drwxr-xr-x. 10 8980 users 258 Nov 9 14:42 FastDFS
drwxrwxr-x. 3 500 500 47 May 4 2014 fastdfs-nginx-module
-rw-r--r--. 1 root root 17510 Nov 16 15:49 fastdfs-nginx-module_v1.16.tar.gz
-rw-r--r--. 1 root root 345400 Nov 9 14:39 FastDFS_v5.05.tar.gz
drwxr-xr-x. 3 root root 18 Nov 9 15:52 file
drwxrwxr-x. 3 root root 102 Nov 9 14:31 libfastcommon-1.0.7
-rw-r--r--. 1 root root 73148 Nov 9 14:30 libfastcommonV1.0.7.tar.gz
drwxr-xr-x. 9 es mysql 186 Nov 9 17:05 nginx-1.18.0
-rw-r--r--. 1 root root 1039530 Nov 9 17:03 nginx-1.18.0.tar.gz
drwxr-xr-x. 4 root root 30 Nov 9 15:52 storage
drwxr-xr-x. 4 root root 30 Nov 9 15:22 tracker
[root@localhost fastdfs]# cd fastdfs-nginx-module/
[root@localhost fastdfs-nginx-module]# ll
total 8
-rw-rw-r--. 1 500 500 2342 May 4 2014 HISTORY
-rw-rw-r--. 1 500 500 1733 May 4 2014 INSTALL
drwxrwxr-x. 2 500 500 109 May 4 2014 src
配置Nginx,在nginx中添加模块
# 首先我们停止nginx服务,然后进入解压包目录,然后添加模块:
[root@localhost nginx-1.18.0]# ./configure --add-module=/fastdfs/fastdfs-nginx-module/src
# 重新编译,安装
[root@localhost nginx-1.18.0]# make && make install
# 查看nginx模块
[root@localhost nginx-1.18.0]# /usr/local/nginx/sbin/nginx -V
...
configure arguments: --add-module=/fastdfs/fastdfs-nginx-module/src # <--- 如果发现这句表示添加成功
复制 fastdfs-nginx-module 源码中的配置文件到/etc/fdfs 目录
[root@localhost /]# cd fastdfs/fastdfs-nginx-module/
[root@localhost fastdfs-nginx-module]# cd src/
[root@localhost src]# ll
total 76
-rw-rw-r--. 1 500 500 33207 Aug 30 2013 common.c
-rw-rw-r--. 1 500 500 3479 Jan 3 2012 common.h
-rw-rw-r--. 1 500 500 447 Nov 4 2010 config
-rw-rw-r--. 1 500 500 3679 Mar 30 2013 mod_fastdfs.conf
-rw-rw-r--. 1 500 500 28542 May 4 2014 ngx_http_fastdfs_module.c
[root@localhost src]# cp mod_fastdfs.conf /etc/fdfs/
[root@localhost src]#
修改mod_fastdfs.conf如下配置,其它默认:
connect_timeout=10;tracker_server=192.168.179.133:22122;url_have_group_name = true:如果文件ID的uri中包含/group**,则要设置为true;store_path0=/fastdfs/file:Storage配置的store_path0路径,必须和storage.conf中的一致;
复制 FastDFS 的部分配置文件到 /etc/fdfs 目录
[root@localhost /]# cd fastdfs/
[root@localhost fastdfs]# ll
total 1448
drwxr-xr-x. 2 root root 6 Nov 9 16:05 client
drwxr-xr-x. 10 8980 users 258 Nov 9 14:42 FastDFS
drwxrwxr-x. 3 500 500 47 May 4 2014 fastdfs-nginx-module
-rw-r--r--. 1 root root 17510 Nov 16 15:49 fastdfs-nginx-module_v1.16.tar.gz
-rw-r--r--. 1 root root 345400 Nov 9 14:39 FastDFS_v5.05.tar.gz
drwxr-xr-x. 3 root root 18 Nov 9 15:52 file
drwxrwxr-x. 3 root root 102 Nov 9 14:31 libfastcommon-1.0.7
-rw-r--r--. 1 root root 73148 Nov 9 14:30 libfastcommonV1.0.7.tar.gz
drwxr-xr-x. 9 es mysql 186 Nov 9 17:05 nginx-1.18.0
-rw-r--r--. 1 root root 1039530 Nov 9 17:03 nginx-1.18.0.tar.gz
drwxr-xr-x. 4 root root 30 Nov 9 15:52 storage
drwxr-xr-x. 4 root root 30 Nov 9 15:22 tracker
[root@localhost fastdfs]# cd FastDFS/
[root@localhost FastDFS]# ll
total 124
drwxr-xr-x. 3 8980 users 4096 Nov 9 14:42 client
drwxr-xr-x. 2 8980 users 4096 Nov 9 14:41 common
drwxr-xr-x. 2 8980 users 146 Dec 2 2014 conf
-rw-r--r--. 1 8980 users 35067 Dec 2 2014 COPYING-3_0.txt
-rw-r--r--. 1 8980 users 2802 Dec 2 2014 fastdfs.spec
-rw-r--r--. 1 8980 users 31386 Dec 2 2014 HISTORY
drwxr-xr-x. 2 8980 users 48 Dec 2 2014 init.d
-rw-r--r--. 1 8980 users 7755 Dec 2 2014 INSTALL
-rwxr-xr-x. 1 8980 users 5813 Dec 2 2014 make.sh
drwxr-xr-x. 2 8980 users 4096 Dec 2 2014 php_client
-rw-r--r--. 1 8980 users 2380 Dec 2 2014 README.md
-rwxr-xr-x. 1 8980 users 1768 Dec 2 2014 restart.sh
-rwxr-xr-x. 1 8980 users 1680 Dec 2 2014 stop.sh
drwxr-xr-x. 4 8980 users 4096 Nov 9 14:42 storage
drwxr-xr-x. 2 8980 users 4096 Dec 2 2014 test
drwxr-xr-x. 2 8980 users 4096 Nov 9 14:42 tracker
[root@localhost FastDFS]# cd conf/
[root@localhost conf]# ll
total 84
-rw-r--r--. 1 8980 users 23981 Dec 2 2014 anti-steal.jpg
-rw-r--r--. 1 8980 users 1461 Dec 2 2014 client.conf
-rw-r--r--. 1 8980 users 858 Dec 2 2014 http.conf
-rw-r--r--. 1 8980 users 31172 Dec 2 2014 mime.types
-rw-r--r--. 1 8980 users 7829 Dec 2 2014 storage.conf
-rw-r--r--. 1 8980 users 105 Dec 2 2014 storage_ids.conf
-rw-r--r--. 1 8980 users 7102 Dec 2 2014 tracker.conf
[root@localhost conf]# cp anti-steal.jpg http.conf mime.types /etc/fdfs/
配置nginx,修改nginx.conf
[root@localhost fdfs]# cd /usr/local/nginx/
[root@localhost nginx]# ll
total 4
drwx------. 2 nobody root 6 Nov 9 17:07 client_body_temp
drwxr-xr-x. 2 root root 4096 Nov 9 17:14 conf
drwx------. 2 nobody root 6 Nov 9 17:07 fastcgi_temp
drwxr-xr-x. 2 root root 40 Nov 9 17:06 html
drwxr-xr-x. 2 root root 41 Nov 9 17:30 logs
drwx------. 2 nobody root 6 Nov 9 17:07 proxy_temp
drwxr-xr-x. 2 root root 36 Nov 16 16:09 sbin
drwx------. 2 nobody root 6 Nov 9 17:07 scgi_temp
drwx------. 2 nobody root 6 Nov 9 17:07 uwsgi_temp
[root@localhost nginx]# cd conf/
[root@localhost conf]# ll
total 68
-rw-r--r--. 1 root root 1077 Nov 9 17:06 fastcgi.conf
-rw-r--r--. 1 root root 1077 Nov 16 16:09 fastcgi.conf.default
-rw-r--r--. 1 root root 1007 Nov 9 17:06 fastcgi_params
-rw-r--r--. 1 root root 1007 Nov 16 16:09 fastcgi_params.default
-rw-r--r--. 1 root root 2837 Nov 16 16:09 koi-utf
-rw-r--r--. 1 root root 2223 Nov 16 16:09 koi-win
-rw-r--r--. 1 root root 5231 Nov 9 17:06 mime.types
-rw-r--r--. 1 root root 5231 Nov 16 16:09 mime.types.default
-rw-r--r--. 1 root root 2763 Nov 9 17:14 nginx.conf
-rw-r--r--. 1 root root 2656 Nov 16 16:09 nginx.conf.default
-rw-r--r--. 1 root root 636 Nov 9 17:06 scgi_params
-rw-r--r--. 1 root root 636 Nov 16 16:09 scgi_params.default
-rw-r--r--. 1 root root 664 Nov 9 17:06 uwsgi_params
-rw-r--r--. 1 root root 664 Nov 16 16:09 uwsgi_params.default
-rw-r--r--. 1 root root 3610 Nov 16 16:09 win-utf
[root@localhost conf]# vim nginx.conf
location ~/group([0-9])/M00 {
ngx_fastdfs_module;
}
- listen 80 端口值是要与
/etc/fdfs/storage.conf中的http.server_port=80(前面改成80了)相对应。如果改成其它端口,则需要统一 - location 的配置,如果有多个group则配置
location ~/group([0-9])/M00,没有则不用配group。
启动nginx并进行测试
[root@localhost sbin]# ./nginx
ngx_http_fastdfs_set pid=10971
重新上传一张图片:
[root@localhost /]#
[root@localhost /]# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf timg.png
group1/M00/00/00/wKizhV-yOiOAUrLTAAAxXVoV3i4802.png
[root@localhost /]#
在地址栏访问:http://192.168.179.133/group1/M00/00/00/wKizhV-yOiOAUrLTAAAxXVoV3i4802.png。
如果能成功访问到图片,说明我们的配置没有问题。
八:客户端API实现文件上传下载
前面已经搭建好了FastDFS环境,在实际工作中,一般都是使用FastDFS客户端API来上传或者下载文件
fastDFS client是开源的,https://github.com/tobato/FastDFS_Client

首先,我们创建一个springboot项目,项目目录结构大体如下:

1:依赖和配置
引入FastDFS、Thymeleaf等依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- taobao fastdfs依赖 -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
server:
port: 80
# 分布式文件系统FDFS配置
fdfs:
soTimeout: 1500 #socket连接超时时长
connectTimeout: 600 #连接tracker服务器超时时长
reqHost: 192.168.179.133 #nginx访问地址
reqPort: 80 #nginx访问端口
thumbImage: #缩略图生成参数,可选
width: 150
height: 150
trackerList: #TrackerList参数,支持多个,这里只有一个,如果有多个在下方加- x.x.x.x:port
- 192.168.179.133:22122
#- 192.168.179.134:22122
#- 192.168.179.135:22122
spring:
application:
name: fastdfs-demo
servlet:
multipart:
enabled: true
max-file-size: 10MB
max-request-size: 20MB
2:配置FastDFS
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
@Configuration
@Import(FdfsClientConfig.class) // 导入FastDFS-Client组件
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) // 解决jmx重复注册bean的问题
public class CustomFastDFSConfiguration {
}
3:编写FastDFS操作文件的工具类
FastDFS上传、下载以及删除文件底层都是靠的FastFileStorageClient对象来对文件进行操作。
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileOutputStream;
import java.io.IOException;
@Component
public class FastDFSClientUtils {
private static Logger logger = LoggerFactory.getLogger(FastDFSClientUtils.class);
@Autowired
private FastFileStorageClient fastFileStorageClient;
/**
* 上传文件
*/
public String uploadFile(MultipartFile multipartFile) throws Exception {
// 拿到原始文件名
String originalFilename = multipartFile.getOriginalFilename()
.substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1);
// fastFileStorageClient进行上传操作并且生成缩略图,注意参数:文件的流,文件大小,原始文件名称
StorePath storePath = fastFileStorageClient.uploadImageAndCrtThumbImage(
multipartFile.getInputStream(),
multipartFile.getSize(), originalFilename, null);
// 拿到存储后的完整路径
return storePath.getFullPath();
}
/**
* 删除文件
*/
public void deleteFile(String fileUrl) {
if (StringUtils.isEmpty(fileUrl)) {
logger.info("需要删除的文件路径为空......");
return;
}
try {
// 通过fileUrl解析出来storePath
StorePath storePath = StorePath.parseFromUrl(fileUrl);
// 调用fastFileStorageClient.deleteFile进行删除
fastFileStorageClient.deleteFile(storePath.getGroup(), storePath.getPath());
} catch (Exception e) {
logger.info(e.getMessage());
}
}
/**
* 下载文件
*/
public byte[] downloadFile(String fileUrl) {
// 拿到分组和路径从fileUrl中
String group = fileUrl.substring(0, fileUrl.indexOf("/"));
String path = fileUrl.substring(fileUrl.indexOf("/") + 1);
logger.info("下载文件的group: {},path: {}", group, path);
// 声明一个DownloadByteArray
DownloadByteArray downloadByteArray = new DownloadByteArray();
// 调用downloadFile进行下载,返回文件的字节数组
byte[] bytes = fastFileStorageClient.downloadFile(group, path, downloadByteArray);
try {
//将文件保存到d盘
FileOutputStream fileOutputStream = new FileOutputStream("d:\\image.png");
fileOutputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
}
4:控制层编写
import com.springboot.fastdfs.fastdfsdemo.utils.FastDFSClientUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.Arrays;
@Controller
public class FastDFSController {
private static final Logger logger = LoggerFactory.getLogger(FastDFSController.class);
@Resource
private FastDFSClientUtils fastDFSClientUtils;
@GetMapping("/")
public String index() {
return "upload";
}
/**
* 文件上传
*/
@RequestMapping(value = "/uploadFile", headers = "content-type=multipart/form-data", method = RequestMethod.POST)
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
String result;
try {
String path = fastDFSClientUtils.uploadFile(file);
if (!StringUtils.isEmpty(path)) {
result = path;
} else {
result = "文件上传失败";
}
} catch (Exception e) {
e.printStackTrace();
result = "服务器异常,请稍后重试!";
}
return ResponseEntity.ok(result);
}
/**
* 文件删除
*/
@RequestMapping(value = "/deleteByPath", method = RequestMethod.GET)
public ResponseEntity<String> deleteByPath(@RequestParam("filePathName") String filePathName) {
if (StringUtils.isBlank(filePathName)) {
logger.error("请传入需要删除的文件路径!");
return ResponseEntity.ok("请传入需要删除的文件路径!");
}
fastDFSClientUtils.deleteFile(filePathName);
return ResponseEntity.ok("文件删除成功!");
}
/**
* 文件下载
*/
@GetMapping("/downloadFile")
public void downloadFile(@RequestParam("filePathName") String filePathName, HttpServletResponse response) {
if (StringUtils.isBlank(filePathName)) {
logger.error("请传入需要下载的文件路径!");
} else {
byte[] bytes = fastDFSClientUtils.downloadFile(filePathName);
logger.info(Arrays.toString(bytes));
//此处需要设置ISO8859-1,application/octet-stream为未知文件类型时使用
response.setContentType("application/octet-stream;charset=ISO8859-1");
BufferedOutputStream output;
try {
output = new BufferedOutputStream(response.getOutputStream());
response.setHeader("Content-Disposition", "attachment;filename=image.png");
output.write(bytes);
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5:随便编写一个upload.html
<!DOCTYPE html>
<html>
<body>
<h1>FastDFS 文件上传案例</h1>
<form method="POST" action="/uploadFile" enctype="multipart/form-data">
<input type="file" name="file"/><br/><br/>
<input type="submit" value="上传文件"/>
</form>
</body>
</html>
在启动项目之前,确保FastDFS环境都已经启动成功
1630

被折叠的 条评论
为什么被折叠?



