• FastDFS分布式文件系统环境搭建和代码测试


    FastDFS分布式文件系统环境搭建和代码测试

    待配置的机器:

    192.168.44.10 192.168.44.11 192.168.44.12 192.168.44.13

    注意:关闭linux防火墙,或者开放FastDFS所需的一些列端口

    一、安装必要的工具和依赖

    1、工具

    yum install lrzsz wget vim unzip net-tools -y
    

    2、依赖

    yum install gcc perl openssl openssl-devel pcre pcre-devel zlib zlib-devel libevent libevent-devel -y
    

    二、安装FastDFS

    1、安装包下载地址

    码云地址:https://gitee.com/fastdfs100
    下载FastDFS、libfastcommon、fastdfs-nginx-module(可选)、fastdfs-client-java(可选)
    

    使用rz -y 上传文件,使用sz下载文件,这个工具在lrzsz安装,有这个工具后,用拖拽也可以。

    2、安装libfastcommon

    libfastcommon 库是 FastDFS 文件系统运行需要的公共 C 语言函数库

    解压:tar -zxvf fastdfs100-libfastcommon-V1.0.51.tar.gz
    
    如果是zip包使用:unzip fastdfs100-libfastcommon-V1.0.51.zip
    
    进入目录,编译:./make.sh
    
    编译没报错可以安装:./make.sh install
    
    

    3、安装FastDFS

    解压:tar -zxvf fastdfs100-fastdfs-V6.07.tar.gz
    或 unzip fastdfs100-fastdfs-V6.07.zip
    
    进入目录,编译:./make.sh
    
    编译没报错可以安装:./make.sh install
    

    所有编译出来的文件存放在/usr/bin****目录下

    所有配置文件存放在/etc/fdfs****目录下

    通过ls /usr/bin/fdfs* 可以查看所有fastDFS的命令

    三、配置FastDFS

    1、将/etc/fdfs下的配置文件样例全部改名,去掉sample后缀

     mv client.conf.sample client.conf
     mv storage.conf.sample storage.conf
     mv storage_ids.conf.sample storage_ids.conf
     mv tracker.conf.sample tracker.conf
    

    2、将安装目录conf下的http.conf和拷贝到/etc/fdfs下

    cp http.conf /etc/fdfs/
    cp mime.types /etc/fdfs/
    

    3、分组

    group1:192.168.44.10 192.168.44.11
    
    group2: 192.168.44.12 192.168.44.13
    

    tracker server: 192.168.44.10 192.168.44.12

    storage server: 全部机器

    group1和group2的数据在各自的组内自动复制,做冗余备份。

    group1和group2之间数据不重复,只为提高并发和容量。

    4、创建日志目录和数据目录

    mkdir -p /opt/fastdfs/tracker #tracker的日志目录
    mkdir -p /opt/fastdfs/storage #storage的日志目录
    mkdir -p /opt/fastdfs/storage/files #真正存放文件的目录
    

    5、修改tracker.conf

    192.168.44.10

    base_path = /opt/fastdfs/tracker
    store_group = group1
    

    192.168.44.12

    base_path = /opt/fastdfs/tracker
    store_group = group2
    

    store_group参数与store_lookup参数相关

    注意:FastDFS默认是带有负载均衡策略的可以在tracker的2台机器中修改tracker.conf文件
    store_lookup=1

    0 随机存放策略
    1 指定组
    2 选择磁盘空间的优先存放 默认值

    修改后重启服务
    fdfs_trackerd /etc/fdfs/tracker.conf restart

    6、修改storage.conf

    # group1或group2,看分组配置
    group_name = group1 
    base_path = /opt/fastdfs/storage
    store_path0 = /opt/fastdfs/storage/files
    tracker_server = 192.168.44.10:22122
    tracker_server = 192.168.44.12:22122
    

    7、启动tracker server

    192.168.44.10和192.168.44.12

    fdfs_trackerd /etc/fdfs/tracker.conf start
    
    ps -ef | grep fdfs
    
    root       1753      1  0 11:30 ?        00:00:00 fdfs_trackerd /etc/fdfs/tracker.conf
    

    8、启动storage server

    fdfs_storaged /etc/fdfs/storage.conf start
    

    需要通过ps -ef | grep fdfs检查是否启动。

    /opt/fastdfs/storage/files/data 这个目录下是数据存放位置,data目录是FastDFS自动创建,这个目录下有00~FF个目录

    9、查看storage注册情况

    fdfs_monitor /etc/fdfs/storage.conf
    

    10、重启FastDFS

    重启tracker

    fdfs_trackerd /etc/fdfs/tracker.conf restart
    

    重启storage

    fdfs_storaged /etc/fdfs/storage.conf restart
    

    11、关闭FastDFS

    fdfs_trackerd /etc/fdfs/tracker.conf stop
    fdfs_storaged /etc/fdfs/storage.conf stop
    

    不建议在生产环境使用 kill -9 强制关闭,因为可能会导致文件信息不同步问题

    四、环境测试

    使用FastDFS自带的测试工具

    1、修改client.conf配置文件,主要修改两个配置:

    base_path=/opt/fastdfs/client
    tracker_server=192.168.44.10:22122
    

    2、测试

    执行上传命令

    fdfs_test /etc/fdfs/client.conf upload /root/test.txt
    

    删除测试

    fdfs_delete_file /etc/fdfs/client.conf group1/要删除的文件路径
    

    注意:

    没有搭建集群默认只有一个组group1

    后缀名包含-m的为属性文件(meta)

    五、代码测试

    使用Springboot进行代码测试

    https://gitee.com/asker124143222/my-boot.git

    1、依赖

            <dependency>
                <groupId>com.github.tobato</groupId>
                <artifactId>fastdfs-client</artifactId>
                <version>1.27.2</version>
            </dependency>
    
    

    2、service

    property外置前缀upload到application.yml里

    @ConfigurationProperties(prefix = "upload")
    @Data
    public class UploadProperties {
        private String baseUrl;
        private List<String> allowTypes;
    }
    

    UploadService

    package com.home.system.service;
    
    import com.github.tobato.fastdfs.domain.fdfs.FileInfo;
    import com.github.tobato.fastdfs.domain.fdfs.StorePath;
    import com.github.tobato.fastdfs.service.FastFileStorageClient;
    import com.home.system.config.UploadProperties;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.annotation.Resource;
    import javax.imageio.ImageIO;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.image.BufferedImage;
    import java.io.Closeable;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.HashSet;
    
    /**
     * @Author: xu.dm
     * @Date: 2021/6/16 14:44
     * @Version: 1.0
     * @Description: TODO
     **/
    @Slf4j
    @EnableConfigurationProperties(UploadProperties.class)
    @Service
    public class UploadService {
    
        @Resource
        private FastFileStorageClient storageClient;
        @Resource
        private UploadProperties properties;
    
        public String uploadImage(MultipartFile file) {
            // 1、校验文件类型
            String contentType = file.getContentType();
            if (!properties.getAllowTypes().contains(contentType)) {
                throw new RuntimeException("文件类型不支持");
            }
            // 2、校验文件内容
            try {
                BufferedImage image = ImageIO.read(file.getInputStream());
                if (image == null || image.getWidth() == 0 || image.getHeight() == 0) {
                    throw new RuntimeException("上传文件有问题");
                }
            } catch (IOException e) {
                log.error("校验文件内容失败....{}", e);
                throw new RuntimeException("校验文件内容失败" + e.getMessage());
            }
            try {
                // 3、上传到FastDFS
                // 3.1、获取扩展名
                String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
                // 3.2、上传
                StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extension, new HashSet<>());
                System.out.println(storePath.getGroup());
                System.out.println(storePath.getPath());
                System.out.println(storePath);
                // 返回路径
                return properties.getBaseUrl() + storePath.getFullPath();
            } catch (IOException e) {
                log.error("【文件上传】上传文件失败!...." + e);
    
                throw new RuntimeException("【文件上传】上传文件失败!" + e.getMessage());
    
            }
        }
    
        public String uploadFile(MultipartFile file) {
            try {
                // 3、上传到FastDFS
                // 3.1、获取扩展名
                String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
                // 3.2、上传
                StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extension, new HashSet<>());
                System.out.println(storePath.getGroup());
                System.out.println(storePath.getPath());
                System.out.println(storePath);
                // 返回路径
                return properties.getBaseUrl() + storePath.getFullPath();
            } catch (IOException e) {
                log.error("【文件上传】上传文件失败!...." + e);
    
                throw new RuntimeException("【文件上传】上传文件失败!" + e.getMessage());
    
            }
        }
    
        public void downloadFile(HttpServletResponse response, String groupName, String path) {
            FileInfo fileInfo = null;
            try {
                fileInfo = storageClient.queryFileInfo(groupName, path);
            }catch (Exception e){
                throw new RuntimeException("文件不存在");
            }
    
    
    
            if(fileInfo == null) {
                throw new RuntimeException("文件不存在");
            }
    
            InputStream inputStream = storageClient.downloadFile(groupName, path, ins -> ins);
            String filename = path.replace("/", ".");
            response.setContentType("application/octet-stream;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename="+filename);
            try {
                streamCopy(inputStream,response.getOutputStream());
                response.flushBuffer();
            } catch (IOException e) {
                closeQuietly(inputStream);
                e.printStackTrace();
                throw new RuntimeException("下载文件失败!");
            }
        }
    
        public void deleteFile(String groupName, String path) {
            storageClient.deleteFile(groupName, path);
        }
    
        private void streamCopy(InputStream inp, OutputStream out) throws IOException {
            byte[] buff = new byte[4096];
            int count;
            while ((count = inp.read(buff)) != -1) {
                if (count > 0) {
                    out.write(buff, 0, count);
                }
            }
        }
    
        public static void closeQuietly( final Closeable closeable ) {
            // no need to log a NullPointerException here
            if(closeable == null) {
                return;
            }
    
            try {
                closeable.close();
            } catch ( Exception e ) {
                log.error( "Unable to close resource: " + e,
                        e );
            }
        }
    }
    

    3、controller

    package com.home.system.controller;
    
    import com.home.system.service.UploadService;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletResponse;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author: xu.dm
     * @Date: 2021/6/16 14:50
     * @Version: 1.0
     * @Description: TODO
     **/
    @Controller
    public class UploadController {
    
        @Resource
        private UploadService uploadService;
    
    
        @GetMapping("/upload")
        public String upload() {
            return "upload";
        }
    
        @GetMapping("/fileDelete")
        public String fileDelete() {
            return "fileDelete";
        }
    
        @GetMapping("/fileDownload")
        public String fileDownload() {
            return "download";
        }
    
    
        @PostMapping("file/download")
        public void doDownload(HttpServletResponse response, String groupName, String path){
            uploadService.downloadFile(response,  groupName, path);
        }
    
    
        @PostMapping("file/delete")
        @ResponseBody
        public String doDelete(String groupName, String path){
            uploadService.deleteFile(groupName, path);
            return "删除成功";
        }
    
        @RequestMapping("upload/doUpload")
        @ResponseBody
        public Map<String,Object> doUpload(MultipartFile file){
            System.out.println(file.getOriginalFilename());
            Map<String, Object> upload =new HashMap<>();
            String path = this.uploadService.uploadImage(file);
            upload.put("path",path);
            return upload;
        }
    
        @RequestMapping("upload/doFileUpload")
        @ResponseBody
        public Map<String,Object> doFileUpload(MultipartFile file){
            System.out.println(file.getOriginalFilename());
            Map<String, Object> upload =new HashMap<>();
            String path = this.uploadService.uploadFile(file);
            upload.put("path",path);
            return upload;
        }
    }
    

    4、application.yml文件配置

    server:
      port: 8080
      tomcat:
        accept-count: 3
        max-connections: 6
        threads:
          max: 10
        basedir: ./target/
    
    logging:
      file:
        # 一旦日志文件大于设定值,这个日志文件就会被加上日期归档,原文清空重新开始记录日志
        name: ./target/myBoot.log
      logback:
        rollingpolicy:
          max-file-size: 20MB
          max-history: 30
    
    spring:
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
      servlet:
        multipart:
          max-request-size: 500MB
          max-file-size: 500MB
    
    fdfs:
      connect-timeout: 60000
      so-timeout: 120000
      tracker-list:
        - 192.168.44.10:22122
        - 192.168.44.12:22122
    
    
    upload:
      base-url: http://192.168.1.105/ #换成你的ip
      allow-types:
        - image/jpeg
        - image/png
        - image/bmp
    
    
    
  • 相关阅读:
    Sharding-JDBC(三)3.1.0版本实践
    Sharding-JDBC(二)2.0.3版本实践
    Sharding-JDBC(一)简介
    Java并发(六)线程池监控
    Java并发(五)线程池使用番外-分析RejectedExecutionException异常
    Java并发(四)线程池使用
    Java并发(三)线程池原理
    Java并发(二)异步转同步
    tarjan+概率
    线段树(种树)
  • 原文地址:https://www.cnblogs.com/asker009/p/14893923.html
Copyright © 2020-2023  润新知