什么是FastDFS?
FastDFS是用c语言编写的一款开源的分布式文件系统。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
为什么要使用FastDFS?
我们把静态资源文件存储在本地服务器也能正常访问啊,如放在Tomcat项目文件夹下,也能实现正常的访问。但是当我们的系统超过1000并发后,需要使用nginx进行服务器的负载均衡(即使用多个服务器),用户访问就访问的nginx,nginx将求情转发给用于服务器Tomcat,但是有一种情况,张上用户上传图片,nginx分配给服务器A,然后服务器tomcat将图片存在其工程文件夹下,而李四访问这张图片的时候,nginx可能将请求转发给服务器B,但是由于图片存放在服务器A中,故将发生404错误。
上述问题出现在我们没有把图片放在同一的一个位置。
那么当我们专门使用一台服务器作为图片服务器呢?所有的图片访问都找这个专门的服务器picture。
但是我们也可以使用tomcat作为静态资源服务器啊?为什么使用FastDFS服务器呢?
原因:这台服务器的存储有上限,其扩容性不强。
当这个服务器满容量后,若再加一个服务器其访问的URL将会相应的发生变化,而且如果这个服务器挂了,则相应的数据丢失。
使用FastDFS的优点:
使用FastDFS可以实现横向扩容,如果你的存储空间不够了,可以加服务器,它会对group进行集中管理。其运行在Linux下。
其架构图如下:
服务端两个角色:
Tracker:
- 管理集群, tracker也可以实现集群。每个tracker节点地位平等。
- 作用:引导客户端去哪台服务器存储数据,实际上是客户端与存储服务器直接进行通信的,并不需要通过Tracker进行中转。
Storage:
- 需要连接tracker端,定期报告自己的情况(是否活着,剩余容量,负载情况)
- 分为多个组,每个组之间保存的文件是不同的。每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。
卷1、卷2、卷n是可以实现横向扩容的,向里面添加组服务器,且同一个组里面的文件是一样的,一台服务器挂了,还有别的服务器可以提供访问。(实现高可用)
一台服务器很忙,可以将访问分配给其他服务器,实现负载均衡。
文件上传其时序图:
客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。
group1/M00/02/44/shaudhuasduasd.jpg
- 组名:文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。
- 虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。
- 数据两级目录:storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
- 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。(已经加密了)
文件上传实现步骤
好了,上面的都是概念介绍,下面实现其文件的上传;
- 1向工程中加入jar包
fastdfs_client-1.25.jar(此处是maven工程,直接导入fastdfs_client工程后maven insatll导入本地仓库 ) - 2创建一个配置文件 配置文件内容tarcker_server=192.168.25.133:22122
配置文件内容是FastDFS的IP地址 - 3加载配置文件
ClientGlobal.init(path) - 4创建一个TrackerClient对象
TrackerClient trackerClient = new TrackerClient(); - 5使用TrackerClient对象获得trackerserver对象
TrackerServer trackerServer = trackerClient.getConnection(); - 6创建一个storageServer为null
StorageServer storageServer=null; - 7创建一个storageClient对象,参数为trackerserver、storageServer
StorageClient storageClient=new StorageClient(trackerServer, storageServer); - 8使用storageClient对象上传文件
String[] upload_file=storageClient.upload_file(“D:/111/1.jpg”, “jpg”, null)
参数三是原数据,文件的相关信息(修改日期、创建者等等)。
@Test
public void test() throws Exception{
//1.向工程中加入jar包
//2创建一个配置文件 配置文件内容tarcker_server=192.168.25.133:22122
//3加载配置文件
ClientGlobal.init("E:/javaWeb-kaoshi/workspaces_taotao/taotao-manager-web/src/main/resources/client.conf");
//4创建一个TrackerClient对象
TrackerClient trackerClient = new TrackerClient();
//5使用TrackerClient对象获得trackerserver对象
TrackerServer trackerServer = trackerClient.getConnection();
//6创建一个storageServer为null
StorageServer storageServer=null;
//7创建一个storageClient对象,参数为trackerserver、storageServer
StorageClient storageClient=new StorageClient(trackerServer, storageServer);
//8使用storageClient对象上传文件
String[] upload_file = storageClient.upload_file("D:/111/1.jpg", "jpg", null);
for (String string : upload_file) {
System.out.println(string);
}
}
输出:
group1
M00/00/00/wKgZhV0Hg-yAQPmPAACtd9REEP8664.jpg
当我们需要访问时,其访问URl为:192.168.25.133/ group1/M00/00/00/wKgZhV0Hg-yAQPmPAACtd9REEP8664.jpg
工具类使用
1.图片上传工具类
在我们上传图片的时候,由于上述步骤很多步骤都是重复的,我们可以将其封装后变的简单一点。
package com.taotao.utils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
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);
}
}
测试类:
@Test
public void testUtils() throws Exception{
FastDFSClient fastDFSClient = new FastDFSClient("E:/javaWeb-kaoshi/workspaces_taotao/taotao-manager-web/src/main/resources/client.conf");
String uploadFile = fastDFSClient.uploadFile("D:/111/2.jpg", "jpg", null);
System.out.println(uploadFile);
}