FastDFS

概念理解、搭建过程、代码示例、流程示意图

简单介绍

1.FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)三个部分组成,主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。
2.主要有Tracker(管理) 和Storage (储存)。
3.返回路径= 组名 /虚拟盘符{M00/00/02} /文件名。
4.为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。
在这里插入图片描述

Linux搭建FastDFS文件服务器

内容较为繁琐
注意:所有软件的安装主机都是192.168.0.146,我只安装了一台虚拟机

1.软件包

新建目录 并进入

mkdir -p /root/fastdfs
cd    /root/fastdfs

下载安装包

wget  https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz
wget  http://jaist.dl.sourceforge.net/project/fastdfs/FastDFS%20Nginx%20Module%20Source%20Code/fastdfs-nginx-module_v1.16.tar.gz
wget  https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
wget  http://nginx.org/download/nginx-1.16.1.tar.gz

2.安装gcc

检查系统是否有安装GCC

gcc –v

安装GCC

yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
yum -y install wget httpd-tools vim

3.安装libfastcommon

进入libfastcommon-1.0.7的下载位置

cd    /root/fastdfs

解压libfastcommon-1.0.7

tar -zxvf  V1.0.7.tar.gz

解压libfastcommon-1.0.7后进入 文件夹libfastcommon-1.0.7

cd  /root/fastdfs/libfastcommon-1.0.7

进入解压的libfastcommon-1.0.7目录后编译

./make.sh

此时libfastcommon的安装路径 /root/fastdfs/libfastcommon-1.0.7

安装

./make.sh install 

最后,将/libfastcommon-1.0.7/src下的libfastcommon.so文件到usr/lib下 ,请按照自己的实际文件路径修改被复制路径

cp  /root/fastdfs/libfastcommon-1.0.7/src/libfastcommon.so    /usr/lib

4.安装FastDFS

进入FastDFS_v5.05.tar.gz的下载位置

cd    /root/fastdfs

解压FastDFS_v5.05.tar.gz

tar -zxvf V5.05.tar.gz

进入解压后的文件fastdfs-5.05

cd fastdfs-5.05/

编译

./make.sh

安装

./make.sh install 

此时fastdfs-5.05的安装路径 /root/fastdfs/fastdfs-5.05

安装成功后将目录conf内的文件拷贝到/etc/fdfs目录下:(注意/root/fastdfs/fastdfs-5.05 是我的安装路径,你要写自己的)

cp  /root/fastdfs/fastdfs-5.05/conf/*   /etc/fdfs/

5.安装tracker

进入/etc/fdfs目录,修改tracker.conf文件。如果不存在,就拷贝tracker.conf.sample文件为tracker.conf,然后再修改:

base_path=/home/yuqing/fastdfs >>> base_path=/home/logs/fastdfs (注解:日志文件)
http.server_port=8080 >>> http.server_port=80 (注解:端口,80是方便默认)
store_group=group1 (注解:组名)

其中,/home/logs/fastdfs目录如果不存在,就创建一个。

之后,就启动tracker,并查看是启动成功(出现如下提示,表示启动成功):restart重启

fdfs_trackerd /etc/fdfs/tracker.conf start

查看是否启动成功

netstat -unltp | grep tracker

在这里插入图片描述

6.安装storage

由于storage和tracker运行的都是fastDFS程序,每一台服务器都部署一台fasfDFS,一台服务器是tracker,一台是storage
修改storage.conf文件。如果不存在,就拷贝storage.conf.sample文件为storage.conf,然后再修改:

base_path=/home/yuqing/fastdfs >>> base_path=/home/logs/storage (日志路径)

store_path0=/home/yuqing/fastdfs >>> store_path0=/home/data/storage  (实际储存文件路径,可以配置多个)

tracker_server=192.168.209.121:22122 >>> tracker_server=192.168.0.146:22122 (连接tracker服务器地址)

group_name=group1 (必须和tracker的组名相同)

http.server_port=80 (这个端口也要改)

其中,如果/home/logs/storage和/home/data/storage不存在,就创建该目录

然后,就启动storage,并查看是否成功(出现如下提示,表示启动成功):

fdfs_storaged /etc/fdfs/storage.conf start

查看是否启动成功

netstat -unltp | grep storage

在这里插入图片描述
最后,查看tracker和storage是不是在通信:

fdfs_monitor /etc/fdfs/storage.conf

如下提示,出现ACTIVE,表示二者均正常启动,至此就可以进行上传文件测试了。
在这里插入图片描述

7.测试文件上传

Tracker和storage都已经安装完成,使用命令测试文件上传:
FastDFS提供一个文件上传命令:usr/bin/fdfs_test 测试文件上传。测试上传需要连接tracker服务器,连接storage服务器。因此需要指定一个配置文件:client.conf配置文件,通过Client.conf连接tracker服务器。
修改/etc/fdfs下client.conf

base_path=/home/logs/client (日志目录)

tracker_server=192.168.0.146:22122  (tracker端口)

测试开始

新建目录

mkdir  -p  /home/logs/client

进入临时文件夹

cd  /tmp

新建cs.txt文件 (类型不重要,不一定是图片)

echo ceshi>cs.txt

测试(测试一次就可以)

/usr/bin/fdfs_test   /etc/fdfs/client.conf   upload  cs.txt 

在这里插入图片描述
出现example file url: http://192.168.0.146/group1/M00/00/00/wKgAkl-H7suAUW2wAAAABmkPdf0609.txt 等字样表示成功

测试成功可以安装nginx

8.安装Nginx

安装Nginx所需的其他环境,gcc在上面装过了。本人安装没走这一步

#gcc安装 
yum install gcc-c++

#PCRE pcre-devel 安装
yum install -y pcre pcre-devel

#zlib 安装
yum install -y zlib zlib-devel

#OpenSSL 安装
yum install -y openssl openssl-devel

安装Nginx

解压

tar -zxvf nginx-1.16.1.tar.gz

进入解压目录

cd nginx-1.16.1/

配置

./configure

编译

make

安装

make install

9.安装fastdfs-nginx-module

首先解压fastdfs-nginx-module_v1.16.tar.gz,修改/fastdfs-nginx-module/src/config文件。去掉所有的local(三个)
拷贝usr/lib64目录下库文件libfdfsclient.so

cp  /usr/lib64/libfdfsclient.so   /usr/lib 

在nginx安装目录下执行如下命令:把module添加nginx中。通过设置安装参数方式添加模块。

cd  /root/fastdfs/nginx-1.16.1
./configure --add-module = ../fastdfs-nginx-module/src

重新安装编译

make && make install

查看Nginx的模块

/usr/local/nginx/sbin/nginx -V

复制 fastdfs-nginx-module 源码中的配置文件到/etc/fdfs 目录, 并修改

cd  fastdfs-nginx-module/src
cp  mod_fastdfs.conf  /etc/fdfs/

进入/etc/fdfs/修改mod_fastdfs.conf如下配置,其他默认

#连接超时时间
connect_timeout=10

#Tracker Server
tracker_server=192.168.0.146:22122

#StorageServer 默认端口
storage_server_port=23000

#如果文件ID的uri中包含/group**,则要设置为true
url_have_group_name = true

#Storage 配置的store_path0路径,必须和storage.conf中的一致
store_path0=/home/data/storage

#the base path to store log files
base_path=/home/logs/storage

配置iNginx ,进入/usr/local/nginx/conf目录下修改nginx.conf
注意:无论你在哪解压安装的。必须进这个目录/usr/local/nginx/conf下修改nginx.conf
vi nginx.conf
修改配置,其它的默认
在80端口下添加fastdfs-nginx模块

location ~/group([0-9])/M00 {
ngx_fastdfs_module;
}
注意下面#user nobody;改成 #user root;

#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       80;
        server_name  192.168.2.231;
        location ~/group([0-9])/M00 {
            ngx_fastdfs_module;
        }
        #charset koi8-r;

        #access_log  logs/host.access.log  main;

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

        #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;
    #    }
    #}

}

注意:
  listen 80 端口值是要与 /etc/fdfs/storage.conf 中的 http.server_port=80 (前面改成80了)相对应。如果改成其它端口,则需要统一,同时在防火墙中打开该端口。

location 的配置,如果有多个group则配置location ~/group([0-9])/M00 ,没有则不用配group。

在文件存储目录下创建软连接,将其链接到实际存放数据的目录,注意这个文件存储的位置后面多个data目录是系统自动生成的

ln -s /home/data/storage/data /home/data/storage/data/M00

启动nginx ()

直接启动

/usr/local/nginx/sbin/nginx

设置开机启动

vim  /etc/rc.local/usr/local/nginx/sbin/nginx

设置执行权限

chmod 755 rc.local

查看Nginx是否启动

ps -ef | grep nginx

OK记得云服务的安全组 和防火墙设置需要方通 80、22122、 23000

查看防火墙状态
firewall-cmd --state
如果没开启的话开启防火墙

systemctl start firewalld 
#nginx
firewall-cmd --permanent --zone=public --add-port=80/tcp         
# tracker
firewall-cmd --permanent --zone=public --add-port=22122/tcp     
#storage
firewall-cmd --permanent --zone=public --add-port=23000/tcp   
#未来的java程序
firewall-cmd --permanent --zone=public --add-port=9000/tcp    

已经搭建完成
在浏览器地址栏输入

http://192.168.0.146/group1/M00/00/00/wKgAkl-H7suAUW2wAAAABmkPdf0609.txt

浏览器展示出我们当时新建文件时输入的内容
在这里插入图片描述

后端springboot代码

核心代码在service

1.数据库

在这里插入图片描述

Sql

DROP TABLE IF EXISTS `file`;
CREATE TABLE `file`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `group_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `file_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

2.Pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>com.luhuiguo</groupId>
    <artifactId>fastdfs-spring-boot-starter</artifactId>
    <version>0.2.0</version>
</dependency>

3.application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mysql01?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    username: root
    password: root
  application:
    name: file
  http:
    multipart:
      max-file-size: 10000000
server:
  port: 9000

fdfs:
  # 连接Tracker服务器超时时间
  connect-timeout: 10000
  # storage服务器响应的超时时间
  so-timeout: 3000
  #  trakcer服务器的数量
  tracker-list:
    - 192.168.0.146:22122
mybatis:
  configuration:
    map-underscore-to-camel-case: true
  type-aliases-package: com.wx.fastdfs.model
  mapper-locations: classpath:mapper/*.xml

4.Model

File

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class File implements Serializable {
    private Integer id;
    private String fileName;
    private String groupName;
    private String filePath;
}

5.mapper

FileMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        
<mapper namespace="com.wx.fastdfs.dao.FileDao">
<insert id="addFile" parameterType="com.wx.fastdfs.model.File"   useGeneratedKeys="true" keyProperty="id">
  insert into file(file_name,group_name,file_path)
  values (#{fileName},#{groupName},#{filePath})
</insert>

<select id="getFileById" resultType="com.wx.fastdfs.model.File" parameterType="java.lang.Integer">
    select * from file where id =#{id}
</select>
</mapper>

6.dao

FileDao

import com.wx.fastdfs.model.File;

public interface FileDao {
    Integer addFile(File build);

    File getFileById(Integer id);
}

7.controller

FileController

import com.wx.fastdfs.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@RequestMapping("/file")
public class FileController {
    @Autowired
    FileService fileService;
    //上传文件返回id
    @PostMapping("/myUpload")
    public Integer upload(MultipartFile myFile) throws IOException {
         return fileService.upload(myFile);
    }
    //根据图片id(mysql中的id)
    @GetMapping("/fdownload/{id}")
    public void download(@PathVariable Integer id, HttpServletResponse response) throws IOException {
        fileService.download(id,response);
    }
}

8.service

FileService

import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface FileService {
    Integer upload(MultipartFile myFile) throws IOException;

    void download(Integer id, HttpServletResponse response) throws IOException;
}

9.Impl

FileServiceImpl

import com.luhuiguo.fastdfs.domain.StorePath;
import com.luhuiguo.fastdfs.service.FastFileStorageClient;
import com.wx.fastdfs.dao.FileDao;
import com.wx.fastdfs.model.File;
import com.wx.fastdfs.service.FileService;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

@Service
public class FileServiceImpl implements FileService {
    @Autowired
    private FileDao fileDao;

    @Autowired
    private FastFileStorageClient storageClient;

    @Override
    public Integer upload(MultipartFile myFile) throws IOException {
        //1.获取扩展名
        String extension = FilenameUtils.getExtension(myFile.getOriginalFilename());
        //2.上传文件(上传到group1)
        StorePath uploadFile = storageClient.uploadFile("group1", myFile.getInputStream(), myFile.getSize(), extension);
        //3.将上传文件的信息保存到mysql中,并返回自增id
        File build = File.builder().fileName(myFile.getOriginalFilename()).filePath(uploadFile.getPath()).groupName(uploadFile.getGroup()).build();
        fileDao.addFile(build);
        return build.getId();
    }

    @Override
    public void download(Integer id, HttpServletResponse response) throws IOException {
        //1.去数据库查询文件信息(文件名、在fastdfs中的位置)
        File file=fileDao.getFileById(id);
        //2.解决中文文件名下载后乱码的问题
        String filename = URLEncoder.encode(file.getFileName(), "utf-8");
        //3.告诉浏览器 下载的文件名
        response.setHeader("Content-Disposition", "attachment; filename=" + filename + "");
        //4.将文件内容从fastdfs的输出到浏览器
        byte[] downloadFile = storageClient.downloadFile(file.getGroupName(), file.getFilePath());
        response.getOutputStream().write(downloadFile);

    }
}

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--
   上传的方式是post
   enctype的格式必须是:multipart/form-data
 -->
<form action="http://localhost:9000/file/myUpload" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="myFile">
    <input type="submit" value="上传">
</form>

<img src="http://localhost:9000/file/fdownload/1" alt="">
<img src="http://localhost:9000/file/fdownload/7" alt="">

<a href="http://localhost:9000/file/fdownload/7">下载</a>

</body>
</html>

上传过程

在这里插入图片描述
参考:
https://www.cnblogs.com/zeussbook/p/10757699.html fastdfs搭建 (1)更换nginx版本1.16.1 (2)有一些文件目录 如/home/data/client需要新建

https://www.cnblogs.com/zeussbook/p/10191051.html 关闭防火墙

https://blog.csdn.net/wufewu/article/details/84801600 代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值