1 什么是分布式文件系统

1.1什么是文件系统

引用“百度百科”中的描述:

1523143569917

​ 总结:文件系统是负责管理和存储文件的系统软件,它是操作系统和硬件驱动之间的桥梁,操作系统通过文件系统提供的接口去存取文件,用户通过操作系统访问磁盘上的文件。如下图:

1523146202692

常见的文件系统:FAT16/FAT32、NTFS、HFS、UFS、APFS、XFS、Ext4等 。

思考:如果没有文件系统我们该怎么管理自己的文件?

1523146408290

1.2 什么是分布式文件系统

引用“百度百科”中的描述:1523143450086

为什么会有分布文件系统呢?

​ 分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经满足不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,另外我们还要要做好数据备份、数据安全等。

​ 采用分布式文件系统可以将多个地点的文件系统通过网络连接起来,组成一个文件系统网络,结点之间通过网络进行通信,一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算共同传输。如下图:

1523148802075

​ 好处:

​ 1、一台计算机的文件系统处理能力扩充到多台计算机同时处理。

​ 2、一台计算机挂了还有另外副本计算机提供数据。

​ 3、每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度。

1.3 主流的分布式文件系统

1、NFS

1523149559554

1523150201123

​ 1)在客户端上映射NFS服务器的驱动器。

​ 2)客户端通过网络访问NFS服务器的硬盘完全透明。

2、GFS

1523149801475

1523150073582

1)GFS采用主从结构,一个GFS集群由一个master和大量的chunkserver组成。

2)master存储了数据文件的元数据,一个文件被分成了若干块存储在多个chunkserver中。

3)用户从master中获取数据元信息,从chunkserver存储数据。

3、HDSF

1523151108635

1523151086985

1)HDFS采用主从结构,一个HDFS集群由一个名称结点和若干数据结点组成。

​ 名称结点存储数据的元信息,一个完整的数据文件分成若干块存储在数据结点。

2)客户端从名称结点获取数据的元信息及数据分块的信息,得到信息客户端即可从数据块来存取数据。

1.4分布式文件服务提供商

1)阿里的OSS

1523152195782

2)七牛云存储

3)百度云存储

2 什么是fastDFS

2.1 fastDSF介绍

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

​ 为什么要使用fastDFS呢?

​ 上边介绍的NFS、GFS都是通用的分布式文件系统,通用的分布式文件系统的优点的是开发体验好,但是系统复杂性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。fastDFS非常适合存储图片等那些小文件,fastDFS不对文件进行分块,所以它就没有分块合并的开销,fastDFS网络通信采用socket,通信速度很快。

2.2 fastDSF工作原理

2.2.1 fastDSF架构

​ FastDFS架构包括 Tracker server和Storageserver。客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。

如下图:

1523153786785

**1)Tracker **

​ Tracker Server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。

​ FastDFS集群中的Tracker server可以有多台,Tracker server之间是相互平等关系同时提供服务,Tracker server不存在单点故障。客户端请求Tracker server采用轮询方式,如果请求的tracker无法提供服务则换另一个tracker。

2)Storage

​ Storage Server作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的文件系统而是使用操作系统的文件系统来管理文件。可以将storage称为存储服务器。

​ Storage集群采用了分组存储方式。storage集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,组内的Storage server之间是平等关系,不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的。一个组的存储容量为该组内存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。

​ 采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由tracker进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。

3)Storage状态收集

​ Storage server会连接集群中所有的Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。

2.2.2文件上传流程

1523155433891

​ 客户端上传文件后存储服务器文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。

1523155556871

  • 组名:文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。

  • 虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。

  • 数据两级目录:storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。

  • 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

2.2.3 文件下载流程

1523155448191

tracker根据请求的文件路径即文件ID 来快速定义文件。

比如请求下边的文件:

1523155556871

1.通过组名tracker能够很快的定位到客户端需要访问的存储服务器组是group1,并选择合适的存储服务器提供客户端访问。

2.存储服务器根据“文件存储虚拟磁盘路径”和“数据文件两级目录”可以很快定位到文件所在目录,并根据文件名找到客户端需要访问的文件。

3 fastDFS入门

3.1fastDFS安装与配置

参考:http://www.pbteach.com/post/java_distribut/fastdfs_setup/

3.2 文件上传下载测试

3.2.1搭建环境

这里我们使用javaApi测试文件的上传。

java版本的fastdfs-client下载地址在:

链接:https://pan.baidu.com/s/1TbaXxnvDKRcFSfLZy1QgNg
提取码:yh08

参考此工程编写测试用例。

1)创建maven工程

2)添加依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.9.RELEASE</version>
</parent>
<groupId>com.pbteach.javaee</groupId>
<artifactId>fastdfs</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/net.oschina.zcx7878/fastdfs-client-java -->
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.3.2</version>
    </dependency>
</dependencies>
  1. 配置 文件

在classpath:config下创建fastdfs-client.properties文件

fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 192.168.101.64:22122

3.2.2 文件上传

//上传文件
@Test
public void testUpload() {

    try {
        ClientGlobal.initByProperties("config/fastdfs-client.properties");
        System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
        System.out.println("charset=" + ClientGlobal.g_charset);

        TrackerClient tc = new TrackerClient();

        TrackerServer ts = tc.getConnection();
        if (ts == null) {
            System.out.println("getConnection return null");
            return;
        }

        StorageServer ss = tc.getStoreStorage(ts);
        if (ss == null) {
            System.out.println("getStoreStorage return null");
        }

        StorageClient1 sc1 = new StorageClient1(ts, ss);

        NameValuePair[] meta_list = null;  //new NameValuePair[0];
        String item = "C:\\Users\\admin\\Desktop\\1.png";
        String fileid;
        fileid = sc1.upload_file1(item, "png", meta_list);

        System.out.println("Upload local file " + item + " ok, fileid=" + fileid);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

3.2.3 文件查询

//查询文件
@Test
public void testQueryFile() throws IOException, MyException {
    ClientGlobal.initByProperties("config/fastdfs-client.properties");

    TrackerClient tracker = new TrackerClient();
    TrackerServer trackerServer = tracker.getConnection();
    StorageServer storageServer = null;

    StorageClient storageClient = new StorageClient(trackerServer,
            storageServer);
    FileInfo fileInfo = storageClient.query_file_info("group1", "M00/00/01/wKhlQFrKBSOAW5AWAALcAg10vf4862.png");
    System.out.println(fileInfo);
}

3.2.4 文件下载

//下载文件
@Test
public void testDownloadFile() throws IOException, MyException {
    ClientGlobal.initByProperties("config/fastdfs-client.properties");

    TrackerClient tracker = new TrackerClient();
    TrackerServer trackerServer = tracker.getConnection();
    StorageServer storageServer = null;

    StorageClient1 storageClient1 = new StorageClient1(trackerServer,
            storageServer);
    byte[] result = storageClient1.download_file1("group1/M00/00/01/wKhlQFrKBSOAW5AWAALcAg10vf4862.png");
    File file = new File("d:/1.png");
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    fileOutputStream.write(result);
    fileOutputStream.close();
}

4 文件服务案例

4.1 目标

通过文件服务案例达到以下目标:

1、理解fastDFS在实际项目中的使用方法。

2、能够使用fastDSF实现图片服务器。

4.2需求分析

1523165496820

说明如下:

1、管理员在管理系统中上传图片到fastDFS文件系统。

1)管理员进入管理系统,点击上传图片,选择本地图片

2)选择本地图片后,进行上传,前端浏览器会通过http调用文件管理服务的文件上传接口进行上传

3)文件管理服务通过socket请求fastDFS文件系统的上传图片,最终图片保存在fastDFS文件系统中的storage server中。

2、网友浏览免费视频的课程图片

1)网友输入www.pbteach.com进入下载页面

2)前端浏览器通过图片地址请求图片服务器代理(nginx)

3)图片服务器代理根据负载情况将图片浏览请求转发到一台storage server

4)storage server找到图片后通过nginx将图片响应给网友

4.3 功能开发

4.3.1 搭建fastDFS文件服务器

1)安装fastDFS tracker和storage

2)在storage server上安装nginx

在storage server上安装nginx的目的是对外通过http访问storage server上的文件。

使用nginx的模块FastDFS-nginx-module,它的作用是通过http方式访问storage中的文件,当storage本机没有要找的文件时向源storage主机代理请求文件。

详细参见 fastDFS安装教程

3)在安装图片服务代理

图片服务代理的作用是负载均衡,根据storage server的负载情况将图片浏览请求均匀的转发到storage server上。

4.3.2 搭建文件管理服务

文件管理服务提供通过http方式上传文件,删除文件、查询文件的功能,管理员通过文件管理服务对文件服务器上的文件进行管理。

文件管理服务采用Spring Boot开发,文件管理服务通过与fastDFS交互最终将用户上传的文件存储到fastDFS上。

在fastDFS入门程序上继续开发:

1)创建模型

package com.pbteach.java.fastdfs.model;

/**
 * Created by www.pbteach.com on 2018/4/8.
 */
public class FileSystem {
    private String fileId;

    private String filePath;

    private long fileSize;

    private String fileName;

    private String fileType;

    public String getFileId() {
        return fileId;
    }

    public String getFilePath() {
        return filePath;
    }

    public long getFileSize() {
        return fileSize;
    }

    public String getFileName() {
        return fileName;
    }

    public String getFileType() {
        return fileType;
    }

    public void setFileId(String fileId) {
        this.fileId = fileId;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public void setFileSize(long fileSize) {
        this.fileSize = fileSize;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public void setFileType(String fileType) {
        this.fileType = fileType;
    }
}

2)创建controller

package com.pbteach.java.fastdfs.web.controller;

import com.pbteach.java.fastdfs.model.FileSystem;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;

/**
 * Created by www.pbteach.com on 2018/4/8.
 */
@RestController
@RequestMapping("/fileserver")
public class FileServerController {

    @Value("${pbteach-fastdfs.upload_location}")
    private String upload_location;

    @PostMapping("/upload")
    @ResponseBody
    public FileSystem upload(@RequestParam("file")MultipartFile file){
        FileSystem fileSystem = new FileSystem();
        try {
            ClientGlobal.initByProperties("config/fastdfs-client.properties");

            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;
            StorageClient1 client = new StorageClient1(trackerServer, storageServer);
            //MultipartFile转成File
            String originalFilename = file.getOriginalFilename();//原始文件名

            String extension = originalFilename.substring(originalFilename.lastIndexOf("."));//扩展名
            String newFileName = UUID.randomUUID().toString() + extension;
            File f = new File(upload_location + newFileName);
            file.transferTo(f);

            NameValuePair nvp[] = null;

            String local_filename = f.getAbsolutePath();
            //上传到文件系统
            String fileId = client.upload_file1(local_filename, null,
                    nvp);

            //文件在文件系统中的路径
            fileSystem.setFilePath(fileId);
            fileSystem.setFileId(fileId);
            long size = file.getSize();//文件大小
            //文件大小
            fileSystem.setFileSize(size);
            String contentType = file.getContentType();
            //文件类型
            fileSystem.setFileType(contentType);
            //文件名称
            if (fileSystem.getFileName() == null || fileSystem.getFileName().equals("")) {
                //如果没有传入文件名称则存储文件的原始名称
                fileSystem.setFileName(file.getOriginalFilename());
            }
			//删除web服务器上的文件
            f.deleteOnExit();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return fileSystem;
    }
}

3)创建application.yml

server:
  port: 22100
pbteach-fastdfs:
  #文件上传临时目录
  upload_location: F:\\develop\\upload\\

4)创建spring boot启动类

package com.pbteach.java.fastdfs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Created by www.pbteach.com on 2018/4/8.
 */
@SpringBootApplication
public class FileServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(FileServerApplication.class);
    }
}

4.3.3 管理系统前端

管理员通过管理系统前端上传文件、查询文件、删除文件等操作。

管理系统前端与文件管理服务器通过http交互,这当前流行的前后端分离的架构。

管理系统前端采用当前浏览器的vue.js前端框架实现。

1、创建前端工程

使用webstorm创建前端工程

工程需要导入vue.js及element-ui

1523170445103

2、创建upload.html

该文件实现文件上传及预览

1)导入js及 css

<link rel="stylesheet" href="css/el/index.css" />
<script src="js/vue/vue.min.js"></script>
<script src="css/el/index.js"></script>

2)创建vue实例

var vm= new Vue({   
    el: "#app", 

    data:{
       
    },
    methods: {
        
    },

})

3)添加element-ui的文件上传组件

 <el-upload
            action="/fileserver/upload"
            list-type="picture-card"
            :on-preview="handlePictureCardPreview"
            :on-remove="handleRemove">
        <i class="el-icon-plus"></i>
  </el-upload>
  <el-dialog :visible.sync="dialogVisible">
        <img width="100%" :src="dialogImageUrl" alt="">
        </el-dialog>

定义数据对象及方法 :

var vm= new Vue({
        el: "#app",

        data:{
            dialogImageUrl: '',
            dialogVisible: false
        },
        methods: {

            handleRemove(file, fileList) {
                console.log(file, fileList);
            },
            handlePictureCardPreview(file) {
                console.log(file)
                this.dialogImageUrl = 'http://192.168.101.64/'+file.response.filePath;
                this.dialogVisible = true;
            }
        },

    })

4)配置 nginx虚拟目录

server {
  listen       7283;
  server_name  localhost;
  location / {
      alias   F:/teach/fastDFS公开课/code/fastDFSTest/fastdfs_ui/;
      index  index.html;
  }
  location ^~ /fileserver/ {  
      proxy_pass http://127.0.0.1:22100/fileserver/;  
  }  
}  

5)测试

1523172148537

4.3.4 课程图片浏览

网友(学习者)输入www.pbteach.cn网址进入免费视频下载页面,浏览器根据页面上的图片地址请求图片服务代理,由代理将请求转发到fastDFS storage server上,最终在浏览器看到图片。

上章节实现图片上传后已经实现图片的预览,本功能实现略。

5 总结

通过本次课程的学习您要达到以下目标:

1)了解分布式文件系统的概念及应用场景

分布式文件系统是通过网络将单机上的文件系统组成一个网络文件系统。

分布式文件系统主要应用在大型互联网项目中,实现图片存储、音视频存储等服务。

分布式文件系统的优点:可以快速扩容存储,提高文件访问速度。

2)理解fastDFS的工作原理

fastDFS由tracker和storage组成,它们都可以部署集群。

tracker负责调度,storage负责存储。

3)掌握fastDFS存取文件方法

客户端与fastDFS采用socket协议通信,可以采用官方提供的java版本的fastDSF-client快速开发。

4)能够动手搭建一个fastDSF文件服务器

Logo

前往低代码交流专区

更多推荐