一、概念
1、FastDFS是啥?
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
2、包括啥?
FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。
-
跟踪器主要做调度工作,在访问上起负载均衡的作用。
-
存储节点用来存储文件,完成文件管理的所有功能:存储、同步和提供存取接口,FastDFS同时对文件的meta data进行管理。所谓文件的meta data就是文件的相关属性,以键值对(key value pair)方式表示,如:width=1024,其中的key为width,value为1024。文件meta data是文件属性列表,可以包含多个键值对。
3、上传文件交互过程
- client询问tracker上传到的storage,不需要附加参数;
- tracker返回一台可用的storage;
- client直接和storage通讯完成文件上传。
4、下载文件交互过程
- client询问tracker下载文件的storage,参数为文件标识(卷名和文件名);
- tracker返回一台可用的storage;
- client直接和storage通讯完成文件下载。
二、Docker安装FastDFS
1、 拉取镜像
docker pull delron/fastdfs
2、构建tracker容器(跟踪服务器,起调度作用)
docker run -d --network=host --name tracker -v /mydata/fastdfs/tracker:/var/fdfs delron/fastdfs tracker
3、构建storage容器 (存储文件、文件管理)
docker run -d --network=host --name storage -e TRACKER_SERVER=47.94.93.93:22122 -v /mydata/fastdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage
4、配置nginx
默认配置不修改也可以,如果外部端口与8888冲突,则可修改下端口号
- 使用
docker exec -it storage /bin/bash
进入storage容器 - 进入
/usr/local/nginx/conf
目录下,打开nginx.conf
文件
3.进入/etc/fdfs
目录,打开storage.conf
文件
此处端口号和nginx监听的端口号一致
5、测试上传文件
-
在启动storage的时候,我们将
/mydata/fastdfs/storage
挂载到了容器中/var/fdfs
的位置,此时我在宿主机上对应位置放一张图片
-
使用
docker exec -it storage /bin/bash
进入storage容器 -
运行如下命令
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /var/fdfs/backend.png
此时该图片已上传至文件系统 -
使用url进行访问 http://ip:port/group1/M00/00/00/rBa6BWDUSsGAbcr-AAf-SZhISJQ290.png
至此,fastdfs 安装完成.
三、SpringBoot中的使用
1.添加maven依赖
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.27.2</version>
</dependency>
2.在application.yml中添加配置
fdfs:
connect-timeout: 6000 #连接超时时间
so-timeout: 6000 #读取超时时间
tracker-list: 47.94.93.93:22122 #tracker服务所在的ip地址和端口号
3.上传和下载文件具体代码
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("fdfs")
public class CenterUserController {
@Autowired
private FastFileStorageClient fastFileStorageClient;
@PostMapping("upload")
public String uploadFace(MultipartFile file) throws Exception {
String path = "";
if (file != null) {
// 获得文件上传的文件名称
String fileName = file.getOriginalFilename();
if (StringUtils.isNotBlank(fileName)) {
String fileNameArr[] = fileName.split("\\.");
//获取文件的后缀名
String suffix = fileNameArr[fileNameArr.length - 1];
StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(),
file.getSize(),
suffix, null);
System.out.println(storePath.getFullPath());
path = storePath.getFullPath();
} else {
throw new RuntimeException("文件名不能为空");
}
}
return path;
}
@GetMapping("/download")
public void downloadFile(String fileUrl, HttpServletResponse response) throws IOException {
String group = fileUrl.substring(0, fileUrl.indexOf("/"));
String path = fileUrl.substring(fileUrl.indexOf("/") + 1);
String[] ss = fileUrl.split("\\.");
String suffix = ss[ss.length-1];
String fileName = System.currentTimeMillis()+"."+suffix;
DownloadByteArray downloadByteArray = new DownloadByteArray();
byte[] bytes = fastFileStorageClient.downloadFile(group, path, downloadByteArray);
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.setCharacterEncoding("UTF-8");
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
测试结果:
四、问题
1.在测试过程中,可以上传文件,但是使用url访问的时候访问不到。
这个问题困扰了我好久,最后经过排查,发现自己下载镜像不对,下载成了season/fastdfs
这个镜像,按照上文内容应该是下载delron/fastdfs
。
其实使用season/fastdfs
镜像部署完成后,我通过挂载的方式将上传文件的存储目录放在了宿主机的目录里,然后在外部再启动一个nginx,将该目录又挂载到nginx容器内部,这样的话,也可以实现使用nginx访问文件的需求。
所以我的理解就是delron/fastdfs
这个版本的镜像是比较全的,含有fastdfs以及nginx以及其相关的配置,所以当tracker和storage两个容器启动之后,storage内部会自动启动nginx,所以可以使用nginx配置文件中监听的ip和port进行访问。
而season/fastdfs没有内置nginx以及其相关的配置,需要自己手动去添加并配置。需要在启动了tracker和storage容器之后,在storage容器内部下载nginx及其相关的配置并启动,才能在外部使用nginx配置文件中监听的ip和port进行访问。
2.在文中,只是实现了FastDfs单组存储配置的搭建,多组存储配置仅提供思路。
storage集群的配置
-
在多个服务器上部署storage容器,修改容器内的storage.conf和mod_fastdfs.conf,将tracker_server指向同一个ip:port
-
在一个storage容器中部署多卷,则需要修改配置mod_fastdfs.conf,
group_count = 0 #0代表单组,非零代表多组,一般设置几就为几组
tracker集群的配置
- 多个服务器部署tracker容器,并在tracker前使用nginx对多台tracker进行反向代理,负载均衡管理。
- 修改所有storage容器中的storage.conf和mod_fastdfs.conf,将其tracker_server配置成多台机器
五 应用场景:
三台服务器分别做三组存储,并且需要两台tracker地址做主备关系,当一台down机后需要另外一台可以提供正常的访问连接
需要保障数据不丢失,可以分别每台存储配置两组group(相同group之间数据会自动备份) ,三台服务器group分别为:
第一台服务器:group1 group2
第二台服务器:group1 group3
第三台服务器:group2 group3