分布式文件系统:FastDFS

网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容
如果右边没有就找找左边
分布式文件系统分类
  1. 通用分布式文件系统

和传统的本地文件系统(ext3,NTFS等)相对应。典型代表Iustre、MooseFS

  1. 优点:表中文件系统操作方式,对开发者门槛较低
  2. 缺点:系统复杂性较高,需要支持若干标准的文件操作,如:目录结构、文件读写权限、文件锁等。复杂性更高,系统整体性能有所降低,因为要支持POSIX标准(表示可移植操作系统接口,POSIX标准定义了操作系统应该为应用程序提供的接口标准)
  1. 专用分布式文件系统

基于google File System的思想,文件上传后不能修改。需要使用专有API对文件进行访问,也可称作分布式文件存储服务。典型代表:MogileFS、FastDFS、TFS。

  1. 优点:系统复杂性较低,不需要支持若干标准的文件操作,如:目录结构、文件读写权限、文件锁等,系统比较简洁。系统整体性能较高,因为无需支持POSIX标准,可以省去支持POSIX引入的环节,系统更加高效
  2. 缺点:采用专用API,对开发者门槛较高(直接封装成工具类)
Google FS 体系结构
  1. 两个角色
  1. 名字服务器(索引服务器)
  2. 存储服务器
  1. 架构特点
  1. 不支持文件修改功能
  2. 文件分块存储,需要索引服务器
  3. 一个文件可以存储多份,一个文件存储到哪些存储服务器,通常采用动态分配的方式
FastDFS简介
  1. FastDFS是一个轻量级的开源分布式文件系统。2008年4月份开始启动。类似google FS的一个轻量级分布式文件系统,存C语言实现,支持Linux、FreeBSD、AIX等UNIX系统
  2. 主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。实现了软件方式的磁盘阵列(RAID),可以使用廉价IDE硬盘进行存储。并且支持存储服务器在线扩容。支持相同内容的文件只保存一份,节约磁盘空间。
  3. FastDFS只能通过ClientAPI访问,不支持POSIX访问方式。
  4. FastDFS特别适合大中型网站使用,用来存储资源文件(如:图片、文档、音频、视频等等)
FastDFS文档和下载地址
  1. FastDFS没有官网,但是作者happy_fish100余庆担任chinaunix中FastDFS板块版主。并且会不定期更新板块中内容。http://bbs.chinaunix.net
    在这里插入图片描述
  2. FastDFS软件可以在sourceforge中下载https://sourceforge.net/projects/fastdfs/files/(不推荐使用这种下载方式,具体下载请看下面环境搭建内容)
    在这里插入图片描述在这里插入图片描述
FastDFS架构

在这里插入图片描述

  1. Client:客户端。使用java语言编写的项目属于客户端
  2. Tracker Server:跟踪服务器,主要做调度工作,在访问上起均衡负载的作用。在内存中记录集群中group和storage server的状态信息,是连接Client和Storage server的枢纽
  3. Storage Server:存储服务器,文件和文件属性(meta data)都保存到存储服务器上,按组group存储,就是上图白色的框框,有若干组,不同组之间不会互相通信
  1. 架构解读
  1. 只有两个角色,tracker server和storage server,不需要存储文件索引信息。
  2. 所有服务器都是对等的,不存在Master-Slave关系。
  3. 不同组中storage server之间不会相信通信。
  4. 由storage server主动向tracker server报告状态,tracker server之间不会互相通信。

一、环境搭建

先下载好相关资源
  1. libfastcommon 下载地址: https://github.com/happyfish100/libfastcommon/releases
  1. libfastcommon是FastDFS官方提供的,libfastcommon包含了FastDFS运行所需要的一些c语言基础库
    在这里插入图片描述
  1. FastDFS 下载地址 https://github.com/happyfish100/fastdfs/releases

注意:请大家下载6.4以上版本,推荐6.4,因为和nginx做整合时,低版本会发生冲突问题
在这里插入图片描述

开始搭建环境
  1. 打开Linux,安装c语言环境,不会Linux请参考文章https://blog.csdn.net/grd_java/article/details/115676099

FastDFS 是C语言开发的应用。安装必须使用make,cmake和gcc编译器
在这里插入图片描述

//安装
yum install -y make cmake gcc gcc-c++
yum -y install libevent
  1. 安装libfastcommon
  1. 将两个包传过去
    在这里插入图片描述
  2. 解压
    在这里插入图片描述
 tar -zxvf libfastcommon-1.0.49.tar.gz -C /opt/module/
  1. 编译
    在这里插入图片描述
  2. 执行安装(有固定的默认安装位置。在/usr/lib64和/usr/include/fastcommon两个目录中)
    在这里插入图片描述
  3. 创建软连接(因为FastDFS主程序设置的lib目录是/usr/local/lib所以需要创建软连接,就是快捷方式)
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/local/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
  1. 解压FastDFS
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  1. 文件解析
    在这里插入图片描述
  1. 配置tracker
  1. 复制配置文件(进入/etc/fdfs中,把tracker配置文件复制一份)
    在这里插入图片描述
cp tracker.conf.sample tracker.conf
  1. 创建数据目录(创建放置tracker数据的目录)
    在这里插入图片描述
mkdir -p /usr/local/fastdfs/tracker
  1. 修改配置文件(修改tracker.conf设置tracker内容存储目录)
    在这里插入图片描述
    在这里插入图片描述
  2. 启动服务(启动成功后,配置文件中指定的目录出现data目录和logs目录)
    在这里插入图片描述
service fdfs_trackerd start
  1. 查看服务运行状态
    在这里插入图片描述
service fdfs_trackerd status
  1. 配置storage(可以和tracker不在同一台服务器)
  1. 复制配置文件(进入/etc/fdfs,把storage配置文件复制一份)
[root@hadoop105 tracker]# cd /etc/fdfs/
[root@hadoop105 fdfs]# cp storage.conf.sample storage.conf
  1. 创建目录(创建两个,base用于存储基础数据和日志,store用于存储上传数据)
[root@hadoop105 fdfs]# mkdir -p /user/local/fastdfs/storage/base
[root@hadoop105 fdfs]# mkdir -p /user/local/fastdfs/storage/store
  1. 修改配置文件(storage.conf配置文件用于描述存储服务的行为,需要进行如下修改)
[root@hadoop105 fdfs]# vim /etc/fdfs/storage.conf
# 基础路径,用于保存storage server基础数据内容和日志内容的目录
base_path=/user/local/fastdfs/storage/base
#存储路径,用于保存FastDFS中存储文件的目录,就是要创建256*256个子目录位
store_path0=/user/local/fastdfs/storage/store
# tracker服务的ip和端口,注意ip写你自己虚拟机或服务器ip,22122是tracker的默认端口,可以在上面tracker.conf文件中配置
tracker_server=192.168.10.105:22122
  1. 启动(成功后,指定目录出现data和logs,path0指定目录,只出现data,第一次启动需要创建256*256子目录,会比较慢)
[root@hadoop105 fdfs]# service fdfs_storaged start
[root@hadoop105 fdfs]# service fdfs_storaged status

二、文件上传

流程说明
  1. 客户端访问Tracker
  2. Tracker返回Storage的ip和端口
  3. 客户端直接访问Storage,把文件内容和元数据发送过去
  4. Storage返回文件存储id,包含了组名和文件名
    在这里插入图片描述
  1. 创建maven项目添加依赖
    在这里插入图片描述
<dependencies>
    <!--这个依赖,作者没有写,所以很多人提供了很多版本,内容都一样,如果这个失效,请去maven仓库换一个fastdfs-client-java-->
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>
</dependencies>
  1. 编写配置文件
    在这里插入图片描述
connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8080
tracker_server = 192.168.10.105:22122
  1. 工具类
    在这里插入图片描述
import org.apache.commons.lang3.StringUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import java.io.*;

/**
 * FastDFS 分布式文件系统操作客户端
 */
public class FastDFSClient {
    private static final String CONF_FILENAME=Thread.currentThread().getContextClassLoader().getResource("").getPath()+"fdfs_client.conf";

    private static StorageClient storageClient = null;
    /**
     * 只加载一次
     */
    static{
        try {
        	//加载配置文件配置信息
            ClientGlobal.init(CONF_FILENAME);
            //创建trackerClient 
            TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
            //创建trackerServer 
            TrackerServer trackerServer = trackerClient.getConnection();
            //获取storageServer 
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            //获取storageClient 
            storageClient = new StorageClient(trackerServer,storageServer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static String[] uploadFile(InputStream inputStream,String fileName){

        try {
            //文件的元数据
            NameValuePair[] meta_list = new NameValuePair[2];
            //第一组元数据,文件的原始名称
            meta_list[0] = new NameValuePair("file name",fileName);
            //第二组元数据
            meta_list[1] = new NameValuePair("file length",inputStream.available()+"");
            //准备字节数组
            byte[] file_buff = null;
            if (inputStream != null){
                //查看文件长度
                int len = inputStream.available();
                //创建对应长度的字节数组
                file_buff = new byte[len];
                //将输入流中的字节内容,读到字节数组中
                inputStream.read(file_buff);
            }
            //上传文件。参数含义:要上传的文件内容(使用字节数组传递),上传的文件的类型(扩展名),元数据
            String[] fileids = storageClient.upload_appender_file(file_buff,getFileExt(fileName),meta_list);
            return fileids;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String[] uploadFile(File file,String fileName){
        FileInputStream fis = null;
        try {
            NameValuePair[] meta_list = null;
            fis = new FileInputStream(file);
            byte[] file_buff = null;
            if(fis != null){
                int len = fis.available();
                file_buff = new byte[len];
                fis.read(file_buff);
            }
            String[] fileids = storageClient.upload_file(file_buff,getFileExt(fileName),meta_list);
            return fileids;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally {
            if(fis != null){
                try{
                    fis.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 根据组名和远程文件名来删除一个文件
     * @param groupName
     * @param remoreFileName
     * @return
     */
    public static int deleteFile(String groupName,String remoreFileName){
        try {
            int result = storageClient.delete_file(groupName == null ? "group1" : groupName, remoreFileName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 修改一个已经存在的文件
     * @param oldGroupName
     * @param oldFileName
     * @param file
     * @param fileName
     * @return
     */
    public static String[] modifyFile(String oldGroupName,String oldFileName,File file,String fileName){
        String[] fileids = null;
        try{
            //先上传
            fileids = uploadFile(file,fileName);
            if(fileids == null){
                return null;
            }
            //再删除
            int delResult = deleteFile(oldGroupName,oldFileName);
            if(delResult != 0){
                return null;
            }
        }catch (Exception e){
            return null;
        }
        return fileids;

    }

    /**
     * 文件下载
     * @param groupName
     * @param remoteFileName
     * @return
     */
    public static InputStream downloadFile(String groupName,String remoteFileName){
        try{
            byte[] bytes = storageClient.download_file(groupName, remoteFileName);
            InputStream inputStream = new ByteArrayInputStream(bytes);
            return inputStream;
        }catch (Exception e) {
            return null;
        }
    }

    public static NameValuePair[] getMetaDate(String groupName,String remoteFileName){
        try{
            NameValuePair[] nvp = storageClient.get_metadata(groupName, remoteFileName);
            return nvp;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 获取文件后缀名,不带点
     */
    private static String getFileExt(String fileName){
        if(StringUtils.isBlank(fileName)||!fileName.contains(".")){
            return "";
        }else{
            return fileName.substring(fileName.lastIndexOf(".")+1);//不带最后的点
        }
    }
}
  1. 编写客户端代码,上传一张图片测试(上传后的文件名,是FastDFS自动生成,和我们代码设置的文件名没啥关系)
    在这里插入图片描述
import com.yzpnb.utils.FastDFSClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.UUID;
public class MyClient {
    public static void main(String[] args) {
        try{
            File file = new File("D:/a.jpg");
            InputStream inputStream = new FileInputStream(file);
            String fileName = UUID.randomUUID().toString()+ ".jpg";

            String[] result = FastDFSClient.uploadFile(inputStream, fileName);

            System.out.println(Arrays.toString(result));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

三、下载

  1. 编写代码并运行
    在这里插入图片描述在这里插入图片描述
import com.yzpnb.utils.FastDFSClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.UUID;
public class MyClient {
    public static void main(String[] args) {
        try{
            //[group1, M00/00/00/wKgKaWENAOWEMeDCAAAAAOFj66Y127.jpg]下载这张图片
            InputStream is = FastDFSClient.downloadFile("group1", "M00/00/00/wKgKaWENAOWEMeDCAAAAAOFj66Y127.jpg");
            FileOutputStream os = new FileOutputStream(new File("D:/b.jpg"));
            int index = 0;
            while((index = is.read())!=-1){
                os.write(index);
            }
            os.flush();
            os.close();
            is.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

四、图片访问

问题
  1. FastDFS没有提供图片访问功能
  2. 所以我们需要使用代理来实现
  3. nginx提供的代理功能可以实现图片访问,但只支持http请求代理(只要支持http协议访问的内容,nginx都可以代理),当接受到外部http请求,返回本地文件资源给客户端
  4. 我们需要借助nginx来实现,外部请求图片,把图片信息响应给请求方
  1. 上传到虚拟机并安装:
  1. fastdfs-nginx-module模块 :https://github.com/happyfish100/fastdfs-nginx-module
    在这里插入图片描述
  2. nginx: http://nginx.org/en/download.html
    在这里插入图片描述
  3. 上传两个文件,解压
    在这里插入图片描述
    在这里插入图片描述
  1. 修改fastdfs-nginx-module配置文件,在文件中src目录下的config文件,因为配置文件中指定的是fastDFS核心代码位置,我们需要指定
    在这里插入图片描述在这里插入图片描述
/usr/include/fastdfs /usr/include/fastcommon/
  1. 安装nginx
  1. 安装一些c++之类的运行库
    在这里插入图片描述
 yum install -y gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl openssl-devel
  1. 修改配置文件之前,创建一个目录(修改配置文件中好多位置都使用了/var/temp/nginx目录,我们需要手动创建这个目录)
    在这里插入图片描述
  2. 给nginx加权限
    在这里插入图片描述
  3. 进入nginx目录,添加配置(你需要修改最后一行,指定路径到你安装fastdfs-nginx-module的src路径)
    在这里插入图片描述
./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/local/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/temp/nginx/client \
--http-proxy-temp-path=/var/temp/nginx/proxy \
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
--http-scgi-temp-path=/var/temp/nginx/scgi \
--add-module=/opt/module/fastdfs-nginx-module-master/src
  1. 编译并安装(在nginx目录下,执行make命令编译安装,make install运行)
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
  1. 复制fastdfs-nginx-module/src/mod-fastdfs.conf配置文件到/etc/fdfs目录,并修改它
    在这里插入图片描述
cp /opt/module/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/

在这里插入图片描述
在这里插入图片描述

connect_timeout=10 # 连接超时时间,单位秒
tracker_server=192.168.10.105:22122# tracker服务结点
url_have_group_name = true# URL是否包含group名称
store_path0=/user/loacl/fastdfs/storage/store#storage服务结点的存储位置,配置与storage结点一致
  1. 提供FastDFS需要的HTTP配置文件(复制FastDFS安装包中两个配置文件http.conf和mine.types到/etc/fdfs目录中)
    在这里插入图片描述
  1. 创建网络访问存储服务的软连接(在上传文件到FastDFS后,FastDFS会返回group1/M00/00/00/xxxxx/xx其中group1是卷名,在mod_fastdfs.conf配置文件中已配置了url_have_group_name,以保证URL解析正确。其中的M00是FastDFS保存数据时使用的虚拟目录,需要将这个虚拟目录定位到真实数据目录上)
    在这里插入图片描述
ln -s /user/local/fastdfs/storage/store/data/ /user/local/fastdfs/storage/store/data/M00
  1. 修改nginx配置文件
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  1. 启动nginx
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

到此,已经可以通过http请求获取资源了

在这里插入图片描述

使用vue工程测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值