FastDFS(分布式文件系统)

Tracker:标准服务端口22122、HTTP端口8080
Storage:标准服务端口23000、HTTP端口8888

文章目录

    • 一、架构
    • 二、文件上传、下载、删除
        • 1 时序图
        • 2 流程说明
          • 3 代码实现

一、架构

架构图:
在这里插入图片描述

Client:客户端。使用java语言编写的项目属于客户端。
Tracker Server:跟踪服务器,主要做调度工作,在访问上起负载均衡的作用。在内存中记录集群中group和storage server的状态信息,是连接Client和Storage server的枢纽。
Storage Server:存储服务器,文件和文件属性(meta data)都保存到存储服务器上

架构解读:

只有两个角色,tracker server和storage server,不需要存储文件索引信息。
所有服务器都是对等的,不存在Master-Slave关系。
存储服务器采用分组方式,同组内存储服务器上的文件完全相同(RAID 1)。
不同组的storage server之间不会相互通信。
由storage server主动向tracker server报告状态信息,tracker server之间不会相互通信。

二、文件上传、下载、删除

1 时序图

1.1 文件上传时序图

在这里插入图片描述

1.2 文件下载时序图
在这里插入图片描述

1.3 文件删除时序图
在这里插入图片描述

2 流程说明

2.1 上传流程说明

  1. 客户端访问Tracker
  2. Tracker 返回Storage的ip和端口
  3. 客户端直接访问Storage,把文件内容和元数据发送过去。
  4. Storage返回文件存储id。包含了组名和文件名
    在这里插入图片描述

2.2 下载流程说明

  1. client询问tracker下载文件的storage,参数为文件标识(组名和文件名);
  2. tracker返回一台可用的storage;
  3. client直接和storage通讯完成文件下载。
3 代码实现

3.1 添加依赖

<dependencies><!-- fdfs java客户端依赖 --><dependency><groupId>cn.bestwu</groupId><artifactId>fastdfs-client-java</artifactId><version>1.27</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version></dependency></dependencies>

3.2 编写配置文件
文件名:fdfs_client.conf
修改成自己的tracker服务器ip

connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8080tracker_server = 192.168.14.129:22122

3.3 导入工具类
在com.wyy.utils.fdfs.FdfsFileSystemUtils下粘贴配置工具类

package com.wyy.utils.fdfs;import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;import java.util.Arrays;/*** 工具类型。提供连接创建,上传、下载、删除等操作。*/
public class FdfsFileSystemUtils {// 通过static初始化代码块,读取配置文件,初始化客户端连接对象。// 客户端连接对象,用于实现文件读写操作使用。private static StorageClient storageClient;static {try {// 读取配置文件// 获取文件名称String path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + "fdfs_config.conf";// 加载配置文件ClientGlobal.init(path);// 创建Tracker客户端对象TrackerClient trackerClient = new TrackerClient();// 创建Tracker服务器对象TrackerServer trackerServer = trackerClient.getConnection();// 创建Storage服务器对象StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);// 创建Storage客户端对象storageClient = new StorageClient(trackerServer, storageServer);}catch(Exception e){e.printStackTrace();// 初始化代码块出错,一定要抛出错误,停止虚拟机。throw new ExceptionInInitializerError(e);}}/*** 文件删除,FastDFS会自动删除这个文件对应的metaData。就是文件名-m这个文件。*/public static boolean deleteFile(String groupName, String fileName){try{// storageClient.delete_file(String groupName, String fileName);// groupName - 要删除的文件的卷名,就是保存文件的storage服务配置中的groupName// fileName - 要删除的文件的文件名,包含路径地址。格式:M00/目录/目录/文件名.后缀名// M00代表保存文件的目录, store_path0 。 目录/目录 - 保存文件的具体位置。int result = storageClient.delete_file(groupName, fileName);// 返回结果为0,代表删除成功,其他是删除失败。return result == 0;}catch(Exception e){e.printStackTrace();return false;}}/*** 文件下载* @param metaDatas - 传入一个数组,用于保存下载文件的扩展信息。如果传入null,则不需要文件扩展信息。*                      如果传入的数组不是null,则需要文件的扩展信息。* @return 下载的文件内容*/public static byte[] downloadFile(String groupName, String fileName, NameValuePair[] metaDatas){try{/** byte[] storageClient.download_file(String groupName, String fileName);* groupName - 卷名 | 组名* fileName - 文件名,是文件保存在fdfs中的目录和文件名。*/byte[] datas = storageClient.download_file(groupName, fileName);// 要下载的文件的扩展信息。if(metaDatas != null) {NameValuePair[] tmp = storageClient.get_metadata(groupName, fileName);// 把查询到的文件扩展信息。保存到传入的数组中。for(int i = 0; i < tmp.length; i++){metaDatas[i] = tmp[i];}}// 返回下载的文件内容return datas;}catch(Exception e){e.printStackTrace();return null; // 下载失败,返回null}}/*** 使用StorageClient对象,实现文件的上传。*/public static String[] uploadFile(byte[] datas, String fileName, String authName){try{// 文件上传// 获取文件的扩展名String extName = fileName.substring(fileName.lastIndexOf(".") + 1);// 创建文件扩展信息。扩展信息包括文件的原始名称,文件的大小,文件的上传者姓名NameValuePair[] metaDatas = new NameValuePair[3];metaDatas[0] = new NameValuePair("fileName", fileName);metaDatas[1] = new NameValuePair("fileSize", datas.length+"");metaDatas[2] = new NameValuePair("auth", authName);/** String[] storageClient.upload_file(byte[] datas, String extName, NameValuePair[] metaDatas)* datas - 要上传的文件的内容* extName - 上传的文件的扩展名* metaDatas - 上传的文件的扩展信息是什么。 如:文件的原始名称、文件的容量大小、文件的上传者等。*/String[] result = storageClient.upload_file(datas, extName, metaDatas);// 上传成功,无异常。返回字符串数组。// 字符串数组长度为2。 0下标位置是 卷名|组名。 1下标位置是 文件名(目录/文件)// fdfs为了解决上传的文件原始名称冲突内容不冲突而覆盖的问题,存储文件的时候,会提供一个uuid文件名称。return result;}catch(Exception e){e.printStackTrace();return null; // 异常发生,返回null。代表上传失败。}}
}

3.4 编写测试代码
随意新建一个包含主方法的类 com.wyy.test

package com.wyy.test;import com.wyy.utils.fdfs.FdfsFileSystemUtils;
import org.csource.common.NameValuePair;import java.io.FileOutputStream;
import java.io.InputStream;public class TestFdfs {public static void main(String[] args) throws Exception {upload();}public static void delete() throws  Exception {String groupName = "group1";String fileName = "M00/00/00/wKhZjF514maAar2-AAA_UVqBgzQ256.png";boolean flag = FdfsFileSystemUtils.deleteFile(groupName,fileName);System.out.println(flag ? "删除文件成功" : "删除文件失败");}// 文件下载。下载的文件保存在D盘根目录下。 文件名称是文件的原始名称public static void download() throws Exception {// 用于保存文件扩展信息的数组NameValuePair[] metaDatas = new NameValuePair[3];String groupName = "group1";String fileName = "M00/00/00/wKhZjF514maAar2-AAA_UVqBgzQ256.png";// 下载文件byte[] datas = FdfsFileSystemUtils.downloadFile(groupName, fileName, metaDatas);String localName = "";for(NameValuePair nvp : metaDatas){System.out.println(nvp.getName() + " - " + nvp.getValue());if(nvp.getName().equals("fileName")){localName = nvp.getValue();}}// 把下载的文件内容保存到文件中。FileOutputStream outputStream = new FileOutputStream("D:\\" + localName);outputStream.write(datas);outputStream.flush();outputStream.close();}// 文件上传public static void upload() throws  Exception {// 读取文件内容String fileName = "1.png";InputStream inputStream = TestFdfs.class.getClassLoader().getResourceAsStream(fileName);// 创建字节数组byte[] datas = new byte[inputStream.available()];// 读取文件内容到字节数组中。inputStream.read(datas, 0, datas.length);// 上传文件String[] result = FdfsFileSystemUtils.uploadFile(datas, fileName, "老金");System.out.println("卷名:" + result[0]);System.out.println("文件名:" + result[1]);System.out.println("返回数组的长度:" + result.length);inputStream.close();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务中的异步消息通讯

前言 在上一篇文章中&#xff0c;我们说到了异步消息通讯&#xff0c;下面这篇文章呢&#xff0c;大部分内容是翻译来自于这篇微软的文章&#xff0c;所以其内容还是具有一定的理论指导意义的。 当我们跨多个微服务进行内部通讯的时候&#xff0c;异步消息和事件驱动至关重要…

CSS3的几个变形案例……

大家好&#xff0c;欢迎来到雄雄的小课堂&#xff0c;那个……辣椒酱很好吃的&#xff0c;哈哈哈哈&#xff01;今天给大家分享的内容是利用CSS制作网页的动画。辣椒酱&#xff1a;自从有了这款辣椒酱&#xff0c;拌饭再也不用老干妈CSS变形CSS的变形包括这么几种效果&#xff…

我眼中的ASP.NET Core之微服务

前言 前几天在博客园看到有园友在分享关于微软的一个微服务架构的示例程序&#xff0c;想必大家都已经知道了&#xff0c;那就是eShopOnContainers。 我们先不看项目的后缀名称 OnXXX &#xff0c;因为除了 OnContainers 还有 OnAzure&#xff0c;OnWeb&#xff0c;OnKuberne…

形象的解释神经网络激活函数的作用是什么

转载自 形象的解释神经网络激活函数的作用是什么 神经网络中激活函数的作用 查阅资料和学习&#xff0c;大家对神经网络中激活函数的作用主要集中下面这个观点&#xff1a; 激活函数是用来加入非线性因素的&#xff0c;解决性模型所不能解决的问题。 下面我分别从这个方面…

CSS3中的动画示例

大家好&#xff0c;欢迎来到雄雄的小课堂&#xff0c;上一期我们分享了几个CSS变形案例&#xff0c;大家还记得有哪几个吗&#xff1f;原文在这里&#xff1a;CSS3的几个变形案例……今天&#xff0c;我们来看看CSS的过渡&#xff1a;过渡简单的来讲&#xff0c;就是元素由一种…

ASP.NET Core之跨平台的实时性能监控(2.健康检查)

前言 上篇我们讲了《如何使用App Metrics 做一个简单的APM监控》,最后提到过健康检查这个东西. 这篇主要就是讲解健康检查的内容. 没看过上篇的,请移步:ASP.NET Core之跨平台的实时性能监控 首先我们来了解一下什么是健康检查(health checks)? 1.什么是健康检查? 健康检查…

​通俗理解神经网络BP反向传播算法

转载自 ​通俗理解神经网络BP反向传播算法 通俗理解神经网络BP反向传播算法 在学习深度学习相关知识&#xff0c;无疑都是从神经网络开始入手&#xff0c;在神经网络对参数的学习算法bp算法&#xff0c;接触了很多次&#xff0c;每一次查找资料学习&#xff0c;都有着似懂非…

CSS动画示例(上一篇是CSS过渡…)

大家好&#xff0c;欢迎来到雄雄的小课堂&#xff0c;前面&#xff0c;我们将CSS的变形和过渡都整理了&#xff0c;有需要的可以移步这里看&#xff1a;CSS3中的动画示例CSS3的几个变形案例……今天&#xff0c;我们来看看CSS3的动画。CSS3使用动画分为两个步骤&#xff1a;1.通…

Health Check in eShop -- 解析微软微服务架构Demo(五)

引言 What is the Health Check Health Check&#xff08;健康状态检查&#xff09;不仅是对自己应用程序内部检测各个项目之间的健康状态&#xff08;各项目的运行情况、项目之间的连接情况等&#xff09;&#xff0c;还包括了应用程序对外部或者第三方依赖库的状态检测。 W…

为什么梯度反方向是函数下降最快的方向

转载自 为什么梯度反方向是函数下降最快的方向 为什么梯度反方向是函数下降最快的方向&#xff1f; 刚接触梯度下降这个概念的时候&#xff0c;是在学习机器学习算法的时候&#xff0c;很多训练算法用的就是梯度下降&#xff0c;然后资料和老师们也说朝着梯度的反方向变动&a…

javaweb中实现分页,持续更新……

大家好&#xff0c;欢迎来到雄雄的小课堂&#xff0c;昨天分享了个分页工具类一个简单的分页工具类&#xff0c;其实&#xff0c;也是为今天的分享做的铺垫&#xff0c;今天&#xff0c;给大家带来的是javaweb实现分页的全过程&#xff01;前言&#xff1a;为什么需要分页&…

Redis(入门)

文章目录一、 Redis简介二、 基于Docker安装Redis单机版三、 Redis常用命令1 Key操作2 字符串值(String)&#xff08;值的长度不超过512MB&#xff09;3 哈希表(Hash)4 列表&#xff08;List&#xff09;5 集合(Set)6 有序集合&#xff08;Sorted Set&#xff09;四、 Redis持久…

浅析神经网络为什么能够无限逼近任意连续函数

转载自 浅析神经网络为什么能够无限逼近任意连续函数 神经网络为什么能够无限逼近任意连续函数&#xff1f; 下面通过一个分类例子一步一步的引出为什么神经网络能够无限逼近任意函数这个观点&#xff0c;并且给出直观感觉! 我们首先有这个需求&#xff0c;需要将下面的数据…

前端模块化工具--webpack学习心得

话说前头 webpack前段时间有听说一下&#xff0c;现在已经到了3.x的版本&#xff0c;自己没去接触。因为之前使用gulp来作为自己的项目构建工具。现在感觉gulp使用的趋势在减少。现在这段时间去接触了webpack&#xff0c;感觉很不错&#xff0c;它的模块化打包机制&#xff0c…

基于.NET CORE微服务框架 -谈谈surging的服务容错降级

一、前言 对于不久开源的surging受到不少.net同学的青睐&#xff0c;也受到.net core学习小组的关注&#xff0c;邀请加入.NET China Foundation 以方便国内.net core开源项目的推广&#xff0c;我果断接受邀请加入了队伍进行互相交流学习&#xff0c;最近也更新了surging新的…

java中部的分页实现(二)

大家好&#xff0c;欢迎来到雄雄的小课堂&#xff0c;昨天分享了关于分页查询的理论知识&#xff0c;今天我们就来结合代码和案例实际的应用一下&#xff0c;方便大家理解。前言&#xff1a;我们都知道&#xff0c;实现分页需要三个步骤。第一&#xff0c;确定页大小&#xff0…

SpringSecurity授权(访问控制)

一、 访问控制url匹配 在前面讲解了认证中所有常用配置&#xff0c;主要是对httpSecurity.formLogin()进行操作。而在配置类中httphttpSecurity.authorizeRequests()主要是对url进行控制&#xff0c;也就是我们所说的授权&#xff08;访问控制&#xff09;。httpSecurity.autho…

剥析surging的架构思想

1、前言 前面第一篇阐述了采用基于.NET CORE微服务架构&#xff0c;应用surging服务端与客户端之间进行通信的简单示例以及对于surging服务化框架简单介绍。在这篇文章中&#xff0c;我们将剥析surging的架构思想。 surging源码下载 2、通信机制 2.1 简介 在单体应用中&am…

javaweb实现分页(二)

前言&#xff1a;我们都知道&#xff0c;实现分页需要三个步骤。第一&#xff0c;确定页大小&#xff08;每页显示的数据量&#xff09;。第二&#xff0c;计算显示的总页数。第三&#xff0c;写分页的sql语句。这三步已经在昨天的推文中详细说明&#xff0c;需要的可以点击这里…

滴滴出行基于RocketMQ构建企业级消息队列服务的实践

转载自 滴滴出行基于RocketMQ构建企业级消息队列服务的实践 本文整理自滴滴出行消息队列负责人 江海挺 在Apache RocketMQ开发者沙龙北京站的分享。通过本文&#xff0c;您将了解到滴滴出行&#xff1a; 1. 在消息队列技术选型方面的思考&#xff1b; 2. 为什么选择 RocketMQ…