FastDFS入门安装与nginx整合

分布式文件系统fastDFS研究

什么是分布式文件系统

技术应用场景

一个网站拥有大量的视频和图片资源,并且免费提供用户去下载,文件太多如何高效存储?用户访问量大,如何提升访问速度?

分布式文件系统可以解决上述问题.

分布式文件系统解决了海量文件存储及传输访问的瓶颈问题,对海量视频的管理、对海量图片的管理等。

什么是文件系统

总结:文件系统是负责管理和存储文件的系统软件,它是操作系统和硬件驱动之间的桥梁,操作系统通过文件系统

提供的接口去存取文件,用户通过操作系统访问磁盘上的文件。如下图:

1566120616102

常见的文件系统:FAT16/FAT32、NTFS、HFS、UFS、APFS、XFS、Ext4等 。

什么是分布式文件系统

为什么会有分布文件系统呢?

分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经满足

不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,另外我们还要要做好数据备份、数据安全等。

采用分布式文件系统可以将多个地点的文件系统通过网络连接起来,组成一个文件系统网络,结点之间通过网络进

行通信,一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算共同传输。如下

图:

1566120660440

好处:

1、一台计算机的文件系统处理能力扩充到多台计算机同时处理。

2、一台计算机挂了还有另外副本计算机提供数据。

3、每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度。

主流的分布式文件系统

1、NFS

1566120677777

2、GFS

1566120700956

1)GFS采用主从结构,一个GFS集群由一个master和大量的chunkserver组成。

2)master存储了数据文件的元数据,一个文件被分成了若干块存储在多个chunkserver中。

3)用户从master中获取数据元信息,从chunkserver存储数据。

3、HDFS

1566120727733

1)HDFS采用主从结构,一个HDFS集群由一个名称结点和若干数据结点组成。

名称结点存储数据的元信息,一个完整的数据文件分成若干块存储在数据结点。

2)客户端从名称结点获取数据的元信息及数据分块的信息,得到信息客户端即可从数据块来存取数据。

分布式文件服务提供商

1566120746916

什么是fastDFS

fastDSF介绍

FastDFS是用c语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。FastDFS专为互联

网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很

容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

为什么要使用fastDFS呢?

上边介绍的NFS、GFS都是通用的分布式文件系统,通用的分布式文件系统的优点的是开发体验好,但是系统复杂

性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。fastDFS非常适合

存储图片等那些小文件,fastDFS不对文件进行分块,所以它就没有分块合并的开销,fastDFS网络通信采用

socket,通信速度很快。

fastDSF工作原理

fastDSF架构

FastDFS架构包括 Tracker server和Storageserver。客户端请求Tracker server进行文件上传、下载,通过Tracker

server调度最终由Storage server完成文件上传和下载。

1566120766450

1)Tracker

Tracker Server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提

供文件上传服务。可以将tracker称为追踪服务器或调度服务器。

FastDFS集群中的Tracker server可以有多台,Tracker server之间是相互平等关系同时提供服务,Tracker server

不存在单点故障。客户端请求Tracker server采用轮询方式,如果请求的tracker无法提供服务则换另一个tracker。

2)Storage

Storage Server作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己

的文件系统而是使用操作系统的文件系统来管理文件。可以将storage称为存储服务器。

3)Storage状态收集

Storage server会连接集群中所有的Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步

状况、文件上传下载次数等统计信息。

总结:

(1)客户端请求tracker执行下载或者上传文件,tracker负责找到文件在storage集群的位置,将信息返回客户端

(2)客户端拿到信息,向storage具体组,和具体文件位置执行操作

(3)storage可以在配置时分多个group组,每组可以有多台storage服务器,但是每台服务器,再执行上传或者下载之后都会将

数据同步到该组下的其他服务器上,因此一个组的每个服务器文件内容一样,这样是为了高可用

文件上传流程

1566120786426

客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息

包括:组名,虚拟磁盘路径,数据两级目录,文件名。

1566120802924

  • 组名:文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。

  • 虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,

如果配置了store_path1则是M01,以此类推。

  • 数据两级目录:storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。

  • 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创

建时间戳、文件大小、随机数和文件拓展名等信息。

文件下载流程

1566120819693

tracker根据请求的文件路径即文件ID 来快速定义文件。

文件id从数据库中获取到,再去文件系统中查找

比如请求下边的文件:

1566120835619

1.通过组名tracker能够很快的定位到客户端需要访问的存储服务器组是group1,并选择合适的存储服务器提供客 户端访问。

2.存储服务器根据“文件存储虚拟磁盘路径”和“数据文件两级目录”可以很快定位到文件所在目录,并根据文件名找到 客户端需要访问的文件。

fastDFS入门

FastDFS 安装与配置

导入虚拟机

1、使用Vmware打开虚拟机配置文件“CentOS 7 64 位.vmx”,提示如下图:

2、选择“我已复制该虚拟机”

3、启动虚拟机之前启动VMware的服务:

fastDFS安装

分别在 192.168.101.3 和 192.168.101.4 上安装 tracker。

注:初次安装可只安装一台 tracker,快速体验。

tracker 和 storage 使用相同的安装包,下载地址:

https://github.com/happyfish100/FastDFS

本测试下载:FastDFS_v5.05.tar.gz

FastDFS 安装环境

FastDFS 是 C 语言开发,建议在 linux 上运行,本教程使用 Centos7 作为安

装环境。

安装 FastDFS 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果

没有 gcc 环境,需要安装 gcc:yum install gcc-c++

安装 libevent

FastDFS 依赖 libevent 库,需要安装:

yum -y install libevent

安装 libfastcommon

libfastcommon 是 FastDFS 官方提供的,libfastcommon 包含了 FastDFS 运行所需

要的一些基础库。

将 libfastcommonV1.0.7.tar.gz 拷贝至/usr/local/下

cd /usr/local

tar -zxvf libfastcommonV1.0.7.tar.gz

cd libfastcommon-1.0.7

./make.sh

./make.sh install

注意:make指令不能用的话是缺少相关指令包,下载即可

注意:libfastcommon 安装好后会自动将库文件拷贝至/usr/lib64 下,由于 FastDFS 程

序引用 usr/lib 目录所以需要将/usr/lib64 下的库文件拷贝至/usr/lib 下。

要拷贝的文件如下:

1566120855467

tracker 编译安装

将 FastDFS_v5.05.tar.gz 拷贝至/usr/local/下

tar -zxvf FastDFS_v5.05.tar.gz

cd FastDFS

./make.sh 编译

./make.sh install 安装

安装成功将安装目录下的 conf 下的文件拷贝到/etc/fdfs/下。

1566120871118

配置

安装成功后进入/etc/fdfs 目录:

拷贝一份新的 tracker 配置文件:

cp tracker.conf.sample tracker.conf

修改 tracker.conf

vi tracker.conf

端口:port=22122

存储策略:store_lookup= 取值范围:0(轮询向storage存储文件)、1(指定具体的group)、2负载均衡,选择空闲的storage存储

指定具体的group:store_group= 如果store_lookup设置为1则这里必须指定一个具体的group。

tracker 基础目录:base_path=/home/fastdfs,tracker在运行时会向此目录存储storage的管理数据。

启动tracker

usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart

注意:没有目录自行创建,进程占用就kill掉

storage 安装

分别在 192.168.101.5、192.168.101.6、192.168.101.7、192.168.101.8 上安装 storage。

注:初次安装可只安装一台 storage,快速体验。

安装 libevent

同 tracker 安装

安装 libfastcommon

同 tracker 安装。

storage 编译安装

同 tracker 编译安装。

配置

安装成功后进入/etc/fdfs 目录:

拷贝一份新的 storage 配置文件: 

cp storage.conf.sample storage.conf

修改 storage.conf 

vi storage.conf 

group_name=group1 

向tracker心跳间隔(秒):heart_beat_interval=30 

storage基础目录:base_path=/home/fastdfs 

磁盘存储目录,可定义多个store_path: 
store_path0=/home/fastdfs/fdfs_storage 此目录下存储上传的文件,在/home/fastdfs/fdfs_storage/data下 store_path1=... ... 

上报tracker的地址:tracker_server=192.168.101.64:22122 
如果有多个tracker则配置多个tracker,比如: 
tracker_server=192.168.101.64:22122 
tracker_server=192.168.101.65:22122 
....

启动storage

/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart

文件上传下载测试

搭建环境

这里我们使用javaApi测试文件的上传,java版本的fastdfs-client地址在:

https://github.com/happyfifish100/fastdfs-client-java,参考此工程编写测试用例。

1)创建maven工程

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>xc-framework-parent</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../xc-framework-parent/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>test-fastdfs</artifactId>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-io</artifactId>
    </dependency>
</dependencies>
</project>

2) 配置 文件

在classpath:confifig下创建fastdfs-client.properties文件

#http连接超时时间
fastdfs.connect_timeout_in_seconds=5 
#tracker与storage网络通信超时时间
fastdfs.network_timeout_in_seconds = 30 
#字符编码
fastdfs.charset = UTF-8
#多个traker的话后面逗号继续配置
#tracker服务器地址,多个地址中间用英文逗号分隔
fastdfs.tracker_servers = 192.168.138.129:22122 

文件上传

//上传测试
    @Test
    public void testUpload() {
        //加载配置文件,提供端口等信息
        try {
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            //定义一个tracker客户端,用来请求trackerServer
            TrackerClient trackerClient = new TrackerClient();
            //连接tracker
            TrackerServer trackerServer = trackerClient.getConnection();
            //获取storage
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            //创建storageClient
            StorageClient1 storageClient1 = new StorageClient1(trackerServer,storageServer);
            //向storage服务器上传文件
            //本地文件
            String filePath = "F:/logo.png";
            //上传成功后拿到文件id
            String fileId = storageClient1.upload_file1(filePath, "png", null);
            System.out.println(fileId);
//            group1/M00/00/00/wKiKgV0iIOWAWnTPAAAawU0ID2Q874.png
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }

文件下载

//下载测试
    @Test
    public void testDownload() {
        try {
        //读取配置文件
        ClientGlobal.initByProperties("config/fastdfs-client.properties");
        //创建tracker客户端
        TrackerClient trackerClient = new TrackerClient();
        //连接tracker
        TrackerServer trackerServer = trackerClient.getConnection();
        //tracker连接storage
        StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
        //创建storage客户端
        StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);
        //从服务器下载文件
            String fileId = "group1/M00/00/00/wKiKgV0iIOWAWnTPAAAawU0ID2Q874.png";
        //获取下载路径
            byte[] bytes = storageClient1.download_file1("group1/M00/00/00/wKiKgV0iIOWAWnTPAAAawU0ID2Q874.png");
        //使用输出流保存文件
        FileOutputStream outputStream = new FileOutputStream(new File("g:/logo.png"));
        //向本地写文件
        outputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        }

文件查询

//查询文件 
@Test 
public void testQueryFile() throws IOException, MyException { 

    ClientGlobal.initByProperties("config/fastdfs‐client.properties"); 

    TrackerClient tracker = new TrackerClient(); 

    TrackerServer trackerServer = tracker.getConnection(); 

    StorageServer storageServer = null; 

    StorageClient storageClient = new StorageClient(trackerServer, 

    storageServer);

    FileInfo fileInfo = storageClient.query_file_info("group1", 

    "M00/00/01/wKhlQFrKBSOAW5AWAALcAg10vf4862.png"); 

    System.out.println(fileInfo); 
} 

搭建图片虚拟主机

在storage上安装Nginx

在 storage server 上安装 nginx 的目的是对外通过 http 访问 storage server 上的文 件。使用 nginx 的模块

FastDFS-nginx-module 的作用是通过 http 方式访问 storage 中 的文件,当 storage 本机没有要找的文件时向源

storage 主机代理请求文件。

  • ### 在storage上安装FastDFS-nginx-module模块

将 FastDFS-nginx-module_v1.16.tar.gz 传 至 fastDFS 的 storage 服 务 器 的

/usr/local/下,执行如下命令:

cd /usr/local
tar -zxvf FastDFS-nginx-module_v1.16.tar.gz
cd FastDFS-nginx-module/src
修改 config 文件将/usr/local/路径改为/usr/

1566120893740

将 FastDFS-nginx-module/src 下的 mod_FastDFS.conf 拷贝至/etc/fdfs/下

cp mod_FastDFS.conf /etc/fdfs/

并修改 mod_FastDFS.conf 的内容:

vi /etc/fdfs/mod_FastDFS.conf 

base_path=/home/FastDFS

tracker_server=192.168.101.3:22122 

tracker_server=192.168.101.4:22122 

url_have_group_name=true #url 中包含 group 名称 

store_path0=/home/fastdfs/fdfs_storage #指定文件存储路径 

\#如果有多个

将 libfdfsclient.so 拷贝至/usr/lib 下

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

创建 nginx/client 目录

mkdir -p /var/temp/nginx/client

  • storage上nginx 安装

将 nginx-1.8.0.tar.gz 拷贝到/usr/local 下

解压 nginx-1.8.0.tar.gz

进入 nginx-1.8.0 目录,执行如下配置命令:

下边红色部分表示添加 fastdfs-nginx-module 模块

--prefix=/usr/local/nginx \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/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=/usr/local/fastdfs-nginx-module/src #红色

make

make install

  • nginx 配置文件

usr/local/nginx/conf/下新建一个 nginx 配置文件 nginx-fdfs.conf.

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

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

添加虚拟主机:(对上述模板进行修改)

server{
        listen  80;
        server_name 192.168.138.129;

        location /group1/M00/{
            root /home/fastdfs/fdfs_storage/data;
            ngx_fastdfs_module;
        }
 }

说明:

server_name 指定本机 ip

location /group1/M00/:group1 为 nginx 服务 FastDFS 的分组名称,M00 是 FastDFS

自动生成编号,对应 store_path0=/home/fastdfs/fdfs_storage,如果 fastdfs定义

store_path1,这里就是 M01

  • 安装完成启动storage上的nginx:

/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf

注意:启动如果报nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] still could not bind() 错误那是端口占用了,使用lsof -i :80命令查看被占用端口,kill掉

测试

通过 java 客户端上传文件,使用浏览器 http 访问文件,这里访问上传图片测试的文件:

访问 storage:http://192.168.101.5/group1/M00/00/00/wKhlBVVY2M-AM_9DAAAT7-0xdqM485_big.png

ip 地址改为 192.168.101.6 也可以访问到文件,因为同一个分组的 storage 文件互相同步。

访问 tracker:

http://192.168.101.3/group1/M00/00/00/wKhlBVVY2M-AM_9DAAAT7-0xdqM485_

big.png

ip 地址改为 192.168.101.4 也可以访问到文件。

配置Nginx图片服务虚拟机主机

图片服务虚拟主机的作用是负载均衡,将图片请求转发到storage server上。

1、通过图片服务虚拟主机请求图片流程图

1566120911979

3、在nginx图片代理服务上配置图片服务器虚拟主机

配置 #图片服务配置了group1下的storage服务器地址 和 #学成在线图片服务

#gzip  on;
	
		#cms页面预览
		upstream cms_server_pool{
		server 127.0.0.1:31001 weight=10;
		}
		
	#图片服务配置了group1下的storage服务器地址
	upstream img_server_pool{
	#server 192.168.101.5:80 weight=10;
	server 192.168.138.129:80 weight=10;
	}
	#upstream img_server_pool2{
	#server 192.168.101.5:80 weight=10;
	#server 192.168.138.129:80 weight=10;
	#}
	
    server{
	listen       80;
	server_name  www.xuecheng.com;
	ssi on;
	ssi_silent_errors on;
	location / {
		alias   F:/WebXiangmu/xuecheng/xc-ui-pc-static-portal/;
		index  index.html;
	}
	#页面预览
		location /cms/preview/ {
		proxy_pass http://cms_server_pool/cms/preview/;
	}
	
   }
	#学成在线图片服务
		server {
		listen 80;
		server_name img.xuecheng.com;
		
		#个人中心
		location /group1{
		
		proxy_pass http://img_server_pool;
		}
		#location /group2{
		#proxy_pass http://img_server_pool2; 
		#} 
	}

然后在HOSTS文件中添加 127.0.0.1 img.xuecheng.com dns服务,再执行ipconfig/flushdns刷新dns服务

就可以使用域名加文件id访问了

图片服务器启动 脚本

1、启动tracker:/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart 
2、启动storage:/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart 
3、启动storage上的nginx:/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf 
4、启动图片虚拟主机 nginx

HuangRui

Every man dies, not every man really lives.

HaungRui, China suixinblog.cn