本文引用至:https://sh.qihoo.com/pc/detail?url=https%3A%2F%2Fwww.toutiao.com%2Fi6642852421280203277%2F&check=edce824a247c0dfa&sign=baike&uid=15484592.2690209269186620000.1543843680589.368
一、 什么是fastDfs
fastDfs是一个轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
二、 为什么要使用fastDfs
在单体应用时代可以使用 apache的common-fileupload或者struts进行文件的上传下载,但是对于海量的数据,文件资源和程序都放在一起会影响性能,特别是针对现在的微服务框架,更需要使用分布式的文件系统去上传,下载图片或者文件,对于海量的文件存储,fastDfs是个不错的选择。
fastDfs有两个重要的部件:
① 跟踪器(tracker)
简单来说就是控制文件上传的路由,负责分配文件的地址,保持周期性心跳。
② 存储节点(storage)
相当于一个存贮的容器,以 group 为单位,每个 group 内可以有多台 storage server。
引用官方的一个原理图
三、 如何安装
安装的教程网上是有很多的,这里不再过多的阐述。
这里针对linux版本的单节点的安装推荐两篇网上的安装教程:
https://blog.csdn.net/zxl315/article/details/53535751
http://www.cnblogs.com/adolfmc/p/4239575.html
主要有这4个配置文件
如果需要配置修改fastDfs的密码的话,可以修改下图的这个地方
四、 如何使用
1. 引入依赖
在javaweb程序中使用的时候,如果项目没有使用maven,需要下载jar包 fastdfs_client_v1.19.jar,然后引入。
如果是maven项目的话,需要在pom.xml文件中引入fastdfs_client 依赖。
org.csource
fastdfs-client-java
5.0.4
2. 配置参数
在src/main/resource 下创建 fdfs_client.conf 配置文件
#fdfs_client.conf 配置
connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8888
http.anti_steal_token = no
http.secret_key = FastDFS1234567890
tracker_server = 192.168.220.88:22122
#如果有多台服务,指定集群的IP
#tracker_server = 192.168.220.89:22122
#tracker_server = 192.168.220.90:22122
3. 工具类
1) 初始化
初始化fastDfs的跟踪器和存储器,上传和下载的时候就可以调用这个初始化了。
/**
* @Description:初始化fastDfs
* @author: jhy
* @date: 2017年10月31日 上午9:52:16
*/
public static Map init() {
Map map = new HashMap();
try {
String classPath = new File(FastDfsUtil.class.getResource("/").getFile()).getCanonicalPath();
classPath = URLDecoder.decode(classPath,"utf-8");
String configFilePath = classPath + File.separator + "fdfs_client.conf";
logger.info("配置文件:" + configFilePath);
// 初始化参数
ClientGlobal.init(configFilePath);
// 初始化跟踪器
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getConnection();
// 初始化存储器
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
map.put("trackerClient", trackerClient);
map.put("trackerServer", trackerServer);
map.put("storageClient", storageClient);
map.put("storageServer", storageServer);
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
2) 上传文件
通过传入file和文件名,上传成功返回上传成功的路径
/**
* @Description:上传文件
* @author: jhy
* @date: 2017年10月25日 上午9:28:52
* @param:file:上传文件流
*/
public static Map upload(File file, String fileName) {
Map map = new HashMap();
try {
// 初始化fastDfs
Map initMap = FastDfsUtil.init();
TrackerClient trackerClient = (TrackerClient) initMap.get("trackerClient");
TrackerServer trackerServer = (TrackerServer) initMap.get("trackerServer");
StorageClient storageClient = (StorageClient) initMap.get("storageClient");
// 初始化参数
NameValuePair[] meta_list = new NameValuePair[3];
meta_list[0] = new NameValuePair("width", "120");
meta_list[1] = new NameValuePair("heigth", "120");
meta_list[2] = new NameValuePair("author", "jhy");
//获取文件后缀名
String prefix = fileName.substring(fileName.lastIndexOf(".") + 1);
FileInputStream fis = new FileInputStream(file);
byte[] file_buff = null;
if(fis != null){
int len = fis.available();
file_buff = new byte[len];
fis.read(file_buff);
}
logger.info("文件长度: " + file_buff.length);
// 声明组
String group_name = null;
// 根据跟踪器和组查找存储器
StorageServer[] storageServers = trackerClient.getStoreStorages(trackerServer, group_name);
if (storageServers == null) {
logger.info("无法找到存储器服务:" + storageClient.getErrorCode());
map.put("resCode", storageClient.getErrorCode());
map.put("resMsg", "无法找到存储器服务");
return map;
}else{
logger.info("存储器数量: " + storageServers.length);
for (int k = 0; k
logger.info("当前文件:"+ k + 1 + ". " + "当前ip和端口" + storageServers[k].getInetSocketAddress().getAddress().getHostAddress() + ":" + storageServers[k].getInetSocketAddress().getPort());
}
}
// 开始时间
long startTime = System.currentTimeMillis();
// 文件上传返回结果
String[] results = storageClient.upload_file(file_buff, prefix, meta_list);
logger.info("上传耗费时间: " + (System.currentTimeMillis() - startTime) + " ms");
if (results == null){
logger.info("上传失败:" + storageClient.getErrorCode());
map.put("resCode", storageClient.getErrorCode());
map.put("resMsg", "上传失败");
return map;
}
//返回结果赋值给组
group_name = results[0];
String remote_filename = results[1];
logger.info("组名: " + group_name + ", 文件路径: " + remote_filename);
logger.info(storageClient.get_file_info(group_name, remote_filename).toString());
//根据跟踪器,组和文件路径查找跟踪服务器
ServerInfo[] servers = trackerClient.getFetchStorages(trackerServer, group_name, remote_filename);
if (servers == null){
logger.info("无法找到跟踪器服务:" + storageClient.getErrorCode());
map.put("resCode", trackerClient.getErrorCode());
map.put("resMsg", "无法找到跟踪器服务");
return map;
} else {
logger.info("跟踪服务器数量: " + servers.length);
for (int k = 0; k
logger.info("当前文件:"+ k + 1 + ". " + "当前ip和端口" + servers[k].getIpAddr() + ":" + servers[k].getPort());
}
}
map.put("resCode", "0000");//代表上传成功
map.put("resMsg", remote_filename);
logger.info("上传成功");
trackerServer.close();
return map;
} catch (Exception e) {
e.printStackTrace();
map.put("resCode", "9999");
map.put("resMsg", "文件服务器连接异常");
}
return map;
}
3) 获取文件信息
通过传入组名和服务器保存的文件名称获取远程文件信息
/**
* @Description:获取文件信息
* @author: jhy
* @date: 2017年10月31日 上午9:56:33
* @param:group_name:组名
* @param:remote_filename 文件名称
*/
public static Map getFileInfo(String group_name, String remote_filename) {
Map map = new HashMap();
try {
// 初始化fastDfs
Map initMap = FastDfsUtil.init();
StorageClient storageClient = (StorageClient) initMap.get("storageClient");
FileInfo fi = storageClient.get_file_info(group_name, remote_filename);
String sourceIpAddr = fi.getSourceIpAddr();
long size = fi.getFileSize();
logger.info("ip地址:" + sourceIpAddr + ",文件大小:" + size);
map.put("resCode", "0000");//代表下载成功
map.put("resMsg", fi);
logger.info("获取文件信息成功");
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
4) 下载文件
通过组名和文件名下载服务器的文件。
/**
* @Description:下载文件
* @author: jhy
* @date: 2017年10月31日 上午9:56:33
* @param:group_name:组名
* @param:remote_filename 文件名称
*/
public static Map download(String group_name, String remote_filename) {
Map map = new HashMap();
try {
// 初始化fastDfs
Map initMap = FastDfsUtil.init();
StorageClient storageClient = (StorageClient) initMap.get("storageClient");
byte[] b = storageClient.download_file(group_name, remote_filename);
logger.info("下载字节b:" + b);
if (b != null) {
map.put("resCode", "0000");//代表下载成功
map.put("resMsg", b);
logger.info("下载成功");
}else {
map.put("resCode", "9999");//代表下载失败
map.put("resMsg", b);
logger.info("下载失败");
}
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
5) 测试
/**
* @Description:测试
* @author: jhy
* @date: 2017年10月25日 上午11:04:39
*/
public static void main(String[] args) {
// 上传
// File file = new File("E:\\pic.png");
// FastDfsUtil.upload(file,"E:\\pic.png");
// 下载
FastDfsUtil.download("group1", "M00/00/01/pqYBZVofaPeANx_UAACnTf3PBis648.png");
}