FastDfs分布式文件系统的搭建及使用
本文章是参照江南一点雨发表的博客教程搭建的
https://blog.csdn.net/u012702547/article/details/104589468
在cento7下搭建
1、简介
FastDFS 由淘宝的余庆大佬在 2008 年开源的一款轻量级分布式文件管理系统,FastDFS 用 C 语言实现,支持 Linux、FreeBSD、MacOS 等类 UNIX 系统。FastDFS 类似 google FS,属于应用级文件系统,不是通用的文件系统,只能通过专有 API 访问,目前提供了 C 和 Java SDK ,以及 PHP 扩展 SDK。
这款开源软件从发布至今,历经数十年,这款开源软件的生命力依然旺盛,在业界依然备受推崇,当然这也得益于作者一直在不断完善该软件。
FastDFS 专为互联网应用量身定做,解决大容量文件存储问题,追求高性能和高扩展性,它可以看做是基于文件的 key/value 存储系统,key 为文件 ID,value 为文件内容,因此称作分布式文件存储服务更为合适。
2、架构
- 文件存储
- 文件同步
- 文件上传
- 文件下载
FastDFS 架构包括 Tracker 和 Storage 两部分,看名字大概就能知道,Tracker 用来追踪文件,相当于是文件的一个索引,而 Storage 则用来保存文件。
我们上传文件的文件最终保存在 Storage 上,文件的元数据信息保存在 Tracker 上,通过 Tracker 可以实现对 Storage 的负载均衡。
Storage 一般会搭建成集群,一个 Storage Cluster 可以由多个组构成,不同的组之间不进行通信,一个组又相当于一个小的集群,组由多个 Storage Server 组成,组内的 Storage Server 会通过连接进行文件同步来保证高可用。
3、安装
Tracker 安装
1、需要gcc环境
yum install gcc-c++
2、安装依赖库
yum -y install libevent
另一个库是 libfastcommon,这是 FastDFS 官方提供的,它包含了 FastDFS 运行所需要的一些基础库。
libfastcommon 下载地址:https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
将下载好的 libfastcommon 拷贝至 /usr/local/ 目录下,然后依次执行如下命令:
cd /usr/local
tar -zxvf V1.0.43.tar.gz
cd libfastcommon-1.0.43/
./make.sh
./make.sh install
3、安装
由于 Tracker 和 Storage 是相同的安装包,所以下载一次
安装文件可以从 FastDFS 的 GitHub 仓库上下载,下载地址:https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
下载成功后,将下载文件拷贝到 /usr/local 目录下,然后依次执行如下命令安装:
cd /usr/local
tar -zxvf V6.06.tar.gz
cd fastdfs-6.06/
./make.sh
./make.sh install
安装成功后,执行如下命令,将安装目录内 conf 目录下的配置文件拷贝到 /etc/fdfs 目录下:
cd conf/
cp ./* /etc/fdfs/
4、配置
接下来进入 /etc/fdfs/ 目录下进行配置:
打开 tracker.conf 文件:
vim /etc/fdfs/tracker.conf
port默认为22122
修改元数据存储目录
base_path = /homo/tom/fastdfs //元数据存储目录要真实存在
5、启动
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start
Storage安装
1、安装命令和tacker一样,直接修改配置文件就行了
vim /etc/fdfs/storage.conf
base_path、storage_path0 配置的路径和tracker 配置的路径一致
tracker_server的ip地址为tracker的ip地址端口默认
2、启动
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start
Nginx安装
1、安装依赖
yum -y install pcre-devel
yum -y install openssl openssl-devel
2、解压安装包并进入解压之后的安装包根目录、编译安装
./configure
make
make install
3、装好之后,默认安装位置在 :
/usr/local/nginx/sbin/nginx
4、启动
进入sbin目录下
./nginx
5、如果修改了配置,如下命令重新加载配置文件
./nginx -s reload
安装fastdfs-nginx-module
首先下载 fastdfs-nginx-module,下载地址:https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.22.tar.gz
1、解压安装
2、复制及修改配置文件
然后将 /usr/local/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf
文件拷贝到 /etc/fdfs/
目录下,并修改该文件的内容:
vi /etc/fdfs/mod_fastdfs.conf
修改tracker_server的路径为tracker的ip地址
修改url_have_group_name = true
修改storage_path0 为tracker配置文件下一样路径的地址
3、接下来,回到第一步下载的 nginx 安装文件的解压目录中,执行如下命令,重新配置编译安装:
./configure --add-module=/usr/local/fastdfs-nginx-module-1.22/src
make
make install
4、修改nginx的配置文件
vi /usr/local/nginx/conf/nginx.conf
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GY6X0YiV-1615343119636)(C:\Users\tom\AppData\Roaming\Typora\typora-user-images\image-20210115162329136.png)]
5、配置完成后,启动 nginx,看到如下日志,表示 nginx 启动成功:
./nginx -s stop
./nginx
ngx_http_fastdfs_set pid=9908
疑问:fastdfs-nginx-module 有啥用
看了整个安装过程之后,很多小伙伴有疑问,到头来还是 nginx 本身直接找到了图片文件目录,fastdfs-nginx-module 到底有啥用?
前面我们说过,Storage 由很多组构成,每个组又是一个小的集群,在每一个组里边,数据会进行同步,但是如果数据还没同步,这个时候就有请求发来了,该怎么办?此时fastdfs-nginx-module 会帮助我们直接从源 Storage 上获取文件。
安装成功了。
4、springboot整合Fastdfs
1、添加依赖
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27-SNAPSHOT</version>
</dependency>
2、添加配置文件
在resource目录下添加配置文件fast_client.conf
connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 80
tracker_server = 192.168.6.128:22122
3、写FastDfs文件类
public class FastDFSFile{
private String name;
private byte[] content;
private String ext;
private String md5;
private String author;
//省略get、set方法及构造
}
4、创建FastDFS客户端
public class FastDFSClient {
private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
//寻找fastdfs配置文件
static {
try {
//获取文件的绝对路径
String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
ClientGlobal.init(filePath);
} catch (Exception e) {
logger.error("FastDFS Client Init Fail!",e);
}
}
public static String[] upload(FastDFSFile file) {
logger.info("File Name: " + file.getName() + "File Length:" + file.getContent().length);
NameValuePair[] meta_list = new NameValuePair[1];
meta_list[0] = new NameValuePair("author", file.getAuthor());
long startTime = System.currentTimeMillis();
String[] uploadResults = null;
StorageClient storageClient=null;
try {
storageClient = getTrackerClient();
uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
} catch (IOException e) {
logger.error("IO Exception when uploadind the file:" + file.getName(), e);
} catch (Exception e) {
logger.error("Non IO Exception when uploadind the file:" + file.getName(), e);
}
logger.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms");
if (uploadResults == null && storageClient!=null) {
logger.error("upload file fail, error code:" + storageClient.getErrorCode());
}
String groupName = uploadResults[0];
String remoteFileName = uploadResults[1];
logger.info("upload file successfully!!!" + "group_name:" + groupName + ", remoteFileName:" + " " + remoteFileName);
return uploadResults;
}
public static FileInfo getFile(String groupName, String remoteFileName) {
try {
StorageClient storageClient = getTrackerClient();
return storageClient.get_file_info(groupName, remoteFileName);
} catch (IOException e) {
logger.error("IO Exception: Get File from Fast DFS failed", e);
} catch (Exception e) {
logger.error("Non IO Exception: Get File from Fast DFS failed", e);
}
return null;
}
public static InputStream downFile(String groupName, String remoteFileName) {
try {
StorageClient storageClient = getTrackerClient();
byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
InputStream ins = new ByteArrayInputStream(fileByte);
return ins;
} catch (IOException e) {
logger.error("IO Exception: Get File from Fast DFS failed", e);
} catch (Exception e) {
logger.error("Non IO Exception: Get File from Fast DFS failed", e);
}
return null;
}
public static void deleteFile(String groupName, String remoteFileName)
throws Exception {
StorageClient storageClient = getTrackerClient();
int i = storageClient.delete_file(groupName, remoteFileName);
logger.info("delete file successfully!!!" + i);
}
public static StorageServer[] getStoreStorages(String groupName)
throws IOException {
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getConnection();
return trackerClient.getStoreStorages(trackerServer, groupName);
}
public static ServerInfo[] getFetchStorages(String groupName,
String remoteFileName) throws IOException {
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getConnection();
return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
}
public static String getTrackerUrl() throws IOException {
return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ClientGlobal.getG_tracker_http_port()+"/";
}
private static StorageClient getTrackerClient() throws IOException {
TrackerServer trackerServer = getTrackerServer();
StorageClient storageClient = new StorageClient(trackerServer, null);
return storageClient;
}
private static TrackerServer getTrackerServer() throws IOException {
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getConnection();
return trackerServer;
}
}
5、文件上传
/****
* 上传文件
*
*
* @param file
* @return
*/
@RequestMapping("/upload")
@ResponseBody
public JSONObject singleFileUpload(@RequestParam("file") MultipartFile file) {
JSONObject jsonObject = new JSONObject();
if (file.isEmpty()) {
jsonObject.put("msg","file cannot null");
}
try {
//保存文件
String path=saveFile(file);
jsonObject.put("message","You successfully uploaded '" + file.getOriginalFilename() + "'");
jsonObject.put("path", path);
} catch (Exception e) {
logger.error("upload file failed",e);
}
return jsonObject;
}
/**
* @param multipartFile
* @return
* @throws IOException
*/
public String saveFile(MultipartFile multipartFile) throws IOException {
String[] fileAbsolutePath={};
String fileName=multipartFile.getOriginalFilename();
String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
byte[] file_buff = null;
InputStream inputStream=multipartFile.getInputStream();
if(inputStream!=null){
int len1 = inputStream.available();
file_buff = new byte[len1];
inputStream.read(file_buff);
}
inputStream.close();
FastDFSFile file = new FastDFSFile(fileName, file_buff, ext);
try {
fileAbsolutePath = FastDFSClient.upload(file); //upload to fastdfs
} catch (Exception e) {
logger.error("upload file Exception!",e);
}
if (fileAbsolutePath==null) {
logger.error("upload file failed,please upload again!");
}
return FastDFSClient.getTrackerUrl()+fileAbsolutePath[0]+ "/"+fileAbsolutePath[1];
}