FastDFS 分布式上传文件

11 篇文章 0 订阅

简介

FastDFS 是基于 C 语言开发的,是一个轻量级开源的高性能分布式文件系统。主要功能有:文件存储、文件同步、文件访问(文件上传/下载),解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。FastDFS 特别适合中大型网站以文件为载体的在线服务,适合存储 4KB ~ 500MB 之间的小文件,如照片共享网站、视频共享网站(图片、文档、音频、视频等等)。

术语

在这里插入图片描述

Client
客户端,实现文件上传下载的服务器,就是我们自己的项目所部署在的服务器。通过专有接口,使用 TCP/IP 协议与跟踪服务器或存储服务器进行数据交互。FastDFS 向使用者提供基本文件访问接口,比如 upload、download、append、delete等,以客户端库的方式提供给用户使用。

Tracker Server
跟踪服务器,负责文件访问的调度和负载均衡,负责管理所有的 Storage Server 和 group 组/卷。

Storage Server
存储服务器,负责文件存储,文件同步/备份,提供文件访问接口,文件元数据管理。以 group 为单位,每个 group 内可以有多台 Storage Server,数据互为备份,达到容灾的目的。每个 Storage 在启动以后会主动连接 Tracker,告知自己所属 group 等存储相关信息,并保持周期性心跳。

Group
 组,也可称为 Volume 卷。同组内服务器上的文件是完全相的,同一组内的 Storage Server 之间是对等的,文件上传、删除等操作可以在任意一台 Storage Server 上进行。

Metadata
文件系统中存储的数据分为数据和元数据两部分,数据是指文件中的实际数据,即文件的实际内容;而元数据是用来描述一个文件特征的系统数据,诸如访问权限、文件拥有者以及文件数据块的分布信息等等。如果文件是一张图片,元数据就是图片的宽,高等等。

安装

下载资源

1、github: https://github.com/happyfish100

下载 libfastcommon , fastdfs ,fastdfs-nginx-module、libserverframe 三个项目对应的压缩包

2、通过资源地址:https://sourceforge.net/projects/fastdfs/files/ 下载

3、giteet: https://toscode.gitee.com/fastdfs100/projects

  • libfastcommon :从 fastdfs 项目和 fastdht 项目中提取出来的公共 C 函数库。
  • fastdfs :FastDFS 核心项目。
  • fastdfs-nginx-module :Nginx 整合 FastDFS 时 Nginx 需要添加的模块资源。
  • libserverframe :网络框架库 libserverframe,替换原有的 tracker nio 和 storage nio 两个模块

安装依赖

FastDFS 是基于 C 语言开发的,安装它之前必须先安装它所依赖的环境。

yum install -y make cmake gcc gcc-c++

安装zip、unzip

yum install zip
yum install unzip

libfastcommon-master.zip

#解压 libfastcommon-master 至当前所在目录
unzip libfastcommon-master.zip
# 进入解压后的 libfastcommon-master 目录
cd libfastcommon-master
# 编译并安装
./make.sh && ./make.sh install

libserverframe-master.zip

#解压 libserverframe-maste 至当前所在目录
unzip libserverframe-master.zip
# 进入解压后的 libfastcommon-master 目录
cd libserverframe-master
# 编译并安装
./make.sh && ./make.sh install

fastdfs-master.zip

#解压 fastdfs-master 至当前所在目录
unzip fastdfs-master.zip
# 进入解压后的 fastdfs-master 目录
cd fastdfs-master
# 编译并安装
./make.sh && ./make.sh install

fastdfs 默认安装在以下位置:

  • /usr/bin :可执行文件
  • /etc/fdfs :配置文件
  • /etc/init.d :主程序代码 (如果改文件中没有 fdfs_storaged 和fdfs_trackerd 时,拷贝fastdfs-master中init.d总共的文件)
  • /usr/include/fastdfs :插件组

启动 Tracker

tracker 和 storage 其实都是 fastdfs ,只不过启动时通过不同的配置文件启动,所扮演的角色不同而已。也就是说,安装 tracker 和 storage 就是在安装 fastdfs ,然后通过每个角色具体的配置文件启动即可。

查看 /etc/fdfs 目录下所有配置文件。

client.conf  http.conf  mime.types  storage.conf  storage_ids.conf  tracker.conf

client.conf.sample :客户端的配置文件,测试用
storage.conf.sample :存储器的配置文件
tracker.conf.sample :跟踪器的配置文件

编辑 tracker.conf 配置文件

#允许访问 tracker 服务器的 IP 地址,为空则表示不受限制
bind_addr =
#tracker 服务监听端口
port = 22122
#tracker 服务器的运行数据和日志的存储父路径(需要提前创建好)
base_path = /fastdfs/tracker
#tracker 服务器 HTTP 协议下暴露的端口
http.server_port = 8080

启动 tracker 服务

#创建 tracker 服务器的运行数据和日志的存储父路径
mkdir -p /fastdfs/tracker
#启动 tracker 服务
service fdfs_trackerd start 
#查看 tracker 服务状态
service fdfs_trackerd status
#重启 tracker 服务
service fdfs_trackerd restart
#停止 tracker 服务
service fdfs_trackerd stop

启动 Storage

编辑 storage.conf 配置文件

#storage 组名/卷名,默认为 group1
group_name = group1
#允许访问 storage 服务器的 IP 地址,为空则表示不受限制
bind_addr =
#storage 服务器的运行数据和日志的存储父路径(需要提前创建好)
base_path = /fastdfs/storage/base
#storage 服务器中客户端上传的文件的存储父路径(需要提前创建好)
store_path0 = /fastdfs/storage/store
#storage 服务器 HTTP 协议下暴露的端口
http.server_port = 8888
#tracker 服务器的 IP 和端口
tracker_server = 192.168.10.101:22122

启动 storage 服务

#创建 storage 服务器的运行数据和日志的存储父路径
mkdir -p /fastdfs/storage/base
#创建 storage 服务器中客户端上传的文件的存储父路径
mkdir -p /fastdfs/storage/store
#启动 storage 服务
service fdfs_storaged start
#查看 storage 服务状态
service fdfs_storaged status
#重启 storage 服务
service fdfs_storaged restart
#停止 storage 服务
service fdfs_storaged stop

Client 操作

FastDFS 向使用者提供基本文件访问接口,比如 upload、download、append、delete 等,以客
户端库的方式提供给用户使用。

编辑 client.conf 配置文件

#client 客户端的运行数据和日志的存储父路径(需要提前创建好)
base_path = /fastdfs/client
#tracker 服务器的 IP(配置虚拟ip eth0) 和端口
tracker_server = 192.168.10.101:22122

记得 mkdir -p /fastdfs/client 创建 Client 目录

注:

开放22122和23000端口

上传

1、进入/usr/bin目录

2、执行上传命令

./fdfs_upload_file /etc/fdfs/client.conf /usr/local/tool/FastDFS/libfastcommon-master.zip

3、返回

group1/M00/00/00/MekNfmN9yjSAez-uAAVXdOvFp2k246.zip

注:

​ group1:卷名

M00:虚拟磁盘路径。与 Storage 配置文件中磁盘选项 store_path* 对应。如果配置了store_path0 则是M00 ,如果配置了 store_path1 则是 M01 ,以此类推。比如:store_path0 =

​ 00/00:文件路径

下载

在这里插入图片描述

/usr/bin/fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/MekNfmN9yjSAez-uAAVXdOvFp2k246.zip

删除

/usr/bin/fdfs_delete_file /etc/fdfs/client.conf group1/M00/00/00/MekNfmN9yjSAez-uAAVXdOvFp2k246.zip

Nginx 整合 FastDFS 时 Nginx 需要添加 fastdfs-nginx-module 模块

fastdfs-nginx-module-master.zip

#解压 fastdfs-nginx-module-master 至当前所在目录
unzip fastdfs-nginx-module-master.zip

复制配置文件 mod_fastdfs.conf 到 /etc/fdfs 目录中

cp src/mod_fastdfs.conf /etc/fdfs/

vim /etc/fdfs/mod_fastdfs.conf 编辑配置文件,主要关注以下部分

#tracker 服务器的 IP 和端口
tracker_server = 192.168.10.101:22122
#url 地址是否包含组名/卷名
url_have_group_name = true
#数据组/卷对应的路径地址
store_path0 = /fastdfs/storage/store

复制 fastdfs 安装包中的两个配置文件 http.conf 和 mime.types 到 /etc/fdfs 目录中

cp fastdfs-master/conf/http.conf /etc/fdfs/
cp fastdfs-master/conf/mime.types /etc/fdfs/

配置 Nignx

指定安装模块

--add-module=/usr/local/src/fastdfs-nginx-module-master/src

nginx.conf 编辑配置文件

location ~/group[0-9]/{
	ngx_fastdfs_module;
}

项目使用

下载项目fastdfs-client-java并打成jar

pom

<dependency>
            <groupId>org.csource</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.29-SNAPSHOT</version>
        </dependency>

配置

添加配置文件fdfs_client.conf,增加以下配置

connect_timeout = 2
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
http.anti_steal_token = no
http.secret_key = FastDFS1234567890

tracker_server = 192.168.56.10:22122

http.anti_steal_token:配置防盗链,no表示不开启(详细参考FastDFS防盗链一节)
http.secret_key:防盗链密码
tracker_server:tracker连接信息,有多少tracker就配置几个

工具类

public class FastDfsUtil {

    private static Logger logger = LoggerFactory.getLogger(FastDfsUtil.class);
    // 获取配置文件地址
    private static final String CONF_FILENAME = Thread.currentThread() .getContextClassLoader().getResource("").getPath() + "fdfs_client.conf";
    // Storage 存储服务器客户端
    private static StorageClient storageClient = null;

    static {
        try {
            // 加载配置文件
            ClientGlobal.init(CONF_FILENAME);
            // 初始化 Tracker 客户端
            TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
            // 初始化 Tracker 服务端
             TrackerServer trackerServer = trackerClient.getTrackerServer();
            // 初始化 Storage 服务端
             StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            // 初始化 Storage 客户端
            storageClient = new StorageClient(trackerServer, storageServer);
        }catch (Exception e) {
           logger.error("FastDfs初始化异常",e);
        }
    }

    /**
     * 文件上传
     * @param multipartFile
     * @return
     */
    public  static  String[] uploadFile(MultipartFile multipartFile){
        InputStream inputStream=null;
        try {
            if(!multipartFile.isEmpty()){
                //获取流
                inputStream = multipartFile.getInputStream();
                String fileName=multipartFile.getOriginalFilename();
                // 查看文件的长度
                int len = inputStream.available();
                // 初始化元数据数组
                NameValuePair[] metaList = new NameValuePair[2];
                // 第一组元数据,文件的原始名称
                metaList[0] = new NameValuePair("file_name", fileName);
                // 第二组元数据,文件的长度
                metaList[1] = new NameValuePair("file_length",String.valueOf(len));
                // 创建对应长度的字节数组
                byte[] fileBuff = fileBuff = new byte[len];
                // 将输入流中的字节内容,读到字节数组中
                inputStream.read(fileBuff);
                return  storageClient.upload_file(fileBuff,getFileExt(fileName),metaList);
            }
        }catch (Exception e){
            logger.error("FastDfs上传异常",e);
        }finally {
            if(inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.error("FastDfs上传关闭流异常",e);
                }
            }
        }
        return null;
    }
    /**
     * 获取文件后缀名(不带点)
     *
     * @param fileName
     * @return 如:"jpg" or ""
     */
    private static String getFileExt(String fileName) {
        if (StringUtils.isBlank(fileName) || !fileName.contains(".")) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1); // 不带最后的点
    }

    /**
     * 获取文件详情
     *
     * @param groupName 组/卷名,默认值:group1
     * @param remoteFileName 文件名,例
    如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
     * @return 文件详情
     */
    public static FileInfo getFileInfo(String groupName, String remoteFileName){
        try {
            return storageClient.get_file_info(groupName == null ? "group1" :groupName, remoteFileName);
        } catch (Exception e) {
            logger.error("FastDfs获取文件详情异常",e);
        }
        return null;
    }

    /**
     * 获取元数据
     *
     * @param groupName 组/卷名,默认值:group1
     * @param remoteFileName 文件名,例
    如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
     * @return 文件的元数据数组
     */
    public static NameValuePair[] getMetaData(String groupName, String remoteFileName) {
        try {
            // 根据组名和文件名通过 Storage 客户端获取文件的元数据数组
            return storageClient.get_metadata(groupName == null ? "group1" :groupName, remoteFileName);
        } catch (Exception e) {
            logger.error("FastDfs获取文件的元数据异常",e);
        }
        return null;
    }

    /**
     * 文件下载
     *
     * @param groupName 组/卷名,默认值:group1
     * @param remoteFileName 文件名,例
    如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
     * @return 文件的字节输入流
     */
    public static InputStream downloadFile(String groupName, String remoteFileName) {
        try {
            // 根据组名和文件名通过 Storage 客户端获取文件的字节数组
            byte[] bytes = storageClient.download_file(groupName == null ? "group1" : groupName, remoteFileName);
            // 返回字节流对象
            InputStream inputStream = new ByteArrayInputStream(bytes);
            return inputStream;
        } catch (Exception e) {
            logger.error("FastDfs下载异常",e);
        }
        return null;
    }

    /**
     * 文件删除
     *
     * @param groupName 组/卷名,默认值:group1
     * @param remoteFileName 文件名,例
    如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
     * @return 0为成功,非0为失败
     */
    public static int deleteFile(String groupName, String remoteFileName) {
        int result = -1;
        try {
            // 根据组名和文件名通过 Storage 客户端删除文件
            result = storageClient.delete_file(groupName == null ? "group1" :groupName, remoteFileName);
        } catch (Exception e) {
            logger.error("FastDfs删除异常",e);
        }
        return result;
    }


}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值