搭建FastDFS文件服务器
Posted 即使再小的帆也能远航!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搭建FastDFS文件服务器相关的知识,希望对你有一定的参考价值。
介绍
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件上传下载等,解决了大容量存储和负载均衡的问题。特别适合以中小文件为载体的服务
注意:FastDFS只能上传小于500MB的文件
FastDFS系统有三个角色:跟踪服务器,存储服务器 ,客户端
跟踪服务器(Tracker Server):主要负责管理所有的Storage Server和group,每个Storage启动后会连接Tracker Server发送自己所属的group信息,并且保持周期性的心跳发送信息
存储服务器(Storage Server):主要提供存储以及备份服务,以group为单位,每个group有多台Storage Server,并且之间的数据相互同步备份
客户端(Client):主要发送上传和下载请求
存储策略
为了支持大容量,服务器采用了分卷或分组的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量
上传流程
1.Tracker Server和Storage Server建立连接,并定时检查group的信息
2.Client发送上传请求到Tracker Server
3.Tracker Server检查有没有可用的Storage,并返回可用的Storage
4.Client携带文件数据开始上传文件到Storage Server
5.Storage Server将文件写入磁盘,并返回文件的相对路径(group名+文件名)
6.Client接收相对路径并拼接服务器地址为完整的路径
FastDFS环境搭建
1.下载安装libfastcommon
libfastcommon是从 FastDFS 和 FastDHT 中提取出来的公共 C 函数库,基础环境,只需安装即可 。
下载
https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
解压
tar -zxvf V1.0.43.tar.gz
编译、安装
cd libfastcommon-1.0.43
./make.sh && ./make.sh install
2.下载安装FastDFS
下载
https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
解压
tar -zxvf V6.06.tar.gz
编译、安装
cd fastdfs-6.06
./make.sh && ./make.sh install
默认安装后的文件与目录
1.服务脚本
/etc/init.d/fdfs_storaged
/etc/init.d/fdfs_tracker
2.配置文件,这是作者给的样式文件,可以根据修改
/etc/fdfs/client.conf.sample
/etc/fdfs/storage.conf.sample
/etc/fdfs/tracker.conf.sample
3.命令工具,在/usr/bin
目录下
fdfs_appender_test
fdfs_appender_test1
fdfs_append_file
fdfs_crc32
fdfs_delete_file
fdfs_download_file
fdfs_file_info
fdfs_monitor
fdfs_storaged #启动 storage server
fdfs_test #测试
fdfs_test1
fdfs_trackerd #启动tracker server
fdfs_upload_appender
fdfs_upload_file
stop.sh
restart.sh
3.配置Tracker Server
1.进入/etc/fdfs
目录,复制跟踪服务器的样式文件tracker.conf.sample
,重命名为tracker.conf
cp tracker.conf.sample tracker.conf
2.编辑tracker.conf
,修改重要配置
vim tracker.conf
# 配置文件是否不生效,默认false为生效
disabled=false
# 提供服务的端口,默认
port=22122
# Tracker 数据和日志目录地址(根目录必须存在,子目录会自动创建)
base_path=/usr/local/fastdfs/tracker
# HTTP 服务端口
http.server_port=80
3.创建base_path
mkdir -p /usr/local/fastdfs/tracker
4.防火墙中打开tracker服务端口22122,安全组
#添加22122端口
firewall-cmd --permanent --zone=public --add-port=22122/tcp
#开启防火墙
systemctl start firewalld.service
#重启防火墙
sudo service firewalld restart
#查看端口列表
firewall-cmd --permanent --list-port
#禁用防火墙
systemctl stop firewalld
#查看防火墙状态
systemctl status firewalld
5.启动tracker
/etc/init.d/fdfs_trackerd start
6.查看是否启动成功
netstat -unltp|grep fdfs
7.设置tracker开启自动启动
chkconfig fdfs_trackerd on
8.tracker启动后,会在base_path下创建data
、log
目录,目录结构:
${base_path}
|__data
| |__storage_groups.dat:存储分组信息
| |__storage_servers.dat:存储服务器列表
|__logs
| |__trackerd.log: tracker server 日志文件
4.配置Storage Server
1.进入 /etc/fdfs
目录,复制存储服务器的样式文件 storage.conf.sample
,并重命名为 storage.conf
cp storage.conf.sample storage.conf
2.编辑storage.conf
vim storage.conf
# 配置文件是否不生效,false 为生效
disabled=false
# 指定此 storage server 所在 组(卷)
group_name=group1
# storage server 服务端口
port=23000
# Storage 数据和日志目录地址(根目录必须存在,子目录会自动生成)
base_path=/usr/local/fastdfs/storage
# 存放文件时 storage server 支持多个路径。这里配置存放文件的基路径数目,通常只配一个目录。
store_path_count=1
# 逐一配置 store_path_count 个路径,索引号基于 0。
# 如果不配置 store_path0,那它就和 base_path 对应的路径一样。
store_path0=/usr/local/fastdfs/storage
# FastDFS 存储文件时,采用了两级目录。这里配置存放文件的目录个数。
# 如果本参数只为 N(如: 256),那么 storage server 在初次运行时,会在 store_path 下自动创建 N * N 个存放文件的子目录。
subdir_count_per_path=256
# tracker_server 的列表 ,会主动连接 tracker_server
# 有多个 tracker server 时,每个 tracker server 写一行
tracker_server=127.0.0.1:22122
#tracker_server=127.0.0.1:22122
# 访问端口
http.server_port=80
3.创建base_path
mkdir -p /usr/local/fastdfs/storage
4.防火墙中打开tracker服务端口23000,安全组
#添加22122端口
firewall-cmd --permanent --zone=public --add-port=23000/tcp
#开启防火墙
systemctl start firewalld.service
#重启防火墙
sudo service firewalld restart
#查看防火墙端口列表
firewall-cmd --permanent --list-port
#禁用防火墙
systemctl stop firewalld
#查看防火墙状态
systemctl status firewalld
5.启动storage
/etc/init.d/fdfs_storaged start
查看是否启动成功
netstat -unltp|grep fdfs
查看storage是否和tracker连接成功
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
6.设置tracker开启自动启动
chkconfig fdfs_storaged on
7.storage启动后,会在base_path下创建data
、log
目录,目录结构:
${base_path}
|__data
|_ N*N个目录
|__logs
| |__trackerd.log: tracker server 日志文件
5.文件上传测试
1.进入 /etc/fdfs
目录,复制客户端样式文件client.conf.sample
,并重命名为 client.conf
cp client.conf.sample client.conf
2.编辑client.conf
vim client.conf
# Client 的数据和日志目录
base_path=/usr/local/fastdfs/client
# Tracker端口
tracker_server=127.0.0.1:22122
3.创建base_path
mkdir -p /usr/local/fastdfs/client
4.上传测试
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf 文件路径
上传成功会返回相对路径,格式为group名/存储目录/一级目录/二级目录/文件名
nginx环境搭建
安装Nginx所需的依赖
sudo yum -y install gcc
sudo yum -y install pcre-devel
sudo yum -y install zlib zlib-devel
sudo yum -y install openssl openssl-devel
下载nginx
wget https://nginx.org/download/nginx-1.10.3.tar.gz
解压
tar -zxvf nginx-1.10.3.tar.gz
cd cd nginx-1.10.3
配置
./configure
编译、安装
make && make install
进入安装后的目录,默认为
/usr/local/nginx
cd /usr/local/nginx
启动nginx
cd sbin
./nginx
停止Nginx
./nginx stop
平滑重启nginx
./nginx -s reload
查看nginx版本及模块
./nginx -V
访问文件
修改nginx.conf
vim /usr/local/nginx/conf/nginx.conf
#添加如下行,将 /group1/M00 映射到 storage base_path目录
location /group1/M00 {
alias /usr/local/fastdfs/storage/data;
}
# 重启nginx
/usr/local/nginx/sbin/nginx -s reload
访问之前上传的图片,在之前返回的相对路径前拼接服务器地址,这里的127.0.0.1是我模拟的
http://127.0.0.1/group1/M00/00/00/cH5Sbl65g1CAWd6JAAH553eRc5M827.jpg
FastDFS配置Nginx模块
下载
wget https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.22.tar.gz
解压
tar -zxvf V1.22.tar.gz
cd fastdfs-nginx-module-1.22
配置Nginx
# 先停掉nginx服务
/usr/local/nginx/sbin/nginx -s stop
进入解压包目录
cd /softpackages/nginx-1.10.3/
# 添加模块
./configure --add-module=../fastdfs-nginx-module-master/src
重新编译、安装
make && make install
查看nginx的模块
/usr/local/nginx/sbin/nginx -V
有这个说明添加模块成功
复制
fastdfs-nginx-module-master/src
中的mod_fastdfs.conf
到/etc/fdfs
目录,并修改
cp /fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/
修改mod_fastdfs.conf
vim mod_fastdfs.conf
# Tracker Server
tracker_server=file.ljzsg.com:22122
#日志文件目录
base_path = /usr/local/fastdgs/tmp
# StorageServer 端口
storage_server_port=23000
# 如果文件ID的uri中包含/group**,则要设置为true
url_have_group_name = true
# Storage 配置的store_path0路径,必须和storage.conf中的一致
store_path0=/usr/local/fastdfs/storage
创建
base_path
mkdir -p /usr/local/fastdgs/tmp
复制 FastDFS 的部分配置文件到/etc/fdfs 目录
cd /softpackages/fastdfs-6.06/conf/
cp anti-steal.jpg http.conf mime.types /etc/fdfs/
配置nginx,修改
nginx.conf
vim /usr/local/nginx/conf/nginx.conf
在server节点的location添加fastdfs-nginx
模块
server {
#与 /etc/fdfs/storage.conf 中的 http.server_port=80 (前面改成80了)相对应
listen 80;
server_name localhost;
#如果上面修改了group_name,将group([0-9])改为配置的group_name
location ~/group([0-9])/M00 {
ngx_fastdfs_module;
}
}
启动nginx
/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx
有该说明配置成功
在地址栏访问http://127.0.0.1/group1/M00/00/00/cH5Sbl65g1CAWd6JAAH553eRc5M827
Java集成
fastdfs-client
1.导入fastdfs
依赖到pom.xml
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--fastdfs-->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.27.2</version>
</dependency>
2.application.yml
配置fastdfs
fdfs:
connect-timeout: 30 #连接超时时间 秒
so-timeout: 30 #读取超时时间 秒
tracker-list: 192.168.169.250:22122 #tracker server的ip和端口
file:
host: http://192.168.169.250/ #文件host路径
3.开始上传
FastFileStorageClient:FastDFS提供的客户端类,用于上传下载文件
/**
* 上传一般文件
*
* @param inputStream 文件输入流
* @param fileSize 文件大小
* @param fileExtName 文件后缀名
* @param metaDataSet 元数据集
* @return
*/
StorePath uploadFile(InputStream inputStream, long fileSize, String fileExtName, Set<MetaData> metaDataSet);
StorePath:上传文件后返回的类,用于获取路径
getFullPath(); //获取全路径
storePath.getGroup(); //获取group_name
storePath.getPath(); //获取路径
/**
* @Desc: 文件上传
*/
@RestController
public class FileController {
//注入文件host路径
@Value("${file.host}")
String fileHost;
//fastdfs提供的客户端
@Autowired
FastFileStorageClient storageClient;
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
String fullPath = "";
if (file != null) {
//获取文件名称 xxx.jpg
String fileName = file.getOriginalFilename();
if (StringUtils.isNotBlank(fileName)) {
//获取文件的后缀名
String[] splitFileName = fileName.split(".");
String fileExtName = splitFileName[splitFileName.length - 1];
try {
StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), fileExtName, null);
fullPath = storePath.getFullPath();
// group1/M00/00/00/wKip-l66eNiACV7JAAGqkGAODus33.jpeg
System.out.println("File Path === " + fullPath);
// 将图片存储数据库...
} catch (IOException e) {
e.printStackTrace();
}
}
}
//返回最终路径 http://192.168.169.250/group1/M00/00/00/wKip-l66eNiACV7JAAGqkGAODus33.jpeg
return fileHost + fullPath;
}
}
fastdfs-client-java
1.导入fastdfs-client-java
依赖到pom.xml
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
2.工具类copy到项目中
/**
* FastDFS工具类【实现文件上传、下载、删除、查询】
*
* @author Zhangyongliang
*/
public class FastDFSClient {
private TrackerClient trackerClient = null;
private TrackerServer trackerServer = null;
private StorageServer storageServer = null;
private StorageClient1 storageClient = null;
public FastDFSClient(String conf) throws Exception {
if (conf.contains("classpath:")) {
String path = URLDecoder.decode(getClass().getProtectionDomain().getCodeSource().getLocation().toString(), "UTF-8");
path = path.substring(6);
conf = conf.replace("classpath:", URLDecoder.decode(path, "UTF-8"));
}
ClientGlobal.init(conf);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
storageClient = new StorageClient1(trackerServer, storageServer);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
*
* @param fileName 文件全路径
* @param extName 文件扩展名,不包含(.)
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(String fileName, String extName, NameValuePair[] metas) {
String result = null;
try {
result = storageClient.upload_file1(fileName, extName, metas);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
}
/**
* 上传文件,传fileName
*
* @param fileName 文件的磁盘路径名称 如:D:/image/aaa.jpg
* @return null为失败
*/
public String uploadFile(String fileName) {
return uploadFile(fileName, null, null);
}
/**
* @param fileName 文件的磁盘路径名称 如:D:/image/aaa.jpg
* @param extName 文件的扩展名 如 txt jpg等
* @return null为失败
*/
public String uploadFile(String fileName, String extName) {
return uploadFile(fileName, extName, null);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
*
* @param fileContent 文件的内容,字节数组
* @param extName 文件扩展名
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) {
String result = null;
try {
result = storageClient.upload_file1(fileContent, extName, metas);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
}
/**
* 上传文件
*
* @param fileContent 文件的字节数组
* @return null为失败
* @throws Exception
*/
public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
}
/**
* 上传文件
*
* @param fileContent 文件的字节数组
* @param extName 文件的扩展名 如 txt jpg png 等
* @return null为失败
*/
public String uploadFile(byte[] fileContent, String extName) {
return uploadFile(fileContent, extName, null);
}
/**
* 文件下载到磁盘
*
* @param path 图片路径
* @param output 输出流 中包含要输出到磁盘的路径
* @return -1失败,0成功
*/
public int download_file(String path, BufferedOutputStream output) {
int result = -1;
try {
byte[] b = storageClient.download_file1(path);
try {
if (b != null) {
output.write(b);
result = 0;
}
} catch (Exception e) {
} //用户可能取消了下载
finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 获取文件数组
*
* @param path 文件的路径 如group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return
*/
public byte[] download_bytes(String path) {
byte[] b = null;
try {
b = storageClient.download_file1(path);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return b;
}
/**
* 删除文件
*
* @param group 组名 如:group1
* @param storagePath 不带组名的路径名称 如:M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return -1失败,0成功
*/
public Integer delete_file(String group, String storagePath) {
int result = -1;
try {
result = storageClient.delete_file(group, storagePath);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
}
/**
* @param storagePath 文件的全部路径 如:group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return -1失败,0成功
* @throws IOException
* @throws Exception
*/
public Integer delete_file(String storagePath) {
int result = -1;
try {
result = storageClient.delete_file1(storagePath);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
}
/**
* 获取远程服务器文件资源信息
*
* @param groupName 文件组名 如:group1
* @param remoteFileName M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return
*/
public FileInfo getFile(String groupName, String remoteFileName) {
try {
return storageClient.get_file_info(groupName, remoteFileName);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
3.在resource
目录下创建fdfs_client.properties
配置文件
connect_timeout = 2
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8088 # tracker Http端口
http.anti_steal_token = no # 暂无作用
http.secret_key = FastDFS1234567890 # 暂无作用
tracker_server = 192.168.43.60:22122 # tracker Server地址信息
4.使用工具类上传
/**
* @Desc: 文件上传
*/
@RestController
public class FileController {
//注入文件host路径
@Value("${file.host}")
String fileHost;
@PostMapping("/upload")
public String uploadFast(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
//初始化全局配置。加载一个配置文件。
String confUrl = this.getClass().getClassLoader().getResource("fdfs_client.properties").getPath();
FastDFSClient fastDFSClient = new FastDFSClient(confUrl);
String filePath = "";
if (file != null) {
String fileName = file.getOriginalFilename();
if (fileName != null || !"".equals(fileName)) {
//文件的后缀名
String[] splitFileName = fileName.split(".");
String fileExtName = splitFileName[splitFileName.length - 1];
//开始上传,返回文件路径 group/M00/00/00/xxxxx.xx
filePath = fastDFSClient.uploadFile(file.getBytes(), fileExtName, null);
}
//省略其他
}
return fileHost + filePath;
}
}
以上是关于搭建FastDFS文件服务器的主要内容,如果未能解决你的问题,请参考以下文章