FastDFS(分布式文件管理系统)

news2024/11/28 2:44:57

一、简介

 

解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。

FastDFS服务端只有两个角色,tracker serverstorage server。

所有同角色服务器集群节点都是平等的,不存在主从关系(Master-Slave)。

存储服务器采用分组方式,同组内存储服务器上的文件完全相同(备份);不同分组的存储服务器管理不同的文件(扩容 RAID)。

不同组的storage server之间不会相互通信。

由storage server主动向tracker server报告状态信息,tracker server之间不会相互通信。

二、搭建环境

(1)拉取镜像

docker pull delron/fastdfs

(2)创建tracker service宿主机目录

mkdir -p /opt/fdfs/tracker

(3)创建tracker service容器,默认端口号22122

docker run -d --network=host --name tracker -v /opt/fdfs/tracker:/var/fdfs delron/fastdfs tracker

(4)创建storage service宿主机目录

mkdir -p /opt/fdfs/storage

(5)创建storage service并启动容器,默认端口号23000

docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.146.130:22122 -v /opt/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage

(6)重启问题解决

rm -rf /opt/fdfs/tracker/data/*.pid

rm -rf /opt/fdfs/storage/data/*.pid

三、文件上传

(1)导入依赖

        <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.4</version>
        </dependency>

(2)在src/main/resources目录中创建properties类型配置文件,命名不限。如:fdfs.properties

fastdfs.connect_timeout_in_seconds=10
fastdfs.network_timeout_in_seconds=30
fastdfs.charset=UTF-8
# tracker服务器地址,多个服务器,逗号分隔
fastdfs.tracker_servers=192.168.130.146:22122
# tracker服务器中配置文件tracker.conf中的http端口配置。必须相同。
fastdfs.http_tracker_http_port=8080

(3)创建工具类com.bjsxt.utils.FastDFSUtils

/**
 * FastDFS Java客户端工具
 */
public final class FastDFSUtils {
    /**
     * 定义静态属性,Properties和StorageClient
     */
    private final static Properties PROPERTIES;
    private final static StorageClient STORAGE_CLIENT;

    /**
     * 静态初始化代码块,初始化静态属性
     * 静态初始化代码块有异常如何处理?
     * 处理的时候,try。。catch。。 抛出一个Error,终止虚拟机。
     */
    static{
        try {
            PROPERTIES = new Properties();
            // 读取配置文件
            PROPERTIES.load(
                    FastDFSUtils.class
                            .getClassLoader()
                            .getResourceAsStream("fdfs.properties")
            );
            // 使用ClientGlobal初始化FastDFS客户端配置
            ClientGlobal.initByProperties(PROPERTIES);
            // 创建Tracker客户端对象
            TrackerClient trackerClient = new TrackerClient();
            // 基于Tracker客户端对象,获取Tracker服务器对象
            TrackerServer trackerServer = trackerClient.getConnection();
            // 基于Tracker服务器和客户端对象,获取Storage服务器对象
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            // 创建Storage客户端对象
            STORAGE_CLIENT = new StorageClient(trackerServer, storageServer);
        }catch (Exception e){
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * 删除文件
     * int delete_file(String 卷名, String 路径及文件名);
     * 返回值: 0代表成功,其他数字代表错误编码
     */
    public static int remote(String group, String remote){
        try {
            return STORAGE_CLIENT.delete_file(group, remote);
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * 查询某文件的元数据
     * @param group 卷名
     * @param remote 路径及文件名
     * @return 返回文件的元数据数组。发生错误返回null
     */
    public static NameValuePair[] getMetaData(String group, String remote){
        try{
            return STORAGE_CLIENT.get_metadata(group, remote);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 下载文件工具方法
     *  下载方法
     *  byte[] download_file(String 卷名, String 路径及文件名)
     *  返回要下载的文件内容
     * @param group 卷名
     * @param remote 路径及文件名
     * @return 返回下载的文件内容,发生错误返回null
     */
    public static byte[] download(String group, String remote){
        try {
            return STORAGE_CLIENT.download_file(group, remote);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 上传文件的工具方法
     * 一定保存文件到FastDFS,一定保存至少一个元数据(文件原始名称)
     * @param inputStream 要上传的文件的输入流
     * @param fileName 上传文件的原始名称
     * @param metaProperties 上传文件的元数据,成对提供,如: 名,值,名,值
     * @return
     */
    public static String[] uploadFile(InputStream inputStream, String fileName, String... metaProperties){
        try {
            int length = inputStream.available();
            byte[] datas = new byte[length];
            inputStream.read(datas, 0, length);
            // 处理元数据
            NameValuePair[] nameValuePairs = null;
            if (metaProperties.length % 2 == 0) {
                // 参数数量满足要求,开始处理
                nameValuePairs = new NameValuePair[metaProperties.length / 2 + 1];
                for (int i = 0; i < nameValuePairs.length; i = i + 2) {
                    nameValuePairs[i / 2] = new NameValuePair(metaProperties[i], metaProperties[i + 1]);
                }
            } else {
                nameValuePairs = new NameValuePair[1];
            }
            nameValuePairs[nameValuePairs.length - 1] = new NameValuePair("fileName", fileName);
            // 获取文件后缀
            String extName = getExtName(fileName);
            // 上传文件到FastDFS
            String[] result = STORAGE_CLIENT.upload_file(datas, extName, nameValuePairs);
            return result;
        }catch (Exception e){
            // 发生任何异常,上传文件失败。返回null
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 截取文件后缀
     * @param fileName
     * @return
     */
    private static String getExtName(String fileName){
        if(fileName.lastIndexOf(".") > -1){
            // 文件名称中包含字符 .
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        }else{
            // 文件名称中不包含字符 .
            return "";
        }
    }

    /**
     * 提供获取Storage客户端对象的工具方法
     */
    public static StorageClient getStorageClient(){
        return STORAGE_CLIENT;
    }

    private FastDFSUtils(){}
}

(4)service层

 @Override
    public boolean upload(MultipartFile file) {
        try {
            //将文件存入到Storage service中,返回值为长度为2的数组,一个为存储的仓库,一个为存储的文件路径
            String[] strings = FastDFSUtils.uploadFile(file.getInputStream(), file.getOriginalFilename(), "owner", "admin");

            if(strings==null){
                return false;
            }
            //将文件信息存储到数据库中
            MyFile myFile = new MyFile();
            myFile.setFileName(file.getOriginalFilename());
            myFile.setGroupName(strings[0]);
            myFile.setRemoteName(strings[1]);
            myFile.setLength(file.getSize());
            myFile.setCreateTime(new Date());
            int insert = uploadMapper.insert(myFile);
            if(insert != 1){
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

四、文件下载

(1)service层

 /**
     * 文件上传service
     * @param groupName 存储的主机
     * @param remoteName 存储的文件路径及文件名
     * @return
     */
    @Override
    public Map<String, Object> download(String groupName, String remoteName) {
        HashMap<String, Object> map = new HashMap<>();
        //获取文件二进制数组
        byte[] download = FastDFSUtils.download(groupName, remoteName);
        //获取文件元数据
        NameValuePair[] metaData = FastDFSUtils.getMetaData(groupName, remoteName);
        if(download != null && metaData != null){
            map.put("data",download);
            for (NameValuePair metaDatum : metaData) {
                if(metaDatum.getName().equals("fileName")){
                    map.put("fileName", metaDatum.getValue());
                    break;
                }
            }
        }
        return map;
    }

(2)controller

    @RequestMapping("/download")
    public void download(String groupName, String remoteName, HttpServletResponse response) throws IOException {
        Map<String, Object> download = uploadService.download(groupName, remoteName);
        // 设置响应头
        response.setContentType("application/octet-stream");
        // 设置下载文件的附件名称
        response.setHeader("content-disposition", "attachment;filename="+download.get("fileName").toString());
        // 输出要下载的文件内容到客户端
        byte[] datas = (byte[]) download.get("data");
        response.getOutputStream().write(datas, 0, datas.length);
    }

五、文件删除

 @Override
    public boolean delete(MyFile file) {
        //删除数据库文件
        int delete = uploadMapper.delete(file);
        //删除文件
        int remote = FastDFSUtils.remote(file.getGroupName(), file.getRemoteName());
        return delete>0&&remote==0;
    }

 六、文件预览

(1)Nginx简介

Nginx (engine x) 是一个高性能的HTTP和反向代理服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。

Nginx 是一个很强大的高性能Web和反向代理服务,它具有很多非常优越的特性:在连接高并发的情况下,Nginx是Apache服务不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一。

(2)代理方式

正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

两者间的区别

位置不同 正向代理,架设在客户机和目标主机之间; 反向代理,架设在服务器端;

代理对象不同 正向代理,代理客户端,服务端不知道实际发起请求的客户端; 反向代理,代理服务端,客户端不知道实际提供服务的服务端;

(3)Nginx常用场景

Http协议代理

只要支持HTTP协议访问的内容,都可以由Nginx进行代理。Nginx只支持HTTP协议的代理,其他协议不支持。

搭建虚拟主机

Nginx可以监听所安装的主机的某个端口,对外支持这个端口的HTTP访问。当接收到外部HTTP请求后把本机中资源返回给客户端。今天的课程内容就是使用Nginx的搭建虚拟主机功能,外部请求图片时,把图片信息响应给请求发。

负载均衡

Nginx可以代理多个主机,内置负载均衡策略。

(4)使用

使用http请求,ip+存储主机+存储路径及文件名

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

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

相关文章

golang爬虫练习-抓取行业信息分类

抓取框架介绍 gathertool gathertool是golang脚本化开发库&#xff0c;目的是提高对应场景程序开发的效率&#xff1b;轻量级爬虫库&#xff0c;接口测试&压力测试库&#xff0c;DB操作库等。 地址&#xff1a; https://github.com/mangenotwork/gathertool 下载: go get …

醛肽:Gly-Phe-Gly-aldehyde、102579-48-6

可逆组织蛋白酶 B 抑制剂 GFG-醛缩氨基脲已用于通过亲和层析从日本血吸虫中纯化组织蛋白酶 B 样蛋白酶 Sj31&#xff0c;并用于从疟原虫物种中分离恶性疟原虫。编号: 200138 中文名称: 三肽Gly-Phe-Gly-aldehyde CAS号: 102579-48-6 单字母: H2N-GFG-CHO 三字母: H2N-Gly-Phe-G…

Docker网络管理

目录 一、Docker 网络实现原理 二、Docker 的网络模式 1.四种网络模式 2.各网络模式详解 &#xff08;1&#xff09;Host模式 &#xff08;2&#xff09;Container模式 &#xff08;3&#xff09;None模式 &#xff08;4&#xff09;Bridge模式 3.指定容器网络…

常用的实体类转换方式 - BeanUtil | MapStruct

0. 相关依赖&#xff1a;1. 实体类信息&#xff1a;2. BeanUtil方法转换&#xff1a;2.1. 实体类转实体类&#xff08;copyProperties&#xff09;&#xff1a;2.2. 实体类集合转实体类集合&#xff08;copyToList&#xff09;&#xff1a;2.3. 实体类集合转Map&#xff08;bea…

java泛型类型解释

文章目录1、Class<T>使用写法2、常见字母含义举例说明3、object.getClass()和Object.class的区别举例说明1、Class 使用写法 mongoTemplate.findAll(Customer.class); 2、常见字母含义 E - Element (在集合中使用&#xff0c;因为集合中存放的是元素) T - Type&#x…

css修改滚动条样式

有一说一 系统默认的滚动条确实不是很美观 那么我就来带着大家修改一下他的样式 ::-webkit-scrollbar 设置整个滚动条的样式 一般用于设置宽度 你要跟什么元素加 就 元素::-webkit-scrollbar 例如你想 给body 就 body::-webkit-scrollbar ::-webkit-scrollbar-track 设置滚…

一周活动速递|Paper Time第五期;技术征文大赛即将收官

今天周一&#xff0c;小编为大家准时带来 「OceanBase 一周活动速递」 &#xff0c;活动按时间排序&#xff0c;欢迎大家关注&#xff01; Paper Time&#xff1a;基于无服务计算的机器学习方法 01 基本安排 时间&#xff1a; 11 月 23 日&#xff08;周三&#xff09;19:00-2…

让我们进入面向对象的世界(二)

让我们进入面向对象的世界(二) 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录让我们进入面向对象的世界(二)前言二.对象的操作三.让我们离对象村更进一步&#xff0c;进入面向对象封装的特性四 实例变量和局部变量…

ヾ(⌐ ■_■)— HTML-Emmet语法速查表

Emmet是一款文本编辑器/IDE的插件&#xff0c;用来快速生成复杂的HTML代码&#xff0c;只要掌握一些常用的语法&#xff08;类似于CSS选择器&#xff09;&#xff0c;就可以减少重复编码的工作。 1.调用方法 Emmet使用Tab作为自动生成HTML代码的触发器。输入完生成HTML的缩写…

Qt-FFmpeg开发-视频播放(4)

Qt-FFmpeg开发-视频播放【软解码 OpenGL显示YUV420P图像】 文章目录Qt-FFmpeg开发-视频播放【软解码 OpenGL显示YUV420P图像】1、概述2、实现效果3、FFmpeg软解码流程4、主要代码4.1 解码代码4.2 OpenGL显示RGB图像代码5、完整源代码更多精彩内容&#x1f449;个人内容分类汇…

图片如何转换为文字?这些软件可以实现

最近有小伙伴私信说&#xff0c;因为临近期末&#xff0c;老师上课的进度开始加快。他为了兼顾知识点能够当堂吸收&#xff0c;所以没有记笔记&#xff0c;而是将知识点都拍照下来&#xff0c;集中注意力上课。然而当他课后打算整理笔记却发现&#xff0c;自己原来拍了几十张图…

比较研究测井预测:遗传算法与神经网络(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

day071:网络编程(IP、端口、协议)、InetAddress类、UDP协议、TCP协议

目录 一、网络编程 1.网络编程三要素 2.IP地址 &#xff08;1&#xff09;IP地址&#xff08;每台计算机指定的标识号&#xff09; &#xff08;2&#xff09;类InetAddress:方便对IP地址获取和操作&#xff1b;此类表示Internet&#xff08;IP&#xff09;地址 3.端口&am…

LVS+Keepalived高可用群集

目录 一、keepalived简介 二、keepalived工作原理 三、LVS-DR模式keepalived 高可用集群部署 1、部署2台web服务器 2、部署2台负载调度器 四、总结 一、keepalived简介 Keepalived是通过vrrp 协议的实现高可用性&#xff0c;对网络比较了解的IT人&#xff0c;对这个技术应…

[操作系统笔记]调度与死锁杂项知识点

部分定义截取自书本 管态和目态 这说的是处理机的执行状态 管态又称为特权态&#xff0c;系统态&#xff0c;核心态。CPU在管态下可以执行指令系统的全集。如果程序处于管态&#xff0c;则该程序可以访问计算机的任何资源&#xff0c;它的资源访问权限不受限制&#xff0c;通常…

iOS16 中的 3 种新字体宽度样式

前言 在 iOS 16 中&#xff0c;Apple 引入了三种新的宽度样式字体到 SF 字体库。 Compressed Condensed Expend UIFont.Width Apple 引入了新的结构体 UIFont.Width&#xff0c;这代表了一种新的宽度样式。 目前已有的四种样式。 standard&#xff1a;我们总是使用的默认…

centos安装nacos

一、安装JDK环境和MySQL环境 jdk环境安装:centos安装jdk1.8_java-zh的博客-CSDN博客 MySQL环境安装:centos安装mysql5.7_java-zh的博客-CSDN博客 二、拉取nacos项目 GitHub主页&#xff1a;https://github.com/alibaba/nacos GitHub的Release下载页&#xff1a;https://…

ClickHouse教程 — 第一章 ClickHouse单机版安装

ClickHouse教程 — 第一章 ClickHouse单机版安装1 版本区别1.1 clickhouse-client-21.1.9.41以上版本1.2 clickhouse-client-21.1.9.41以下版本2 clickhouse-client-21.1.9.41以上版本2.1 下载2.2 解压安装2.3 启动2.4 clickhouse相关目录2.5 允许远程访问3 clickhouse-client-…

应用地球物理+AI:智能地球勘探

《地球物理人工之智能和信息前沿技术学术报告会》 主讲人&#xff1a;陆文凯 1. 地球物理学 地球科学的主要学科之一&#xff0c;是通过定量的物理方法&#xff08;如&#xff1a;地震、重、磁、电、测井、地热和放射能等方法&#xff09;研究地球以及寻找地球内部矿藏资源的一…

TD集群内存占用过高

1 TD简介 TDengine 是一款开源、云原生的时序数据库&#xff0c;专为物联网、工业互联网、金融、IT运维监控等场景设计并优化。它能让大量设备、数据采集器每天产生的高达 TB 甚至 PB级的数据得到高效实时的处理&#xff0c;对业务的运行状态进行实时的监测、预警&#xff0c;从…