前言
FastDFS是一个开源的高性能分布式文件系统。它的主要功能包括:文件存储、文件同步和文件访问(文件上传和文件下载),可以解决高容量和负载平衡问题。FastDFS应满足其服务基于文件的网站的要求,如照片共享网站和视频共享网站。开源地址
https://github.com/happyfish100
介绍
1、角色
Tracker:跟踪器负责文件访问的调度和负载平衡。负责管理所有的storage和group,storage启动后会连接tracker,告知自己的group信息
Storage:存储器存储文件,其功能是文件管理,包括:文件存储、文件同步、提供文件访问接口
Client:客户端,上传下载文件的服务器,一般是我们的应用程序
2、文件上传
storage定时向tracker同步状态信息,集群中的每个tracker是对等的,因此上传时,客户端选择任意的tracker,请求到storage的相关信息(ip、port),根据返回的信息上传文件,通过storage写入磁盘,并返回客户端存储的文件信息(fileId、路径、文件名等)
3、文件同步
客户端向group内的任意storage写入文件成功即可,storage写完文件后,会由后台线程将文件同步至同group内其他的storage,每个storage写文件后,同时会写一份binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式进行记录,所以最好能保证集群内所有server的时钟保持同步
4、文件下载
客户端根据业务存储的文件信息,可以拿到文件,流程同上传,如下所示
安装
最新版FastDFS安装要求Centos7及以上,
FastDFS安装包
1、安装libfastcommon
解压安装包
unzip libfastcommon-master.zip
进入libfastcommon-master安装目录,分别执行
./make.sh
和
./make.sh install
libfastcommon默认会被安装到/usr/lib64/libfastcommon.so,FastDFS的主程序在/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
至此,libfastcommon安装完成
2、安装fastdfs
在安装fastdfs之前,需要先安装libserverframe,这是因为我这里安装的最新fastdfs安装包,缺少libserverframe,
github地址
,否则执行
./make.sh
时报错
/common/fdfs_global.h:15:26: 致命错误:sf/sf_global.h:没有那个文件或目录
解压安装包
unzip libserverframe-master.zip
进入安装目录,分别执行
./make.sh
和
./make.sh install
,如遇到如下问题,执行
./make.sh clean
然后重新
./make.sh
安装完毕后,安装fasfdfs,解压安装包
unzip fastdfs-master.zip
进入fastdfs-master目录,分别执行
./make.sh
和
./make.sh install
fastdfs配置文件默认在/etc/fdfs,我们继续执行
./setup.sh /etc/fdfs
安装
3、配置tracker
先创建tracker的工作目录,主要用来保存data和log,我直接在fastdfs同级目录创建了/tools/fastdfs_tracker,进入/etc/fdfs配置目录,编辑配置文件
vi /etc/fdfs/tracker.conf
,修改配置如下
1.disabled=false #默认开启(false是启用这个配置文件)
2.port=22122 #默认端口号 (tracker默认端口)
3.base_path=/tools/fastdfs_tracker #上面创建的目录就用在这里
4.http.server_port=6666 #默认端口是8080(tracker的默认http端口)
修改完成保存,然后启动tracker,
systemctl start fdfs_trackerd
,启动后,在工作目录可以看到创建了data和log目录,也可以查看下端口监听
netstat -unltp|grep fdfs
关闭tracker
service fdfs_trackerd stop
,然后将其加入开机启动,查看
ll /etc/rc.d/rc.local
是否有修改权限,若为-rwxr-xr-x表示可以,若为-rw-r–r–则需要刷新权限
执行
chmod +x /etc/rc.d/rc.local
,然后编辑
vi /etc/rc.d/rc.local
加入如下配置
systemctl start fdfs_trackerd
至此,tracker配置启动完毕
4、配置storage
新建storage安装目录/tools/storage和文件存储目录/tools/fdfs_storage_data,编辑配置文件
vi /etc/fdfs/storage.conf
,如下
1.disabled=false
2.group_name=group1 #组名,根据实际情况修改
3.port=23000 #设置storage的端口号,默认是23000,同一个组的storage端口号必须一致
4.base_path=/tools/fdfs_storage #设置storage数据文件和日志目录
5.store_path_count=1 #存储路径个数,需要和store_path个数匹配
6.base_path0=/tools/fdfs_storage_data #实际文件存储路径
7.tracker_server=ip:22122 #这里我写的是服务器内网ip
8.http.server_port=8888 #设置 http 端口号,别设置6667,坑
创建软连接
ln -s /usr/bin/fdfs_storaged /usr/local/bin
,启动前确认tracker已启动,然后启动
systemctl start fdfs_storaged
,启动后查看
netstat -unltp | grep fdfs
然后查看tracker和storage是否通信,
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
然后接入开机启动,同上
5、客户端配置
创建tracker client的数据和日志目录/tools/fdfs_client,编辑配置文件
vi /etc/fdfs/client.conf
base_path = /tools/fdfs_client
tracker_server = ip:22122
测试文件上传
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf 111.png
group1/M00/00/00/wKiIh2SbzNCAAjD3AADMLPdP-Nk403.png
组名/磁盘/目录/文件名
6、配置nginx访问文件
安装nginx
安装gcc yum install gcc‐c++
安装pcre库 yum install ‐y pcre pcre‐devel
安装zlib库 yum install ‐y zlib zlib‐devel
安装openssl库 yum install ‐y openssl openssl‐devel
解压 tar -zxvf nginx-1.22.1-tar.gz
进入解压目录 执行 ./configure
编译 make & make install
修改nginx.conf配置文件 vim /usr/local/nginx/conf/nginx.conf
location /group1/M00 {
alias /tools/fdfs_storage_data/data; #storage存储文件的data路径
}
重启nginx /usr/local/nginx/sbin/nginx -s reload
访问
http://ip:80/group1/M00/00/00/wKiIh2SbzNCAAjD3AADMLPdP-Nk403.png
7、fastdfs配置nginx模块
FastDFS通过Tracker服务器,将文件放在Storage服务器存储,但是同组存储服务器之间需要进行文件复制,有同步延迟的问题。假设 Tracker 服务器将文件上传到了A,上传成功后文件 ID已经返回给客户端。此时 FastDFS 存储集群机制会将这个文件同步到同组存储B,在文件还没有复制完成的情况下,客户端如果用这个文件ID在A上取文件,就会出现文件无法访问的错误。而 fastdfs-nginx-module 可以重定向文件链接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误。
解压安装包
unzip fastdfs-nginx-module-master.zip
,停掉nginx
/usr/local/nginx/sbin/nginx -s stop
,进入nginx安装目录添加模块
./configure --add-module=../fastdfs-nginx-module-master/src
,然后编译安装
make
、
make install
,最后查看nginx模块
/usr/local/nginx/sbin/nginx -V
复制fastdfs-nginx-module源码中的配置文件到/etc/fdfs,
cp mod_fastdfs.conf /etc/fdfs/
修改配置如下
connect_timeout=10
base_path=/tools/fdfs_nginx #日志存放目录
tracker_server=ip:22122 #tracker服务
url_have_group_name = true #如果文件ID的uri中包含/group**,则要设置为true
store_path0=/tools/fdfs_storage_data #文件存放目录,和storage保持一致
然后修改nginx配置文件,修改监听端口为storage的http端口,然后添加如下内容
location ~/group([0-9])/M00 {
ngx_fastdfs_module;
}
重启nginx,重新访问8888端口的图片,访问成功,配置成功
至此,FastDFS的单机安装部署完成,若想要配置集群模式,只需要将tracker和storage多配置几个节点,然后storage里面配好多个tracker的信息即可。
SpringBoot集成
1、依赖&配置
<!--fastDfs-->
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
我这里创建的是properties类型的配置文件,根据开源网站
https://github.com/happyfish100/fastdfs-client-java
的README的提示,将文件命名为
fastdfs-client.properties
,放在source下,加载方式有如下几种
加载 properties 格式文件配置:
ClientGlobal.initByProperties("fastdfs-client.properties");
ClientGlobal.initByProperties("config/fastdfs-client.properties");
ClientGlobal.initByProperties("/opt/fastdfs-client.properties");
ClientGlobal.initByProperties("C:\\Users\\James\\config\\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
fastdfs.tracker_servers = ip:22122
可以在代码中加入本行代码,检查加载配置结果
System.out.println("ClientGlobal.configInfo(): " + ClientGlobal.configInfo());
加载成功的输出如下
ClientGlobal.configInfo(): {
g_connect_timeout(ms) = 5000
g_network_timeout(ms) = 30000
g_charset = UTF-8
g_anti_steal_token = false
g_secret_key = FastDFS1234567890
g_tracker_http_port = 80
trackerServers = ip:22122
}
2、文件上传
package com.example.test.fastDfs;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
/**
* @author zy_ys
*/
public class fast {
static StorageClient1 storageClient;
static TrackerServer trackerServer;
public void init() {
try{
//加载fastDFS客户端配置文件
ClientGlobal.initByProperties("fastdfs-client.properties");
//检查加载结果
System.out.println("ClientGlobal.configInfo(): " + ClientGlobal.configInfo());
//创建tracker客户端
TrackerClient trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
StorageServer storageServer = null;
//创建storage客户端
storageClient = new StorageClient1(trackerServer,storageServer);
}catch (Exception e){
e.printStackTrace();
}
}
public void destroy(){
try{
trackerServer.close();
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
fast f = new fast();
f.init();
f.testQuery();
f.destroy();
}
public void testUpload(){
try{
//文件元信息
NameValuePair[] nameValuePairs = new NameValuePair[1];
nameValuePairs[0] = new NameValuePair("fileName","iu.jpeg");
//执行上传
String fileId = storageClient.upload_file1("C:\\Users\\zy_ys\\Desktop\\壁纸\\iu.jpeg","jpeg",nameValuePairs);
System.out.println(fileId);
}catch (Exception e){
e.printStackTrace();
}
}
}
3、文件查询
public void testQuery(){
try{
FileInfo fileInfo1 = storageClient.query_file_info("group1","M00/00/00/wKiIh2SdLxGAJa56AAH0QK31_6c47.jpeg");
FileInfo fileInfo2 = storageClient.query_file_info1("group1/M00/00/00/wKiIh2SdLxGAJa56AAH0QK31_6c47.jpeg");
System.out.println(fileInfo1);
System.out.println(fileInfo2);
//查询元信息
NameValuePair[] nameValuePairs = storageClient.get_metadata1("group1/M00/00/00/wKiIh2SdLxGAJa56AAH0QK31_6c47.jpeg");
System.out.println(nameValuePairs);
}catch (Exception e){
e.printStackTrace();
}
}
4、文件下载
public void testDown(){
try{
byte[] bytes = storageClient.download_file1("group1/M00/00/00/wKiIh2SdLxGAJa56AAH0QK31_6c47.jpeg");
File file = new File("C:\\Users\\zy_ys\\Desktop\\down_iu.jpeg");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bytes);
fileOutputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
上面展示了基本的上传下载的Java API调用,实际上,我们应用中是需要封装一个可重复使用的项目去连接FastDFS,这里给出一个开源的工具
https://github.com/bojiangzhou/lyyzoo-fastdfs-java
5、开启token验证
前面,我们可以直接根据nginx访问图片,这种显然不安全,FastDFS提供了一种token验证机制,需要在访问地址上拼接token才能访问。我们先配置服务端,修改http.conf,内容如下
http.anti_steal.check_token = true #开启token验证
http.anti_steal.token_ttl = 900 #token失效时间,单位s
http.anti_steal.secret_key = FastDFS1234567890 #密钥,与客户端的fastdfs.http_secret_key保持一致
http.anti_steal.token_check_fail = /etc/fdfs/anti-steal.jpg #token检查失败返回页面
全部重启后,发现访问不到文件,然后修改客户端配置
fastdfs.http_anti_steal_token = true
fastdfs.http_secret_key = FastDFS1234567890
然后客户端生成token,代码如下
public void getToken(){
String filePath = "group1/M00/00/00/wKiIh2SdLxGAJa56AAH0QK31_6c47.jpeg";
String secretKey = "FastDFS1234567890";
String token = "";
int ts = (int) Instant.now().getEpochSecond();
try{
token = ProtoCommon.getToken(getFilename(filePath),ts,secretKey);
}catch (Exception e){
e.printStackTrace();
}
StringBuilder sb = new StringBuilder();
sb.append("token=").append(token);
sb.append("&ts=").append(ts);
System.out.println(sb.toString());
}
public String getFilename(String fileId){
String[] results = new String[2];
StorageClient1.split_file_id(fileId, results);
return results[1];
}
最后在访问路径拼接token信息,访问
访问成功,至此,FastDFS的基本使用搞定!!!