FastDFS-单机版搭建
in with 0 comment

FastDFS-单机版搭建

in with 0 comment

转载 来源:CSDN 作者:luqi0000

一、前言

一般而言,当用户量较少的时候,我们就把图片之类的静态资源文件存储到一台装有 Tomcat 的服务器上。但是,随着用户访问量的增大,一个Tomcat服务就不能满足业务需求了,下面提出几种解决方案:

1. 部署Tomcat集群,使用 Nginx作为负载均衡服务器,分散存储到不同的 Tomcat 服务器上;这种做法可以简单的扩大存储,但是需要处理一个问题:分散存储后,需要正确的处理逻辑来访问到正确的Tomcat 分支上。例如:存储的时候,由Nginx 分配到 Tomcat1 上;访问的时候,由Nginx 分配到 Tomcat2 上。

2. 搭建一个唯一的图片服务器,即tomcat本身不保存图片,而将图片上传到图片服务器上;这种方式采用http的方式来访问图片,需要使用http服务器。可以使用Tomcat ,但是Tomcat的强项在于处理动态请求,这里使用Nginx 服务器比较合适。注意:在上述方案一中,我们也使用了 Nginx,但是“负载均衡”只是 Nginx的功能之一。

3. 搭建图片服务器集群,即分布式文件系统;这种方式用于解决进一步的用户量增长问题,是方案二的升级版。分布式系统可以解决图片、音视频、文件共享的问题。目前,流行的分布式文件系统有FastDFS、GFS(谷歌)、HDFS(Hadoop)、TFS(淘宝),我们采用FastDFS 来进行介绍和部署。

二、FastDFS 介绍

FastDFS 是由淘宝的余庆先生开发,是一个轻量级、高性能的开源分布式文件系统,用纯C语言开发,包括文件存储、文件同步、文件访问(上传、下载)、存取负载均衡、在线扩容、相同内容只存储一份等功能,适合有大容量存储需求的应用或系统。

FastDFS 按组区分存储资源,当存储空间不足时,可以通过增加水平分组来达到扩容的目的。

FastDFS 允许少数Nginx发生故障,是一个满足高可用的分布式文件系统。

2.2角色介绍和操作流程

角色介绍:

FastDFS 两个主要的角色:TrackerServer 和 Storage Server;

Tracker Server:跟踪服务器,主要负责调度storage节点与client通信,在访问上起负载均衡的作用,和记录storage节点的运行状态,是连接client和storage节点的枢纽;

Storage Server:存储服务器,保存文件和文件的meta data(元数据);

Group:文件组,也称为卷。做集群时一组会有多台服务器,同组服务器上的文件是完全相同的,当文件上传到组内的一台机器后,该文件会同步到同组内的其它所有机器上,起到备份的作用;

meta data:文件相关属性,键值对(KeyValue Pair)方式,如:width=1024, height=768;  

FastDFS文件上传流程:

    1、client询问tracker上传到的storage,不需要附加参数;

    2、tracker返回一台可用的storage;

    3、client直接和storage通讯完成文件上传。

FastDFS文件下载流程:

    1、client询问tracker下载文件的storage,参数为文件标识(组名和文件名);

    2、tracker返回一台可用的storage;

    3、client直接和storage通讯完成文件下载。

2.3 安装准备

跟踪服务器(TrackerServer)和存储服务器(Storage Server):192.168.232.100

操作系统:CentOS7(最小化安装即可)

安装包:

    fastdfs-master.zip:FastDFS源码

    libfastcommon-master.zip:(从 FastDFS 和 FastDHT 中提取出来的公共 C 函数库)

    fastdfs-nginx-module-master.zip:storage节点http服务nginx模块

    nginx-1.12.1.tar.gz:Nginx安装包

FastDFS相关的安装包可到https://github.com/happyfish100去下载,Nginx需要到官网下载,下载完成后,将压缩包上传到 “/usr/local”目录下。

三、单机版安装

3.1 安装 FastDFS安装包

3.1.1安装所需的依赖包

shell> yum install make cmake gcc gcc-c++ perl zip unzip

3.1.2 安装 libfastcommon

shell> cd /usr/local  
shell> unzip libfastcommon-master.zip  
shell> cd libfastcommon-master
shell> ./make.sh  
shell> ./make.sh install

3.1.3 安装 FastDFS

shell> cd /usr/local  
shell> unzip fastdfs-master.zip  
shell> cd fastdfs-master
shell> ./make.sh  
shell> ./make.sh install

3.1.4 启动服务

shell> /etc/init.d/fdfs_storaged
shell> /etc/init.d/fdfs_trackerd

3.1.5 配置文件和命令工具目录

[root@localhost bin]# ll /etc/fdfs/  
total 84  
-rw-r--r--. 1 root root 1459 Feb 21 18:12 client.conf  
-rw-r--r--. 1 root root 1461 Jan 13 14:50 client.conf.sample  
-rw-r--r--. 1 root root 955 Jan 13 15:17 http.conf  
-rw-r--r--. 1 root root 31172 Jan 13 15:17 mime.types  
-rw-r--r--. 1 root root 3729 Feb 21 18:12 mod_fastdfs.conf  
-rw-r--r--. 1 root root 7919 Feb 21 18:11 storage.conf  
-rw-r--r--. 1 root root 7927 Jan 13 14:50 storage.conf.sample  
-rw-r--r--. 1 root root 105 Jan 13 14:50 >storage_ids.conf.sample  
-rw-r--r--. 1 root root 7385 Jan 13 14:53 tracker.conf  
-rw-r--r--. 1 root root 7389 Jan 13 14:50 tracker.conf.sample

命令行工具(/usr/bin目录)

shell> ll /usr/bin/ | grep fdfs  
-rwxr-xr-x. 1 root root 317560 Jan 13 14:50 fdfs_appender_test  
-rwxr-xr-x. 1 root root 317336 Jan 13 14:50 fdfs_appender_test1  
-rwxr-xr-x. 1 root root 304184 Jan 13 14:50 fdfs_append_file  
-rwxr-xr-x. 1 root root 303920 Jan 13 14:50 fdfs_crc32  
-rwxr-xr-x. 1 root root 304248 Jan 13 14:50 fdfs_delete_file  
-rwxr-xr-x. 1 root root 304976 Jan 13 14:50 fdfs_download_file  
-rwxr-xr-x. 1 root root 304576 Jan 13 14:50 fdfs_file_info  
-rwxr-xr-x. 1 root root 322488 Jan 13 14:50 fdfs_monitor  
-rwxr-xr-x. 1 root root 1111888 Jan 13 14:50 fdfs_storaged  
-rwxr-xr-x. 1 root root 327504 Jan 13 14:50 fdfs_test  
-rwxr-xr-x. 1 root root 326712 Jan 13 14:50 fdfs_test1  
-rwxr-xr-x. 1 root root 454096 Jan 13 14:50 fdfs_trackerd  
-rwxr-xr-x. 1 root root 305168 Jan 13 14:50 fdfs_upload_appender  
-rwxr-xr-x. 1 root root 306200 Jan 13 14:50 fdfs_upload_file

3.2 Tracker服务器配置

3.2.1 复制样例配置文件

shell> cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf

3.2.2 修改配置文件参数

shell> vi /etc/fdfs/tracker.conf

修改的内容如下:

disabled=false # 启用配置文件
port=22122 # tracker服务器端口(默认22122)
base_path=/fastdfs/tracker # 存储日志和数据的根目录
其它参数保留默认配置

3.2.3 创建 base_path 指定的目录

shell> mkdir -p /fastdfs/tracker

3.2.4开启端口(默认为 22122)

使用iptables:

shell> vi /etc/sysconfig/iptables

添加如下端口行:

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT

重启防火墙:

shell> service iptables restart  

使用firewall:

shell> firewall-cmd --add-port=22122/tcp --permanent #添加端口  
shell> firewall-cmd --reload #重新加载  
shell> firewall-cmd --list-port #查看端口

如果firewall想关闭某个端口,可以使用下面的指令

shell> firewall-cmd --remove-port=22122/tcp --permanent

3.2.5 启动 tracker 服务器

shell> /etc/init.d/fdfs_trackerd start #初次启动,会在/fastdfs/tracker目录下生成logs、data两个目录。  
shell> ps -ef|grep fdfs_trackerd #检查FastDFS Tracker Server是否启动成功  

如果想停止 tracker服务器,可以使用下面的指令

shell> /etc/init.d/fdfs_trackerd stop

3.2.6 设置tracker服务开机启动

shell> chkconfig fdfs_trackerd on

3.3 配置storage服务器

3.3.1 复制样例配置文件

shell> cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf

修改的内容如下:

disabled=false # 启用配置文件
port=23000 # storage服务端口
base_path=/fastdfs/storage # 数据和日志文件存储根目录
store_path0=/fastdfs/storage # 第一个存储目录
tracker_server=192.168.232.100:22122 # tracker服务器IP和端口
http.server_port=8888 # http访问文件的端口
其它参数保留默认配置。

3.3.3 创建基础数据目录

shell> mkdir -p /fastdfs/storage

3.3.4开启端口(默认为 23000)

firewall:

shell> firewall-cmd --add-port=23000/tcp --permanent #添加端口  
shell> firewall-cmd --reload #重新加载  
shell> firewall-cmd --list-port #查看端口

3.3.5 启动 storage 服务器

shell> /etc/init.d/fdfs_storaged start  

初次启动,会在/fastdfs/storage目录下生成logs、data两个目录。

检查FastDFSTracker Server是否启动成功:

shell> ps -ef | grep fdfs_storaged  

停止 storage 服务器的命令

shell> /etc/init.d/fdfs_storaged stop

3.3.6 设置 storage 服务开机启动

shell> chkconfig fdfs_storaged on

3.4上传测试

3.4.1复制样例配置文件并编辑文件

shell> cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf  
shell> vi /etc/fdfs/client.conf

修改以下配置,其它保持默认

base_path=/fastdfs/tracker
tracker_server=192.168.232.100:22122

3.4.2 执行文件上传命令

shell> /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /home/w/test.jpg  

返回类似的文件ID号:group1/M00/00/00/wKjodVqNUXeAE452AAE9rfD8DeY539.jpg。

3.5 安装 fastdfs-nginx-module

3.5.1 fastdfs-nginx-module 介绍

上传文件时,同组存储服务器之间需要复制文件,这就会有同步延迟。在文件还没有复制完成的情况下,客户端如果访问同组其他的服务器,就会出现访问错误。fastdfs-nginx-module 可以重定向文件连接到源服务器(上传的服务器)取文件,避免复制延迟导致的访问错误。

3.5.2 解压 fastdfs-nginx-module-master.zip

shell> cd /usr/local  
shell> unzip fastdfs-nginx-module-master.zip

3.5.3 安装Nginx

安装 Nginx 所需的依赖包

shell> yum install gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl openssl-devel

编译安装 Nginx(添加 fastdfs-nginx-module 模块)

shell> cd /usr/local  
shell> tar -zxvf nginx-1.12.1.tar.gz  
shell> unzip fastdfs-nginx-module-master.zip  
shell> cd nginx-1.12.1  
shell> ./configure --prefix=/opt/nginx --sbin-path=/usr/bin/nginx --add-module=/usr/local/fastdfs-nginx-module-master/src  
shell> make && make install

3.5.4 复制并编辑fastdfs-nginx-module配置文件

shell> cp /usr/local/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/  
shell> vi /etc/fdfs/mod_fastdfs.conf

修改以下配置:

connect_timeout=10 # 客户端访问文件连接超时时长(单位:秒)
base_path=/tmp # 临时目录
tracker_server=192.168.232.100:22122 # tracker服务IP和端口
storage_server_port=23000 # storage服务端口
group_name=group1 # 组名
url_have_group_name=true # 访问链接前缀加上组名
store_path0=/fastdfs/storage # 文件存储路径
其它配置保持默认。

3.5.5 复制 FastDFS 配置文件到/etc/fdfs 目录

shell> cd /usr/local/fastdfs-master/conf  
shell> cp http.conf mime.types /etc/fdfs/

3.5.6创建软连接

shell> ln -s /fastdfs/storage/data/ /fastdfs/storage/data/M00

3.5.7 配置nginx访问storage文件

简洁版nginx配置:

vi /opt/nginx/conf/nginx.conf
user nobody;  
worker_processes 1;  
events {  
    worker_connections 1024;  
}  
http {   
    include mime.types;  
    default_type application/octet-stream;  
    sendfile on;  
    keepalive_timeout 65;  
    server {  
    listen 8888;  
    server_name localhost;  
    location ~/group([0-9])/M00 {  
    ngx_fastdfs_module;  
}  
error_page 500 502 503 504 /50x.html;  
location = /50x.html {  
    root html;  
}    

注意1:8888 端口值与/etc/fdfs/storage.conf中的http.server_port=8888 相对应。

注意2:Storage 对应有多个 group 的情况下,访问路径带group 名,如/group1/M00/00/00/xxx,对应的 Nginx 配置为:

 location~/group([0-9])/M00 {

    ngx_fastdfs_module;

}

注意3:若发现频繁报 404,可将nginx.conf 第一行 user nobody; 修改为 user root; 后重新启动。

3.5.8 开启8888 端口

shell> firewall-cmd --add-port=8888/tcp --permanent #添加端口  
shell> firewall-cmd --reload #重新加载  
shell> firewall-cmd --list-port #查看端口

3.5.9 启动Nginx

启动命令如下,会显示类似 "ngx_http_fastdfs_set pid=xxx"的提示信息

shell> /usr/bin/nginx

nginx重启命令如下:

shell> /usr/bin/nginx -s reload

3.5.10访问上传的文件

测试上传后返回的文件ID为:group1/M00/00/00/wKjodVqNUXeAE452AAE9rfD8DeY539.jpg

浏览访问的地址为:http://192.168.232.111:8888/group1/M00/00/00/wKjodVqNUXeAE452AAE9rfD8DeY539.jpg

注意:不要使用 kill命令,否则可能会导致数据丢失。

3.6 使用FastDFS-Client客户端测试上传和下载

3.6.1 打包fastdfs-client 到本地仓库

访问Github官网下载fastdfs-client源码并转化为maven工程,然后打包到本地maven仓库。这里需要在maven项目中加入坐标,如下所示。
 <dependency>
    <groupid>org.csource</groupid>  
    <artifactid>fastdfs-client-java</artifactid>  
    <version>1.27-SNAPSHOT</version>
 </dependency> 

3.6.2 新建配置文件

在工程的resources目录下新建一个resource文件夹,如下图所示。

在文件夹得下面创建client.conf文件,client.conf文件中输入tracker所在的设备的IP及端口,只保留红框中的即可,如下图所示。

注意1:注释加在上方,否则会报错。

注意2:tracker 服务器可以有多个,上图的配置文件配置了集群的情况,使用的时候取消注释即可。

3.6.3 新建测试类

下面新建一个测试类来进行测试,在src/test/java目录下新建一个包com.xxx.fastdfs,在该包下新建一个测试类TestFastDFS.java,如下所示。
package com.xxx.fastdfs;

import org.csource.common.NameValuePair;  
import org.csource.fastdfs.ClientGlobal;  
import org.csource.fastdfs.StorageClient;  
import org.csource.fastdfs.StorageServer;  
import org.csource.fastdfs.TrackerClient;  
import org.csource.fastdfs.TrackerServer;  
import org.junit.Test;  
import com.xxx.utils.FastDFSClient;

public class TestFastDFS {  
    @Test  
    public void testUploadFile() throws Exception{  
    //1.向工程添加jar包  
    //2.创建一个配置文件,配置tracker服务器地址  
    //3.加载配置文件  
    ClientGlobal.init("D:/Work/taotao2/taotao-manager-web/src/main/resources/resource/client.conf");  
    //4.创建一个TrackerClient对象  
    TrackerClient trackerClient = new TrackerClient();  
    //5.使用TrackerClient对象获得trackerserver对象。  
    TrackerServer trackerServer = trackerClient.getConnection();  
    //6.创建一个StorageServer的引用,我们用null就可以  
    StorageServer storageServer = null;  
    //7.创建一个StorageClient对象。trackerserver、StorageServer两个参数  
    StorageClient storageClient = new 
    StorageClient(trackerServer, storageServer);  
    //8.使用StorageClient对象上传文件  
    NameValuePair[] metaList = new NameValuePair[3];  
    metaList[0] = new NameValuePair("fileName", "2");  
    metaList[1] = new NameValuePair("createTime", "2017-04-13 16:01:00");  
    metaList[2] = new NameValuePair("createUser", "zhangsan");  
    String[] upload_files = storageClient.upload_file("D:/test.jpg", "jpg", metaList);  
    for(String file : upload_files){  
        System.out.println(file);  
    }  
    }  
}  

注意1:在工程中添加junit的依赖(版本已在父工程中定义)

<dependency>
    <groupid>junit</groupid>  
    <artifactid>junit</artifactid>
</dependency>   

注意2:NameValuePair是给图片添加附加信息的,包括图片原文件名、大小、作者等等,导包时会发现有多个选项,我们选择"import org.csource.common.NameValuePair"

注意3:如果在复制粘贴系统的本地文件绝对路径(D:/test.jpg)时,Eclipse识别不了,则手动输入。

3.6.4 执行测试方法

控制台会返回两行数据:第一行是组号;第二行是存放的具体位置。        

带有附加信息的图片上传后,会生成一个以"-m"结尾的文件,如下图所示。

3.6.5 通过浏览器访问图片

访问拼接后的地址192.168.232.100:8888/group1/M00/00/00/wKjoZFqNlgCAQ4enAAVOJlr_l7Q570.jpg,端口8888是在Nginx中配置的对外暴露的访问端口。

3.6.6 封装工具类及测试

为了方便使用,下面对类进行封装,内容如下。封装类中使用的Storage客户端是StorageClient1而不是StorageClient,这个客户端能够自动把文件所在的组以及存放位置拼接到一块。
package com.xxx.utils;

import org.csource.common.NameValuePair;  
import org.csource.fastdfs.ClientGlobal;  
import org.csource.fastdfs.StorageClient1;  
import org.csource.fastdfs.StorageServer;  
import org.csource.fastdfs.TrackerClient;  
import org.csource.fastdfs.TrackerServer;

public class FastDFSClient {  
    private TrackerClient trackerClient = null;  
    private TrackerServer trackerServer = null;  
    private StorageServer storageServer = null;  
    private StorageClient1 storageClient = null;  

    public FastDFSClient(String conf) throws Exception {  
        // 将相对路径"classpath:applications.properties"转为绝对路径"E:/workspace/src/main/resources"  
        if (conf.contains("classpath:")) {  
            conf = conf.replace("classpath:", 
            this.getClass().getResource("/").getPath());  
        }  
        ClientGlobal.init(conf);  
        trackerClient = new TrackerClient();  
        trackerServer = trackerClient.getConnection();  
        storageServer = null;  
        // StorageClient1能够自动把文件所在的组以及存放位置拼接到一块  
        storageClient = new StorageClient1(trackerServer, storageServer);  
    }  
    /**

     * 上传文件方法 
     * <p> 
     * Title: uploadFile 
     * </p> 
     * <p> 
     * Description: 
     * </p> 
     *  
     * @param fileName 
     *            文件全路径 
     * @param extName 
     *            文件扩展名,不包含(.) 
     * @param metas 
     *            文件扩展信息 
     * @return 
     * @throws Exception 
     */  
    public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {  
        String result = storageClient.upload_file1(fileName, extName, metas);  
        return result;  
    }  
    public String uploadFile(String fileName) throws Exception {  
        return uploadFile(fileName, null, null);  
    }  
    public String uploadFile(String fileName, String extName) throws Exception {  
        return uploadFile(fileName, extName, null);  
    }  
    /** 
     * 上传文件方法 
     * <p> 
     * Title: uploadFile 
     * </p> 
     * <p> 
     * Description: 
     * </p> 
     *  
     * @param fileContent 
     *            文件的内容,字节数组 
     * @param extName 
     *            文件扩展名 
     * @param metas 
     *            文件扩展信息 
     * @return 
     * @throws Exception 
     */  
    public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {  
        String result = storageClient.upload_file1(fileContent, extName, metas);  
        return result;  
    }  
    public String uploadFile(byte[] fileContent) throws Exception {  
        return uploadFile(fileContent, null, null);  
    }  
    public String uploadFile(byte[] fileContent, String extName) throws Exception {  
        return uploadFile(fileContent, extName, null);  
    }  

}  ```

新建一个工具包com.xxx.utils,然后把封装类FastDFSClient.java放到下面。
下面进行测试,在TestFastDFS类中新建测试方法testFastDFSClient,代码如下:
```java
@Test  
public void testFastDFSClient() throws Exception {  
    FastDFSClient fastDFSClient = new FastDFSClient("D:/Work/taotao2/taotao-manager-web/src/main/resources/resource/client.conf");  
    String imgPath = fastDFSClient.uploadFile("D:/test.jpg");  
    System.out.println(imgPath);  
}