分布式文件存储

1 FastDFS介绍

FastDFS 是一个由 C 语言实现的开源轻量级分布式文件系统,作者余庆(happyfish100),支持 Linux、FreeBSD、AID 等 Unix 系统,解决了大数据存储和读写负载均衡等问题,适合存储 4KB~500MB 之间的小文件,如图片网站、短视频网站、文档、app 下载站等,UC、京东、支付宝、迅雷、酷狗等都有使用。

该软件作者是阿里巴巴大牛、chinaUnix版主余庆个人独立开发的。

2 FastDFS上传的流程

分布式存储 docker 分布式存储软件_分布式存储 docker

只要 storage 返回图片的路径图片名称,我们就能通过浏览器来访问图片了

3. 创建fastdfs

我们使用Docker搭建FastDFS的开发环境,虚拟机中已经下载了fastdfs的镜像,可以通过docker images查看,如下图:

拉取镜像(已经下载了该镜像,大家无需下载了)

docker pull morunchang/fastdfs

运行tracker

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

运行storage

docker run -d --name storage --net=host -e TRACKER_IP=192.168.200.128:22122 -e GROUP_NAME=group1 morunchang/fastdfs sh storage.sh
  • 使用的网络模式是–net=host, 此时会将宿主机的网络应用于容器,链接容器就可以直接使用宿主机的IP192.168.200.128
  • sh tracker.sh运行tracker.sh脚本文件
  • group1是组名,即storage的组
  • 如果想要增加新的storage服务器,再次运行该命令,注意更换 新组名

配置Nginx

Nginx在这里主要提供对FastDFS图片访问的支持,Docker容器中已经集成了Nginx,我们需要修改nginx的配置,进入storage的容器内部,修改nginx.conf

docker exec -it storage  /bin/bash

进入后

vi /etc/nginx/conf/nginx.conf

添加以下内容:

上图配置如下:

location ~ /M00 {
     ngx_fastdfs_module;
}

访问图片的时候,浏览器通常都会对图片进行缓存,如果有禁止缓存,可以设置nginx配置添加禁止缓存即可。

禁止缓存:

add_header Cache-Control no-store;

退出容器:

exit

重启storage容器:

docker restart storage

查看启动容器docker ps

9f2391f73d97 morunchang/fastdfs "sh storage.sh" 12 minutes ago Up 12 seconds storage
e22a3c7f95ea morunchang/fastdfs "sh tracker.sh" 13 minutes ago Up 13 minutes tracker

开启启动设置:

docker update --restart=always tracker
docker update --restart=always storage

安装Nginx目的:

nginx集成了FastDFS,可以通过它的ngx_fastdfs_module模块,可以通过该模块访问Tracker获取图片所存储的Storage信息,然后访问Storage信息获取图片信息。

4 利用Java客户端调用FastDFS

1、在项目配置文件加上分布式文件系统的ip

fileServer:
  url: http://192.168.200.128:8080/ # fastDFS 分布式文件系统的 ip:port

2、在项目resource中添加tracker.conf 配置文件

tracker_server=192.168.200.128:22122
# 连接超时时间,针对socket套接字函数connect,默认为30秒
connect_timeout=30000
# 网络通讯超时时间,默认是60秒
network_timeout=60000

2、自己封装工具类

package com.xyxy.gmall.product.util;

import org.csource.common.MyException;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

/**
 * @Author 李燕茹
 * @create 2022/3/19 16:27
 * 文件上传工具类
 */
public class FastDFSUtil {

    static {

        try {
            //加载classpath下的配置文件信息
            ClassPathResource classPathResource = new ClassPathResource("tracker.conf");
            //初始化tracker的信息
            ClientGlobal.init(classPathResource.getPath());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件上传
     * 2022/3/19 16:28
     * @param file
     * @return java.lang.String
     */
    public static String fileUpload(MultipartFile file) throws IOException, MyException {
       //文件上传流程
        //初始化trackerClient
        TrackerClient trackerClient = new TrackerClient();
        //获取连接
        TrackerServer trackerServer = trackerClient.getConnection();
        //通过tracker获取storage的信息
        StorageClient storageClient = new StorageClient(trackerServer, null);
        //通过storage完成文件的上传
        String[] strings = storageClient.upload_file(file.getBytes(),
                StringUtils.getFilenameExtension(file.getOriginalFilename()),
                null);
        return strings[0] + "/" + strings[1];
    }

    /**
     * 文件下载
     * 2022/3/19 16:39
     * @param groupName
     * @param fileName
     * @return byte[]
     */
    public static byte[] fileDownload(String groupName, String fileName) throws IOException, MyException {
        //文件下载流程
        //初始化trackerClient
        TrackerClient trackerClient = new TrackerClient();
        //获取服务的连接信息
        TrackerServer trackerServer = trackerClient.getConnection();
        //通过tracker获取storage的信息
        StorageClient storageClient = new StorageClient(trackerServer,null);
        //通过storage完成文文件下载
        byte[] bytes = storageClient.download_file(groupName, fileName);
        return bytes;
    }

    /**
     * 文件删除
     * 2022/3/19 16:41
     * @param groupName
     * @param fileName
     * @return int
     */
    public static int fileDelete(String groupName, String fileName) throws IOException, MyException {
        //文件下载流程
        //初始化trackerClient
        TrackerClient trackerClient = new TrackerClient();
        //获取服务的连接信息
        TrackerServer trackerServer = trackerClient.getConnection();
        //通过tracker获取storage的信息
        StorageClient storageClient = new StorageClient(trackerServer,null);
        //通过storage完成文文件下载
        int delete = storageClient.delete_file(groupName, fileName);
        return delete;
    }

    public static void main(String[] args) throws IOException, MyException {
        //测试下载文件到本地
        byte[] bytes = fileDownload("group1", "M00/00/02/wKjIgGI2DDiAeZFDAAAi3NczRJ49.4.jpg");
        File file = new File("f:\\abc.jpg");
        if (!file.exists()) {
            file.createNewFile();
        }
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        //写入磁盘
        fileOutputStream.write(bytes);
        fileOutputStream.close();
    }
}

4、控制层

@RestController
@RequestMapping("/admin/product")
public class FileController {

    @Value("${fileServer.url}")
    private String url;//获取服务器ip和端口的URL

    @ApiOperation("文件上传接口")
    @PostMapping("/fileUpload")
    public Result fileUpload(@RequestParam MultipartFile file) throws IOException, MyException {
        String imgUrl = FastDFSUtil.fileUpload(file);
        return Result.ok(url+imgUrl);
    }
}

5、测试

使用postman访问文件上传接口 /admin/product/fileUpload

查看上传文件返回的URL,直接放到浏览器即可访问

6、总结

分布式存储 docker 分布式存储软件_中间件_02

分布式存储 docker 分布式存储软件_中间件_03