编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

高级进阶-分布式文件系统之FastDfs

wxchong 2024-08-09 11:36:32 开源技术 15 ℃ 0 评论

一、 什么是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 依赖。

<dependency>
 <groupId>org.csource</groupId>
 <artifactId>fastdfs-client-java</artifactId>
 <version>5.0.4</version>
</dependency>

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<String, Object> init() {
 Map<String, Object> map = new HashMap<String, Object>();
 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<String, Object> upload(File file, String fileName) {
 Map<String, Object> map = new HashMap<String, Object>();
 try {
 // 初始化fastDfs
 Map<String, Object> 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 < storageServers.length; 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 < servers.length; 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<String, Object> getFileInfo(String group_name, String remote_filename) {
 Map<String, Object> map = new HashMap<String, Object>();
 try {
 // 初始化fastDfs
 Map<String, Object> 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<String, Object> download(String group_name, String remote_filename) { 
 Map<String, Object> map = new HashMap<String, Object>();
 try {
 // 初始化fastDfs
 Map<String, Object> 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");
	 }

-------------END-------------

如果感觉对自己有帮助的,可以支持一下哈。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表