FastDFS之快速入门、上手

知识概念

分布式文件系统

通过计算机网络将各个物理存储资源连接起来。通过分布式文件系统,将网络上任意资源以逻辑上的树形结构展现,让用户访问网络上的共享文件更见简便。

文件存储的变迁:

  • 直连存储:直接连接与存储,扩展性、灵活性差。如Tomcat、nginx。
  • 中心化存储:网络互联。
  • 分布式存储:资源存储在多个服务器,这个存储资源构成一个虚拟的存储设备。

常见的DFS

  • FastDFS :开源的轻量级分布式文件系统;
  • HDFS : Hadoop 子项目, Hadoop 的存储系统。
  • Taobao FileSystem :高扩展、高可用、高性能、面向互联网服务的分布式文件系统,针对海量非结构化数据,构建在普通linux机器集群上,提供高可靠、高并发的存储访问。
    • 为淘宝提供海量小文件存储,通常不超1M。
    • 采用HA架构和平滑扩容。

HA架构:通过设计,减少系统不可用的时间。通过 冗余(集群) + 自动故障转移来实现。

  • GridFS:mongodb内置功能。文件分成两份:索引和文件内容。它们存储在集合中,文件内容等分成若干块存储在文档中。一般以4M作为分块存储单位。
  • Google File System :非开源。
  • MogileFS : 由Six Apart开发,广泛应用在 包括LiveJournal等web2.0站点上 。
文件系统FastDFSHDFSTFSMogileFS
数据存储 方式文件/块文件文件文件
集群通讯 协议私有协议私有协议私有协议Http
扩容支持支持支持支持
冗余备份支持支持支持不 支持
单点故障不存在存在存在存在
跨集群同 步部分支持不支持支持不支持
开发语言CJavaC++Perl
适合类型4KB - 500MB大文件所有文件海量小图片
复杂度简单简单复杂复杂
易用性安装简单,社区 活跃安装简单,文档 专业安装复杂,文档 较少安装复杂,文档 较少
研发团队国内开发者-余庆ApacheAlibabaDanga Interactive
FUSE不支持支持不支持支持
POSIX不支持支持无资料不支持

常见DFS提供商

  • 阿里OSS
  • 七牛云存储
  • 百度云存储

FastDFS简介

FastDFS是用C语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。 FastDFS专为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高 性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

功能概况

文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡 的问题。特别适合以中小文件( 建议范围: 4KB 到 500MB ) 为载体的在线服务,如:相册网站、视 频网站等等

架构

FastDFS架构包括 Tracker Server和Storage Server 。 Tracker Server负责处理客户端的文件上传、下载请求,通过调度,追踪定位 Storage Server 目标,最后由其完成文件下载、上传。
image.png

Tracker Server

作用是负载均衡和调度。在FastDFS集群中,可以有多台Tracker Server 同时提供服务,不存在单点故障。

Storage Server

处理文件存储,使用操作系统的文件系统管理文件。
采用分组存储方式,集群由多个一个或多个分组组成,集群容量是集群内所有组的总和,不同组之间不会互相通信,同组内相互连接同步文件(所以组的容量由组内最小容量的节点决定)。
使用分组的方式,比较灵活易扩展。客户端可以直接指定上传的组,也可以由Tracker进行调度;当访问压力大的时候,也可以通过增加组内存储服务器来提高服务能力;当容量不足时,可以增加分组,提高容量。

Storage 状态收集

Storage会连接所有Tracker,然后汇报自己的状态。,包括磁盘空间、文件同步情况、文件上传下载次数等统计信息。

文件上传流程

image.png
客户端拿到file_id之后,存储起来,后续通过file_id拿到文件。
file_id相当于一个索引,其文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。

例如:group1/M00/00/00/wKjIgGNslmOAf5VSAACQjdb7ANw5904822

  • 组名:文件上传后所在的分组;
  • 虚拟磁盘路径:通过store_path指定的 Storage 虚拟路径。 store_path0(相当于一个组内节点) 是M00 ,了store_path1则是M01,以此类推。
  • 数据两级目录 : 在 虚拟磁盘路径下创建的两级目录,用于存储数据文件。
  • 文件名:由存储服务器根据特定信息(源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息)生成。

文件下载流程

image.png

  • 通过组名, tracker 能快速锁定所在分组,然后 tracker 会选择一个合适的存储节点,并把节点信息返回给客户端。
  • 客户端访问存储服务器的时候,存储服务器可以通过文件虚拟路径数据两级目录来快速定位文件,并根据文件名找到访问的文件。

准备环境

开几个ubuntu18虚拟机:

节点IP域名端口开放
tracker1192.168.204.167tracker122122
tracker2192.168.204.168tracker222122
storage1192.168.204.169storage123000、8888
storage2192.168.204.170storage123000、8888

修改一下自己电脑的host文件:

192.168.204.167 tracker1
192.168.204.168 tracker2
192.168.204.169 storage1
192.168.204.170 storage2

下载镜像:
docker pull morunchang/fastdfs

https://hub.docker.com/r/morunchang/fastdfs

tracker

在tracker1、tracker2服务器运行下面命令(运行前检查tracker_data目录是否创建了)。
默认端口:22122。

docker run -d --name tracker -p 22122:22122 -v ~/tracker_data:/data/fast_data  --net=host morunchang/fastdfs sh tracker.sh

–net:支持 bridge/host/none/container 四种类型

storage

在storage1、storage2服务器运行下面命令(运行前检查storage_data、store_path目录是否创建了)。


docker run -d --name storage \
-v ~/storage_data:/data/fast_data \
-v ~/conf/nginx.conf:/etc/nginx/conf/nginx.conf \
--net=host -e GROUP_NAME=group1 \
-e TRACKER_IP=tracker1:22122,tracker2:22122 \
morunchang/fastdfs sh storage.sh



#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       8888;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location ~ /M00 {
                    root /data/fast_data/data;
                    ngx_fastdfs_module;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

整合SpringBoot

去github拉取源码,然后mvn clean install到本地仓库(官方没有发布到maven中心仓库),最后再引入依赖:

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

image.png

# http连接超时时间
connect_timeout = 2
# tracker与storage网络通信超时时间
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
http.anti_steal_token = no
http.secret_key = FastDFS1234567890
# tracker服务器地址,可以重复配置多个
tracker_server = tracker1:22122
tracker_server = tracker2:22122

# 连接池配置
connection_pool.enabled = true
connection_pool.max_count_per_entry = 500
connection_pool.max_idle_time = 3600
connection_pool.max_wait_time_in_ms = 1000

package com.example.demofastdfs.test;

import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.*;
import java.util.Arrays;

/**
 * @className: FastDFSDemo
 * @description: TODO 类描述
 * @author: liangshijie
 * @date: 2023/3/5
 **/
public class FastDFSDemo {
    private static final String CONF_NAME = "fdfs_client.conf";
    private StorageClient storageClient;
    private TrackerServer trackerServer;

    @Before
    public void initStorageClient() throws Exception {
        ClientGlobal.init(CONF_NAME);
        System.out.println("network_timeout=" +
                ClientGlobal.g_network_timeout + "ms");
        System.out.println("charset=" + ClientGlobal.g_charset);
        TrackerClient tracker = new TrackerClient();
        trackerServer = tracker.getTrackerServer();
        StorageServer storageServer = new StorageServer("storage1", 23000, 0);
        storageClient = new StorageClient(trackerServer, storageServer);
//        storageClient = new StorageClient(trackerServer, storageServer);
    }

    /**
     * 测试上传文件
     */
    @Test
    public void upload() throws Exception {
        // http://storage2:23000/group1/M00/00/00/wKjMqWQHVleAFzK7AAAWWKCNj-E2720984.jpg
        NameValuePair[] metaList = new NameValuePair[1];
        String local_filename = "dog.png";
        metaList[0] = new NameValuePair("fileName", local_filename);
        File file = new File("C:\\Users\\admin\\Desktop\\dog.png");
        InputStream inputStream = new FileInputStream(file);
        int length = inputStream.available();
        byte[] bytes = new byte[length];
        inputStream.read(bytes);
        String[] result = storageClient.upload_file(bytes, "jpg", metaList);
//        String[] result = storageClient.upload_file(bytes, null, metaList);
        System.out.println("result {}" + Arrays.asList(result));
    }

    //查询文件
    @Test
    public void testQueryFile() throws IOException, MyException {
//        group1, M00/00/00/wKjMqWQGk_WAesAEAAAWWKCNj-E4269595
        FileInfo fileInfo = storageClient.query_file_info("group1", "M00/00/00/wKjMqWQGk_WAesAEAAAWWKCNj-E4269595");
        System.out.println(fileInfo);

    }

    /**
     * 测试下载
     */
    @Test
    public void download() throws Exception {
        String[] uploadresult = {"group1",
                "M00/00/00/wKjMqWQGk_WAesAEAAAWWKCNj-E4269595"};
        byte[] result = storageClient.download_file(uploadresult[0],
                uploadresult[1]);
        String local_filename = "dog_two.png";
//文件写入磁盘
        writeByteToFile(result, local_filename);
        File file = new File(local_filename);
        System.out.println("file.isFile = " + file.isFile());
    }

    @After
    public void closeClient() {
        System.out.println("close connection");
        if (storageClient != null) {
            try {
                storageClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

    public void writeByteToFile(byte[] fbyte, String fileName) throws
            IOException {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = new File(fileName);
        try {
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(fbyte);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                bos.close();
            }
            if (fos != null) {
                fos.close();
            }
        }
    }

}

测试地址

http://storage1:8888/group1/M00/00/00/wKjMqWQHWfqAGM9mAAAWWKCNj-E813.jpg

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Oracle regexp_substr

select regexp_substr(123|456|789, [^|], 1, 2) from dual;

暴雨信息发布算力网络应用平台打造零感知算网服务新模式

为进一步优化算力网络应用服务能力和降低算力网络使用难度&#xff0c;暴雨信息突破基于算力网络的实例跨域协同与迁移、基于测试评估的应用度量和解构等技术&#xff0c;研发并推出算力网络应用平台。该系统通过提供一种即开即用、按需付费的零感知算网应用服务&#xff0c;使…

Python基础语法(上)——基本语法、顺序语句、判断语句、循环语句(有C++基础快速掌握Python语言)

文章目录 0.python小技巧与易错点1.python 与 c 语法有哪些区别2.Python基本语法2.1python的变量类型2.2python中的运算符2.3python中的表达式2.4python中的输入输出 3.python判断语句3.1基本用法&#xff1a;3.2关于else if 的用法3.3关于pass语句3.4python变量的作用域3.5pyt…

THB6128两相四线步进电机PWM驱动控制

THB6128两相四线步进电机驱动控制模块&#xff0c;可以驱动57及以下两相四线步进电机。该模块有以下优点&#xff1a; 芯片使用双全桥MOSFET驱动&#xff0c;低导通电阻Ron 0.55Ω最高耐压36V&#xff0c;峰值电流2.2A&#xff0c;持续电流2A&#xff0c;电流设定通过拨码开关…

大模型LLM在 Text2SQL 上的应用实践

一、前言 目前&#xff0c;大模型的一个热门应用方向Text2SQL&#xff0c;它可以帮助用户快速生成想要查询的SQL语句&#xff0c;再结合可视化技术可以降低使用数据的门槛&#xff0c;更便捷的支持决策。本文将从以下四个方面介绍LLM在Text2SQL应用上的基础实践。 Text2SQL概…

常用注解/代码解释(仅个人使用)

目录 第一章、代码解释①trim() 方法以及(Arrays.asList(str.split(reg)));②查询字典项②构建后端镜像shell命令解释 第二章、注解解释①PropertySource注解与Configurationproperties注解的区别 第三章、小知识①Linux系统中使用$符号表示变量 友情提醒: 先看文章目录&#…

Android学习(四):常用布局

Android学习&#xff08;四&#xff09;&#xff1a;常用布局 五种常用布局 线性布局&#xff1a;以水平或垂直方向排列相对布局&#xff1a;通过相对定位排列帧布局&#xff1a;开辟空白区域&#xff0c;帧里的控件(层)叠加表格布局&#xff1a;表格形式排列绝对布局&#x…

C语言之三子棋小游戏的应用

文章目录 前言一、前期准备模块化设计 二、框架搭建三、游戏实现打印棋盘代码优化玩家下棋电脑下棋判断输赢 四、结束 前言 三子棋是一种民间传统游戏&#xff0c;又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战&#xff0c;双方依次在9宫格棋盘上摆放棋子&#…

2024--Django平台开发-Django知识点(六)

day06 Django知识点 今日概要&#xff1a; Form和ModelForm组件【使用】【源码】缓存【使用】ORM【使用】其他&#xff1a;ContentTypes、Admin、权限、分页、信号等 1.Form和ModelForm组件 背景&#xff1a;某个公司后台管理项目。 垃圾 def register(request):"&quo…

PowerDesigner简介以及简单使用

软件简介&#xff1a; PowerDesigner是Sybase公司开发的数据库设计工具&#xff0c;开发人员能搞利用PowerDesigner开发数据流程图、各数据模型如物理数据模型&#xff0c;可以分别从概念数据模型(Conceptual Data Model)和物理数据模型(Physical Data Model)两个层次对数据库…

互联网加竞赛 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据…

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷5

某企业根据自身业务需求&#xff0c;实施数字化转型&#xff0c;规划和建设数字化平台&#xff0c;平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”&#xff0c;拟采用开源OpenStack搭建企业内部私有云平台&#xff0c;开源Kubernetes搭建云原生服务平台&#xff0c;选…

[Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例

在群組中看到上述問題&#xff0c;研判應是一份隨月份變動的產品報價表單&#xff0c;空白欄可能表示該月份價格與上個月份一致。這個問題是需要取得最近一次單價和倒數第二次單價&#xff0c;常用且實務的excel案例值得紀錄。 最近一次單價: INDEX($B2:$G2,1,LARGE(IF(ISBLAN…

鸿蒙原生应用再添新丁!京东入局鸿蒙

鸿蒙原生应用再添新丁&#xff01;京东入局鸿蒙 来自 HarmonyOS 微博1月10日消息&#xff0c;#京东启动鸿蒙原生应用开发#&#xff01;优惠信息、派送进度都可以随时随地便捷查询。双方将携手为消费者带来全场景“多快好省”购物体验&#xff0c;更智能&#xff0c;更贴心&…

【Python机器学习】SVM——线性模型与非线性特征

SVM&#xff08;核支持向量机&#xff09;是一种监督学习模型&#xff0c;是可以推广到更复杂模型的扩展&#xff0c;这些模型无法被输入空间的超平面定义。 线模型在低维空间中可能非常受限&#xff0c;因为线和平面的灵活性有限&#xff0c;但是有一种方式可以让线性模型更加…

three.js实现扩散波效果

three.js实现扩散波效果 图例 步骤 创建一个圆柱&#xff0c;不要顶与底面材质允许透明&#xff0c;双面显示动态修改缩放与透明度 代码 <template><div class"app"><div ref"canvesRef" class"canvas-wrap"></div>…

jmeter+ant+Jenkins集成

一、 环境准备 1、Jenkins下载&#xff1a;https://jenkins.io/zh/download/ 2、 Jenkins安装&#xff1a;解压下载的压缩包&#xff0c;直接点击msi文件安装即可 4、 Jenkins登录用户设置&#xff1a;装&#xff1a; 浏览器地址栏中输入&#xff1a;http://localhost:8080/…

jmeter分布式测试

场景&#xff1a;需求要求使用用大量的客户访问时&#xff0c;可以使用分布式来完成 分布式实现原理&#xff1a; 材料&#xff1a;一台控制机器&#xff0c;若干台代理机也叫执行机 运行时&#xff0c;控制机将脚本发送到代理机上-->代理机拿到就开始执行&#xff0c;不会…

Kaniko

一. Kaniko 官网 Kaniko 是一个是谷歌开源的一款用来构建容器镜像在k8s集群内构建容器镜像的工具&#xff0c;使用时&#xff0c;需要一个 Kubernetes 集群&#xff0c; 可以在 Kubernetes 上无需特权的构建 image&#xff0c;k8s CRI无需docker使用后 pull 和 push 镜像很慢…

一文彻底理解 Cookie、Session、Token

很久以前&#xff0c;Web 基本上就是文档的浏览而已&#xff0c;既然是浏览&#xff0c;作为服务器&#xff0c;不需要记录谁在某一段时间里都浏览了什么文档&#xff0c;每次请求都是一个新的 HTTP 协议&#xff0c;就是请求加响应&#xff0c;尤其是我不用记住是谁刚刚发了 H…