快速搭建FastDFS 分布式文件管理系统(亲测多次,五分钟搭建、附FastDFS相关压缩包)
声明
本文目录
文章目录
参考说明
本文参考了江南一点雨的文章以及视频,原文地址
基础知识说明
本文建立在读者了解基础的nginx知识,以及已经搭建好nginx服务器的基础上。如果没有该基础,可以看下之前的文章,或者b站等渠道学习一下。
之前的文章地址
版本说明
- 搭建fastDFS系统主要需要以下三个压缩包文件
- 注意以上版本都是经过本人亲测的(配置不难,版本兼容踩坑许久的结果)
注:nginx也是需要的,我使用的是nginx1.21.3版本,直接官网下载即可。
一、基础知识
什么是FastDFS
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
为什么需要 FastDFS
传统的企业级开发对于高并发要求不是很高,而且数据量可能也不大,在这样的环境下文件管理可能非常 Easy。
为什么需要FastDFS
但是互联网应用访问量大、数据量大,在互联网应用中,我们必须考虑解决文件大容量存储和高性能访问的问题,而 FastDFS就特别适合干这件事情,常见的图片存储、视频存储、文档存储等等我们都可以采用 FastDFS 来做。
FastDFS能做哪些事
- 文件存储
- 文件同步
- 文件上传
- 文件下载
FastDFS 官网的系统架构图
从上面这张图中我们可以看到,FastDFS 架构包括 Tracker 和Storage 两部分,看名字大概就能知道,Tracker用来追踪文件,相当于是文件的一个索引,而 Storage 则用来保存文件。
我们上传文件的文件最终保存在 Storage 上,文件的元数据信息保存在 Tracker 上,通过 Tracker 可以实现对Storage 的负载均衡。
Storage 一般会搭建成集群,一个 Storage Cluster可以由多个组构成,不同的组之间不进行通信,一个组又相当于一个小的集群,组由多个 Storage Server 组成,组内的 StorageServer 会通过连接进行文件同步来保证高可用。
二、正式搭建FastDFS
安装之前先开放一些端口,避免启动服务出错
23000、22122。
最终效果描述:通过一个简单的springboot程序来上传以及下载访问文件。
工作内容:
- Tracker 安装
- Storage 安装
- Nginx 安装
1、Tracker 安装
Tracker 安装需要c的环境(因为是 FastDFS 采用 C 语言开发)、libevent 库、libfastcommon。
- 安装 gcc 环境
yum install gcc-c++
完毕
- libevent 库
yum -y install libevent
完毕
- libfastcommon库(注意不要随便下载版本,各种坑)
这个我上边声明部分就已经给出了gitee的地址,直接下载下来就行,然后放到/usr/local目录下
依次执行命令
cd /usr/local 切换到该目录下
tar -zxvf V1.0.38.tar.gz 解压文件
cd libfastcommon-1.0.38 切换至该目录下
./make.sh 编译文件
./make.sh install 安装文件
期间无任何报错信息即可
接下来我们下载 Tracker,注意,由于 Tracker 和 Storage 是相同的安装包,所以下载一次即可(同样gitee已经已经上传了,可以直接下载)
cd /usr/local 切换到该目录
tar -zxvf V5.11.tar.gz 解压文件
cd fastdfs-5.11/ 切换到解压后的文件目录下
./make.sh 编译
./make.sh install 安装
期间无报错信息
安装成功后,执行如下命令,将安装目录内 conf 目录下的配置文件拷贝到 /etc/fdfs 目录下:
cd conf/
cp ./* /etc/fdfs/
注意目录名不要搞错
接下来进入 /etc/fdfs/ 目录下进行配置:
- 配置tracker.conf文件
vi tracker.conf
指定端口和配置一下元数据的保存目录
创建配置一下元数据的保存目录(上面我们已经指定了工作目录,接下来去创建)
启动
接下来执行如下命令启动 Tracker:
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start
如此之后,我们的 Tracker 就算安装成功了。
2、Storage 安装
简单起见,这里我们搭建一个 Storage 实例即可。Storage 安装也需要 libevent libfastcommon,这两个库的安装参考上文,这里我不在细说。
Storage 本身的安装,也和 Tracker 一致,执行命令也都一样,因为我这里将 Tracker 和 Storage安装在同一台服务器上,所以不用再执行安装命令了(相当于安装 Tracker 时已经安装了 Storage 了)。
唯一要做的,就是进入到 /etc/fdfs 目录下,配置 Storage:
vi storage.conf
- 修改base_path目录
- 修改store_path0目录和tracker_server的ip地址
注意这里ip不能写成127.0.0.1(亲测出现问题)
保存退出
配置完成后,执行如下命令启动 Storage:
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start
启动
3、上传文件
注意如果出现上传失败,请检查防火墙是否关闭,或者开放端口(23000、22122),然后重启服务(Tracker服务、Storage服务)
相关的代码我都放到gitee上了,可以自行查看 gitee地址
引入jar包:
<!--fastDFS的jar包-->
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
<dependency>
<groupId>fastdfs-client</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.25</version>
</dependency>
测试类展示:
@Test
void fileUpLoad() throws MyException, IOException {
ClientGlobal.initByProperties("fastdfs-client.properties");
TrackerClient trackerClient=new TrackerClient();
TrackerServer trackerServer=trackerClient.getConnection();
StorageServer storageServer=null;
StorageClient1 storageClient1= new StorageClient1(trackerServer,storageServer);
NameValuePair nameValuePair[]=null;
//指定文件目录,以及文件后缀名
String fileID=storageClient1.upload_file1("D:\\1.png","png",nameValuePair);
System.out.println(fileID);
}
fastdfs-client.properties
# file_server_addr=file.onepass.com:80
# max_storage_connection=8
fastdfs.connect_timeout_in_seconds=20
fastdfs.network_timeout_in_seconds=30
fastdfs.charset=UTF-8
fastdfs.http_anti_steal_token=false
fastdfs.http_secret_key=superOak
# TrackerServer port
fastdfs.http_tracker_http_port=80
## Tracker Server, if more than one, separate with ","
#fastDFS的ip地址
fastdfs.tracker_servers=192.168.1.8:22122
# fastdfs.connection_pool.enabled=true
然后执行测试
注意一旦出现错误,检查防火墙以及端口开放问题。
4、下载文件
接上面,再写一个测试
@Test
void fileDownLoad() throws MyException, IOException {
ClientGlobal.initByProperties("fastdfs-client.properties");
TrackerClient trackerClient=new TrackerClient();
TrackerServer trackerServer=trackerClient.getConnection();
StorageServer storageServer=null;
StorageClient1 storageClient1= new StorageClient1(trackerServer,storageServer);
NameValuePair nameValuePair[]=null;
byte[] bytes=storageClient1.download_file1("group1/M00/00/00/wKgBCGFO8riAQBgzAABAIwzlD3c515.png");
FileOutputStream fos=new FileOutputStream(new File("D:\\10.png"));
fos.write(bytes);
fos.close();
}
5、配置nginx模块
我们还需要提供一个图片的访问功能,目前来说最佳方案当然是 Nginx 了,所以我们这里连同 Nginx 一起配置好,再来做测试。
Nginx 的安装分为两个步骤:
- 安装 Nginx(此处省略,可以看之前的文章之前的文章地址)
- 首先在 Storage 下安装 fastdfs-nginx-module
首先下载 fastdfs-nginx-module(上面gitee仓库中有,或者自己百度下,版本一定要小心)
cd /usr/local
tar -zxvf fastdfs-nginx-module_v1.16.tar.gz
然后将 /usr/local/fastdfs-nginx-module/src/mod_fastdfs.conf
文件拷贝到 /etc/fdfs/
目录下,并修改该文件的内容:
ip地址、是否使用组名(true)、目录名
保存退出
接下来,回到下载的 nginx 安装文件的解压目录中,执行如下命令,重新配置编译安装:
该目录如下:
埋个坑
./configure --add-module=/usr/local/fastdfs-nginx-module-1.22/src
make
make install
发现
make
以及make install
都出现一下问题。
解决问题
执行ln -s /usr/include/fast* /usr/local/include/
,然后再次执行make
以及make install
,没有问题了,如下
安装完成后,修改 nginx 的配置文件,如下:
vi /usr/local/nginx/conf/nginx.conf
代码如下:
location ~/group([0-9]) {
ngx_fastdfs_module;
}
保存,然后启动nginx(或者重启nginx)
如图
接下来访问一下试一下
6、安全问题
现在,任何人都可以访问我们服务器上传文件,这肯定是不行的,这个问题好解决,加一个上传时候的令牌即可。
首先我们在服务端开启令牌校验:
vi /etc/fdfs/http.conf
配置完成后,记得关闭、在启动nginx服务端:
cd /usr/local/nginx/sbin
./nginx -s stop
./nginx
此时我们再次访问该图片如下
接下来我们写一个带有令牌的链接生成程序
@Test
void hasTokenUrl() throws MyException, UnsupportedEncodingException, NoSuchAlgorithmException {
String filename="M00/00/00/wKgBCGFO8riAQBgzAABAIwzlD3c515.png";
String key="123456";
String ip="http://192.168.1.8";
String groupFilename="/group1/"+filename;
int ts = (int) Instant.now().getEpochSecond();
//根据文件名、时间、密钥生成token
String token = ProtoCommon.getToken(filename, ts, key);
StringBuilder sb = new StringBuilder();
sb.append(ip).append(groupFilename).append("?token="+token).append("&ts="+ts);
System.out.println(sb.toString());
}
测试
生成url:
访问测试
7、写一个小例子
目录结构如下:
首先封装一个工具类:
package cn.fastdfs.util;
import org.csource.common.MyException;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
public class FastDFSUtils {
private static String key="123456";
private static StorageClient1 client1=null;
static {
try {
ClientGlobal.initByProperties("fastdfs-client.properties");
TrackerClient trackerClient=new TrackerClient();
TrackerServer trackerServer=trackerClient.getConnection();
client1= new StorageClient1(trackerServer,null);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
}
public static String upload(MultipartFile file){
String oldName=file.getOriginalFilename();
try {
System.out.println(oldName.substring(oldName.lastIndexOf(".")+1));
System.out.println(client1);
return client1.upload_file1(file.getBytes(),oldName.substring(oldName.lastIndexOf(".")+1),null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 因为配置了访问检测,所以写一个返回带密钥的方法
* @param groupFile_url
* @return
* @throws MyException
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public static String getHasTokenUrl(String groupFile_url) throws MyException, UnsupportedEncodingException, NoSuchAlgorithmException {
String filename=groupFile_url.substring(groupFile_url.indexOf("/") + 1);
String ip="http://192.168.1.8";
String groupFilename="/group1/"+filename;
int ts = (int) Instant.now().getEpochSecond();
//根据文件名、时间、密钥生成token
String token = ProtoCommon.getToken(filename, ts, key);
StringBuilder sb = new StringBuilder();
sb.append(ip).append(groupFilename).append("?token="+token).append("&ts="+ts);
System.out.println(sb.toString());
return sb.toString();
}
}
- 接下来写一个controller
package cn.fastdfs.controller;
import cn.fastdfs.util.FastDFSUtils;
import org.csource.common.MyException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
@RestController
public class FastdfsController {
@RequestMapping("/uploadFile")
public Map<String,Object> uploadFile(MultipartFile file) throws MyException, UnsupportedEncodingException, NoSuchAlgorithmException {
Map<String,Object> map=new HashMap<>();
String file_url="";
try{
file_url= FastDFSUtils.upload(file);
}catch (Exception e){
map.put("url","");
map.put("code","500");
map.put("status","error");
map.put("msg","上传出现故障,请稍后再试");
return map;
}
if (file_url==null||file_url==""){
map.put("url","");
map.put("code","500");
map.put("status","error");
map.put("msg","上传出现失败");
return map;
}
file_url=FastDFSUtils.getHasTokenUrl(file_url);
map.put("url",file_url);
map.put("code","200");
map.put("status","success");
map.put("msg","上传成功");
System.out.println(file_url);
return map;
}
}
最后写一个前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
<link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.6/lib/theme-chalk/index.css">
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
<el-upload
action="/uploadFile"
:on-preview="handlePreview"
accept=""
:limit="10">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</div>
</body>
<script>
new Vue({
el: '#app',
methods:{
handlePreview(file){
window.open(file.response.url);
}
}
})
</script>
</html>
代码等相关文件都已经上传git,感谢收看!!