一、什么是FastDFS?
FastDFS是用C语言编写的一款开源的分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务。如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
二、FastDFS组成要素。
1)、FastDFS架构包括跟踪器(Tracker Server)和存储服务节点(Storage Server)。客户端(Client)请求Tracker Server进行文件上传、下载,此跟踪器主要做调度工作,在访问上起负载均衡的作用,返回给客户端一个IP地址和端口。最终是通过调度Storage Server完成文件上传、下载等服务。
2)、跟踪器和存储节点都可以由一台或者多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加和下线而不影响线上服务。其中跟踪器中的所有服务都是对等的,可以根据服务器的压力情况随时增加和减少。
3)、Storage Server的作用是文件存储,客户端上传的文件最终存储在Storage Server服务器上,Storage Server没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。可以将Storage称为存储器。如上图所示:为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统有一个或者多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。
4)、在卷中增加服务器时,同步已有的文件是由系统自动完成的,同步完成后,系统自动将新增服务器切换到线上提供服务。
5)、当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。
6)、重要:FastDFS中的文件标识分为两个部分:卷名和文件名,二者缺一不可。(存储成功后,返回给客户端的两个信息)
三、文件上传及下载流程
【1】、文件上传流程:
客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用户以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名,如下图:
♀ 组名:文件上传后所在Storage卷名称,在上传成功后由Storage服务器返回,客户端自行保存。
♂ 虚拟磁盘路径:Storage配置的虚拟路径,与磁盘选项store_path*对应,如果配置store_path0则是 M00,如果配置了store_1则是 M01,以此类推。
♀ 数据两级目录:storage服务器在每个虚拟磁盘下创建的两级目录,用户存储文件。
♂ 文件名:与文件上传时不同。是由服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数、文件扩展名等信息。
【2】、文件下载流程:
四、最简单的FastDFS架构
五、FastDFS安装
☞ 参考:《FastDFS安装部署文档》
可以解压提供的虚拟机(留言邮箱可私发),双击vmx文件,修改网络配置为“仅主机模式”,启动时选择“我已移动虚拟机”这样会保留原有的配置IP等信息。
六、FastDFS使用Demo
☛ 需求:将图片上传到服务器,在控制台打印服务器返回的信息。
1)、创建 Maven 工程 fastDFSdemo
由于FastDFS客户端jar包并没有在中央仓库中,所以需要使用下列命令手动安装jar包到Maven本地仓库(将jar包放到d盘setup目录)
mvn install:install-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs -Dversion=1.2 -Dpackaging=jar -Dfile=d:\setup\fastdfs_client_v1.20.jar
▁▂▃ pom.xml中引入:
<dependency>
<groupId>org.csource.fastdfs</groupId>
<artifactId>fastdfs</artifactId>
<version>1.2</version>
</dependency>
<!--用于前端上传文件-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
2)、添加配置文件fast_client.conf。主要:将其中的服务器地址设置为:自己的FastDFS地址。
下载地址:https://download.csdn.net/download/zhengzhaoyang122/10678711
3)、创建main方法如下:
public class fastDemo {
public static void main(String[] args) throws Exception{
//获取配置文件,配置文件中的内容就是track服务器的地址
ClientGlobal.init("E:/learnWorkspacesHight/fastDfs-Demo/src/main/resources/fdfs_client.conf");
//创建一个trackClient对象
TrackerClient trackerClient = new TrackerClient();
//使用客户端创建连接,获取服务端
TrackerServer trackerServer = trackerClient.getConnection();
//创建一个storage的引用
StorageServer storageServer = null;
//创建一个storageClien需要两个参数,StorageServer和trackServer
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
//使用storageClient上传对象
String[] strings = storageClient.upload_file("E:/image/回家的路.jpg", "jpg", null);
for(String s:strings) {
System.out.println(s);
}
}
}
☺ 控制台输出结果:
group1
M00/00/00/wKgZhVkMP4KAZEy-AAA-tCf93Fo973.jpg
在浏览器汇中输入url就可以访问图片:http://192.168.25.133/group1/M00/00/00/wKgZhVkMP4KAZEy-AAA-tCf93Fo973.jpg
七、基于demo扩展到实战
1)、springmvc.xml中配置多媒体解析器,解析图片信息。
<!-- 配置多媒体解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
2)、写一个FastDFS客户端公共方法(工具类:可直接复制使用)
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:")) {
conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
}
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) throws Exception {
String result = storageClient.upload_file1(fileName, extName, metas);
return result;
}
public String uploadFile(String fileName) throws Exception {
return uploadFile(fileName, null, null);
}
public String uploadFile(String fileName, String extName) throws Exception {
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) throws Exception {
String result = storageClient.upload_file1(fileContent, extName, metas);
return result;
}
public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
}
public String uploadFile(byte[] fileContent, String extName) throws Exception {
return uploadFile(fileContent, extName, null);
}
}
3)、Controller类处理逻辑展示,具体注释说明:
@RestController
public class uploadController {
//当配置文件已经有springmvc.xml引入后,可以通过如下方式获取到
//配置文件中配置如下:FILE_SERVER_URL=http://192.168.25.133/
@Value("${FILE_SERVER_URL}")
private String FILE_SERVER_URL;
@RequestMapping("/upload")
public Result upload(MultipartFile file) {
//1、获取文件名称(全名)
String filename = file.getOriginalFilename();
//截取文件的后缀名(不包含.)
String exName=filename.substring(filename.lastIndexOf(".")+1);
try {
//2、获取FastDFS客户端
FastDFSClient fastDFSClient = new FastDFSClient("classpath:config/fdfs_client.conf");
//3、执行上传
String path = fastDFSClient.uploadFile(filename, exName);
//4、将返回的图片地址与服务器http:ip地址组装
String url = FILE_SERVER_URL+path;
//5、返回url
return new Result(true, url);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "上传失败");
}
}
}
4)、前端Server.js请求的规范书写
app.service("uploadService",function($http){
this.uploadFile=function(){
/*
* FormData对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。
* 其主要用于发送表单数据,但亦可用于发送带键数据(keyed data),而独立于表单使用。
*/
var formDate = new FormDate();
/*
* 我们再看这行代码的背景,HTML5支持multiple属性,
* 即<input type="file">可能会添加multiple属性并赋值:multiple="multiple",
* 即<input type="file" multiple="multiple">,这样一次性可同时上传多张图片,
* 所以获得一张图片的方法就是:$('xx')[0].files[0]
*/
formDate.append("file",file.files[0]);
return $http({
method:"POST",
url:"../upload.do",
data:"formDate",
/*
* anjularjs对于post和get请求默认的Content-Type header 是application/json。
* 通过设置‘Content-Type’: undefined,这样浏览器会帮我们把Content-Type
* 设置为 multipart/form-data。
*/
headers:{'Content-Type':undefined},
/*
* 通过设置 transformRequest: angular.identity ,
* anjularjs transformRequest function 将序列化我们的formdata object.
*/
transformRequest: angular.identity
});
}
});
5)、可以将返回的url赋值给src=""中,便可以通过浏览器渲染获得图片信息。