FastDFS 分布式文件系统


前言

文章中的代码


提示:以下是本篇文章正文内容,下面案例可供参考

一、FastDFS是什么?

1.1 思考

  1. 在分布式集群环境中上传文件,我们想要上传到节点A,但是通过负载均衡的算法,上传时,将文件传到了节点B;这种情况下,我们能否精准的访问到我们上产的文件?
  2. 同时考虑如何为文件做冗余备份、负载均衡、线性扩容?这些能力,单节点是否具备?

1.2 FastDFS介绍

  • FastDFS是一个开源的、轻量级的 分布式文件系统 ,它对文件的管理包括:文件存储、文件同步、文件访问(上传、下载)等等,解决了大容量存储和负载均衡的问题。特别适合以文件为猜题的在线服务(如相册网站、视频网站等);
  • FastDFS为互联网量身定做,充分考虑了冗余备份、负载均衡、线性扩容等机制,
  • 注重高可用、高性能指标,可以很容易的搭建一套高性能的文件还能服务器集群并提供服务;
  • FastDFS包括 Tracker serverStorage server 。客户端请通过求Tracker server进行文件操作,而 Tracker server 调度最终由 Storage server完成文件的实际操作(如上传、下载等);
  • Tracker Server:追踪服务器或调度服务器 作用是负载均衡调度,Tracker server 在文件上传时,可以根据以下策略找到 Storage server 提供文件上传服务;
  • Storgae server:存储服务器 作用是文件存储,客户端上传的文件,最终存储在 Storage server 上, Storage server没有实现自己的文件系统,而是利用操作系统的文件系统来管理文件。
    在这里插入图片描述

1.3 上传流程

在这里插入图片描述

  • 客户端上传文件后,存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息;
  • 文件索引信息包括:组名(group)、虚拟磁盘路径、数据存储的两级目录和文件名(新生成的)。
    1. 组名:文件上传后所在的 storage 组名称,文件上传成功后,由 storgae 服务器返回,需要我们自己进行保存
    2. 虚拟磁盘名:Storage 配置的虚拟路径,与磁盘选项 store_path*对应 。如果配置了 stroe_path0 则是M00,如果配置了 store_path1 就是M01,以此类推。
    3. 数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件;
    4. 文件名:与文件上传时不同。是由存储服务器根据特定信息生成的,文件名包括:源存储服务器IP地址、文件上传的时间戳、文件大小、随机数和文件扩展名等信息。

二、FastDFS使用

2.1 安装

在 centOS 7 环境下使用Docker 安装FastDFS

  1. 拉取镜像
docker pull morunchang/fastdfs

在这里插入图片描述
2. 创建并运行 tracker
sh tracker.sh:进入容器是执行的初始化指令,进入tracker之后,执行Tracker.sh脚本。

docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh

在这里插入图片描述
3. 创建并运行storage
使用时 < your tracker server address > 要替换称自己的IP,
< group name > 要替换成自己的组名;

docker run -d --name storage --net=host -e TRACKER_IP=<your tracker server address>:22122 -e
GROUP_NAME=<group name> morunchang/fastdfs sh storage.sh

eg:

docker run -d --name storage --net=host -e TRACKER_IP=192.168.119.130:22122 -e
GROUP_NAME=group1 morunchang/fastdfs sh storage.sh

说明:

  • –net=host 是使用的网络模式,这种模式下,可以不用映射容器和宿主机的ip和端口,容器的ip和端口会暴露出来,直接通过宿主机的ip和端口就可以使用;
  • 组名,是 storage 的组名
  • 新增 storage 容器,只需要重复第 3 步的命令,但是要注意更换 组名;

2.2 修改配置

  1. 进入 storage 的内部,修改nginx的配置文件 nginx.conf;
docker exec -it storage /bin/bash

进入后

vi  /etc/nginx/conf/nginx.conf

找到以下内容

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

添加配置项:

add_header Cache-Control no-store;

在这里插入图片描述

这项配置的作用是,禁止使用缓存。
修改之后,记得重启storage容器

2.3 文件上传微服务

2.3.1 父工程pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kaikeba</groupId>
    <artifactId>fastDFS</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>eureka-server</module>
        <module>upload-service</module>
        <module>bill</module>
    </modules>
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.1.18.RELEASE</version>
    </parent>
    <!-- 版本管理 -->
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud-version>Greenwich.SR1</spring-cloud-version>
        <tk-mybatis.version>2.1.5</tk-mybatis.version>
        <mysql-connection-version>8.0.25</mysql-connection-version>
        <pagehelper.version>5.1.2</pagehelper.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- spring cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- tk mybatis -->
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>2.1.5</version>
            </dependency>

            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql-connection-version}</version>
            </dependency>

            <!-- 分页 -->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper</artifactId>
                <version>${pagehelper.version}</version>
            </dependency>
        </dependencies>

    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.3.2 注册中心eureka-server

2.3.2.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>fastDFS</artifactId>
        <groupId>com.kaikeba</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>
2.3.2.2 application.yml
server:
  port: 8080

spring:
  application:
    name: eureka-server

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka
    register-with-eureka: false
  server:
    enable-self-preservation: false  # 关闭自我保护
    eviction-interval-timer-in-ms: 6000 #失效服务扫描的时间间隔
2.3.2.3 EurekaServerApplication.java
package com.kaikeba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class);
    }
}

2.3.3 文件上传服务

2.3.3.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>fastDFS</artifactId>
        <groupId>com.kaikeba</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>upload-service</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- FastDFS依赖 -->
        <dependency>
            <groupId>com.github.tobato</groupId>
            <artifactId>fastdfs-client</artifactId>
            <version>1.26.7</version>
        </dependency>
    </dependencies>

</project>
2.3.3.2 application.yml

这里要特别注意的是fdfs配置内容:

  • connect-timeout: 连接超时时间
  • so-timeout: 文件处理时间
  • thumb-image: 缩略图的配置
  • tracker-list: 调度服务器的ip列表
server:
  port: 8000

spring:
  application:
    name: uoload-service
  servlet:
    multipart:
      enabled: true
      max-file-size:  10MB  #单个文件上传的大小限制
      max-request-size: 20MB  #上传文件的大小的总限制

logging:
  pattern:
    console: "%d - %msg%n"
  level:
    org.springframework.web: debug
    com.kaikeba: debug

# fastDFS设置
fdfs:
  connect-timeout: 60 # 连接超时时间
  so-timeout: 60 # 读取时间(也就是上传的处理时间),超过这个时间也认为是失败
  thumb-image:  # 缩略图片的尺寸设置
    width: 150
    height: 150
  tracker-list:
    - 192.168.119.130:22122  # 地址

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    lease-renewal-interval-in-seconds: 30 # 续约时间
    lease-expiration-duration-in-seconds: 90 # 服务失效时间
2.3.3.2 FileDfsUtil.java

文件上传的工具类,其实FastDFS的依赖中已经有相当健全的上传方法,我们只要直接调用即可,这里的工具类是做一些参数处理

package com.kaikeba.util;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * 调用fastdfs-client工具方法实现文件上传和删除
 */
@Component
public class FileDfsUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(FileDfsUtil.class);

    @Resource
    private FastFileStorageClient storageClient;

    /**
     * 上传文件
     */
    public String upload(MultipartFile multipartFile) throws IOException {
        // 截取文件扩展名
        String originalFilename = multipartFile.getOriginalFilename().substring(multipartFile
                .getOriginalFilename().lastIndexOf(".") + 1);
        // 上传图片并创建缩略版
        StorePath storePath = storageClient.uploadImageAndCrtThumbImage(multipartFile.getInputStream(), multipartFile.getSize(),
                originalFilename, null);

        return storePath.getFullPath();
    }

    /**
     * 删除文件
     * @param url
     */
    public void  deleteFile(String url) {
        if(StringUtils.isEmpty(url)) {
            LOGGER.info("url ===> 文件路径不能为空");
            return;
        }

       try {
           StorePath storePath = StorePath.parseFromUrl(url);
           storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
       } catch (Exception e) {
           LOGGER.error(e.getMessage());
       }
    }

}

2.3.3.3 FastDFSConfigure.java配置类

配置类中我们只要引入 FdfsClientConfig.class 即可完成配置;

package com.kaikeba.configure;

import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * FastDFS 配置类
 */
@Configuration
@Import(FdfsClientConfig.class)
public class FastDFSConfigure {

}

2.3.3.4 FileController.java

文件的操作Controller

package com.kaikeba.controller;

import com.kaikeba.util.FileDfsUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * 文件上传
 */
@RestController
@RequestMapping("/fu")
public class FileController {
    @Resource
    private FileDfsUtil fileDfsUtil;

    @RequestMapping(value = "/upload", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile multipartFile) {
        try {
            String upload = fileDfsUtil.upload(multipartFile);
            if(StringUtils.isEmpty(upload)) {
                return ResponseEntity.ok("上传失败");
            }
            return ResponseEntity.ok(upload);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.ok("服务异常");
        }
    }

    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    public ResponseEntity<String> deleteFile(String path) {
        fileDfsUtil.deleteFile(path);
        return ResponseEntity.ok("SUCCESS") ;
    }

}

2.3.4 测试结果

我们通过postman进行测试
在这里插入图片描述
结果
在这里插入图片描述
浏览器访问:
在这里插入图片描述
storage 容器:
在这里插入图片描述

2.3.5 自己总结

  • FastDFS是为了解决分布式的文件上传的问题,产生的一个分布式文件系统
  • 他会经过两次nginx的负载均衡和转发,第一次是我们发送请求到调度服务器(Tracker server), 此时会帮我们选择一个文件存储服务器(Storage server);当调度服务器(Tracker server)的请求转发到存储服务器(Storage server)时,会产生二次的负载均衡,选择实际的文件存储的位置;
  • storage server 会根据我们上传的文件信息,计算文件存储的位置,也就是文件在二级目录中的位置在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值