mark

应公司某项产品的需求,需要存储海量的静态资源,且对系统读写性能、并发数要求很高。通过前期技术选型,对现较流行的几种分布式文件存储方案做了对比考量,最终选定FastDFS做底层存储。

FastDFS介绍

FastDFS是一款用C语言开发的开源轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。其特别适合以文件为载体的在线服务,大小在4KB~500MB 之间的小文件都能够出色应对。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群。这是款应用级的分布式文件存储服务,其源码托管在GitHub上。

作者开源地址:https://github.com/happyfish100/fastdfs/

FastDFS基本原理

基本原理这部分,转载了一篇讲得十分详细的资料(膜拜下原作者)。建议在安装前先花时间了解下,指路:分布式文件系统FastDFS设计原理

FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。跟踪器的主要作用是调度,在访问上起负载均衡的作用,存储节点的作用则是存放数据。

安装部署

一、安装环境说明

系统环境:CentOS release 6.9 (Final)

相关软件

软件名版本说明
FastDFSv5.11FastDFS主程序源码
fastdfs-nginx-modulev1.16FastDFS的nginx模块
libfastcommonv1.0.7版本依赖,FastDFS的函数库
nginxv1.8.1nginx服务源码
pcrev8.34nginx依赖的pcre库源码
zlibv1.2.8nginx依赖的zlib库源码

规划服务器角色,两台作为tracker,两个group组,每组下挂两台storage存储器组内冗余两个副本,即同一个group组下的机器存储的数据内容是一模一样的。支持横向扩容或纵向扩容。

角色划分

mark

架构图

mark

目录规划

分区挂载点作用
/dev/sda2/data1日志元数据目录
/dev/sdb/data2数据目录

二、安装 FastDFS服务

需要在该集群内每一台服务器上(所有tracker和storage)都安装FastDFS服务。

  • 初始化系统
    系统最小化环境安装,确保selinux关闭。

    sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
    setenforce 0
    chkconfig iptables off
    echo "*/10 * * * * /usr/sbin/ntpdate asia.pool.ntp.org" >>/etc/crontab yum –y install wget
    rm -rf /etc/yum.repos.d/*
    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo 
    yum makecache
    yum -y install gettext gettext-devel libXft libXft-devel libXpm libXpm-devel automake autoconf libXtst-devel gtk+-devel gcc gcc-c++zlib-devel libpng-devel gtk2-devel glib-devel pcre* gcc git
  • 安装libfastcommon和fastdfs

    编译安装。所有机器均需安装。

      #安装libfastcommon
      cd /tmp/
      git clone https://github.com/happyfish100/libfastcommon.git 
      cd libfastcommon
      ./make.sh
      ./make.sh install
      cp /usr/lib64/libfastcommon.so /usr/lib
  #安装fastdfs
  cd /tmp/
  wget https://github.com/happyfish100/fastdfs/archive/V5.11.tar.gz
  tar xf V5.11.tar.gz
  mv fastdfs-5.11 fastdfs
  cd fastdfs
  sed -i 's#/usr/local/bin/#/usr/bin/#g' init.d/fdfs_storaged 
  sed -i 's#/usr/local/bin/#/usr/bin/#g' init.d/fdfs_trackerd
  ./make.sh
  ./make.sh install

安装完成后,所有相关可执行文件均在/usr/bin目录下,以fdfs_开头。
mark

所有配置文件都在目录/etc/fdfs下,

 [root@localhost ~]# ls /etc/fdfs
 client.conf.sample  storage.conf.sample  tracker.conf.sample

配置服务

本文不涉及参数的具体含义。关于fastdfs配置的各项参数详解之后会抽时间整理。


  • Tracker配置(所有tracker配置文件相同)

Tracker01:172.16.100.212

Tracker02:172.16.100.213

修改配置文件,提前创建好日志元数据目录

mkdir -p /data1
cd /etc/fdfs
cp tracker.conf.sample tracker.conf
sed -i 's&base_path=.*&base_path=/data1&g' tracker.conf

设置自启项

chkconfig --add fdfs_trackerd
chkconfig fdfs_trackerd on
service fdfs_trackerd start
netstat -unltp | grep fdfs

安装nginx,此处的nginx只是作为反向代理使用,不用添加fastdfs-nginx-module模块重新编译,所以yum安装即可。

yum install -y epel-release
yum install -y nginx
chkconfig --add nginx
chkconfig nginx on

配置前端下载网关,修改/etc/nginx/nginx.conf

①设置负载均衡池里的后端真实ip,在http{}段添加:

upstream group1 { 
        server 172.16.100.214:80;
        server 172.16.100.216:80;
}

upstream group2 {
        server 172.16.100.215:80;
        server 172.16.100.217:80;
}

②设置后端真实服务器组的负载均衡参数,在server{}段添加:

location段作用,实际访问后端的服务器返回 502、504、执行超时等错误,自动将请求转发到 upstream 负载均衡池中的另一台服务器,实现故障转移。

server {
        listen 80;
        server_name 172.16.100.212;     #此处是本机服务地址
        #server_name 172.16.100.213;
        
        location /G1/M00 {
            proxy_next_upstream http_502 http_504 error timeout invalid_header;
            proxy_cache  http-cache;
            proxy_cache_valid 200 304 12h; 
            proxy_cache_key $uri$is_args$args; 
            proxy_pass  http://group1;
            expires 30d;
        }    

        location ~* /G2/(M00|M01) { 
            proxy_next_upstream http_502 http_504 error timeout invalid_header; 
            proxy_cache  http-cache;
            proxy_cache_valid 200 304 12h; 
            proxy_cache_key $uri$is_args$args; 
            proxy_pass  http://group2;
            expires 30d;
        }
}

配置完成以后,启动nginx和fdfs_trackerd服务了,tracker端的配置over。

server nginx restart
server fdfs_storaged restart

------

  • Storage配置(同组下的storage配置文件相同)
​​‌‌​​​‌‌​‌​​‌‌‍​‌​‌‌‌​​‌‌‌‌​‌​‍​‌​​‌​​​‌​​​‌‌​‍​‌​‌‌​​​‌‌​​​​​‍​​‌​‌‌‌‌‌‌‌‌​​​‍​‌‌​​‌‌‌​‌‌​​‌‌‌‍​‌‌​​​‌‌‌​​​‌​‌‍​​‌‌‌‌‌‌‌‌​​‌‌‍​‌​‌‌​‌‌‌‌‌‌​​‌‍​‌​​​​‌‌‌‌‌‌‌​​‍​‌​​​​​‌‌‌‌​​​​‍​‌​​‌​​‌​‌​​‌‌‌‍​‌​‌‌‌‌​‌​‌​‌‌‌‍​‌​​‌​​​‌‌​​​​‌‍​​‌‌‌​‌‌‌‌​​‌‌‌‍​​​​​​​​‌‌‌‌​‌‌‌‍‌‌​​‌‌‌​‍​​​​​​​​‌‌‌‌​‌‌​‍​​​​​​​​‌‌‌​​‌​‌‍‌​‌‌‌​​‌‍‌​​‌‌‌‌​‍‌​​​‌‌​​‍‌​​​‌​‌‌‍‌​‌‌‌​‌‌‍‌​‌‌‌​​‌‍‌​‌​‌‌​​‍​‌‌​‌‌‌‌​​​‌​‌‌‌‍​​​​​​​‌​​​‌‌​‌‍​​‌‌‌‌‌‌‌‌​​‌​‍​​​​​​​​‌‌‌‌​​‌‌‍​​​‌​‌​‌‌​​‌‌‌​‍‌​​‌‌‌‌​‍‌​​‌‌​‌‌‍‌​​‌​​‌​‍‌​​‌​‌‌​‍‌​​‌​​​‌‍​‌‌​​​‌​‌‌‌​​​‌‍‌‌​​‌‌​‌‍‌‌​​‌‌‌‌‍‌‌​​‌‌‌​‍‌‌​​‌​​​‍‌‌​‌​​‌​‍‌‌​​‌‌‌​‍‌‌​​‌‌‌​‍‌‌​‌​​‌​‍‌‌​​‌‌​‌‍‌‌​​‌‌‌‌‍​‌​‌‌​‌‌‌‌​​‌​​‍​‌‌​​​​‌​‌​​​‌‌‍​​​​​​​​‌‌‌‌​​‌‌‍​‌​‌‌​​​‌‌​​​​​‍​​‌‌​‌​​‌‌‌‌​​​‍​‌​‌​​​‌‌​​‌‌‌‌‍​‌​‌​​​‌​‌‌‌‌‌‌‍​​​​​​​​‌‌‌​​‌​‌‍‌​​‌​‌‌‌‍‌​​​‌​‌‌‍‌​​​‌​‌‌‍‌​​​‌‌‌‌‍‌​​​‌‌​​‍‌‌​​​‌​‌‍‌​‌​​​‌‌‍‌​‌​​​‌‌‍‌​​‌​‌‌​‍‌​​‌​‌​​‍‌​​‌​‌‌​‍‌​​​‌​​​‍‌​​‌​‌‌​‍‌‌​‌​​​‌‍‌​​‌​​‌​‍‌​​‌‌​‌​‍‌​‌​​​‌‌‍‌​​‌‌‌‌​‍‌​​​‌‌​‌‍‌​​‌‌‌​​‍‌​​‌​‌‌‌‍‌​​‌​‌‌​‍‌​​​‌​​‌‍‌​​‌‌​‌​‍‌​​​‌‌​​‍‌​‌​​​‌‌‍‌‌​​‌‌​‌‍‌‌​​‌​​​‍‌‌​‌​​​‌‍‌​​‌​‌‌‌‍‌​​​‌​‌‌‍‌​​‌​​‌​‍‌​​‌​​‌‌

提前创建好元数据目录和数据目录。此处只列出了需要修改的参数,其他默认即可

G1: SG11(172.16.100.214)

​ SG12(172.16.100.216)

mkdir /data1 /data2    
cd /etc/fdfs
cp storage.conf.sample storage.conf
vim /etc/fdfs/storage.conf
...
group_name=G1    #storage组别名称,这里是group1,即G1
base_path=/data1    #元数据目录
store_path_count=1    #存储路径个数,和store_path个数匹配
store_path0=/data2    #存储路径1
tracker_server=172.16.100.212:22122
tracker_server=172.16.100.213:22122

G2: SG21(172.16.100.215)

​ SG22(172.16.100.217)

mkdir /data1 /data2    
cd /etc/fdfs
cp storage.conf.sample storage.conf
vim /etc/storage.conf
...
group_name=G2    #storage组别名称,这里是group2,即G2
base_path=/data1    #元数据目录
store_path_count=1    #存储路径个数,和store_path个数匹配
store_path0=/data2    #存储路径1
tracker_server=172.16.100.212:22122
tracker_server=172.16.100.213:22122

启动storage服务,所有storage节点上均执行,检查服务是否成功开启:

service fdfs_storaged start
chkconfig fdfs_storaged on
netstat -unltp | grep fdfs

安装配置 fastdfs-nginx-module,解决同步延迟问题。

fastdfs-nginx-module的作用是重定向连接到源服务器取文件,避免客户端由于复制延迟的问题,出现错误。因为同组下的节点互为冗余,即镜像备份,备份过程需要时间,如果一个文件上传到节点A,复制到节点B需要花时间,如果在没有复制完成之前,客户端读取这个文件的请求被调度器指向了节点B,就会发生错误。

在所有的storage节点上安装nginx。这里需要加载 fastdfs-nginx-module模块并对nginx重新编译,所以选择源码包编译的方式安装nginx。

①编译前确保安装依赖

yum install pcre-devel openssl-devel -y 
yum install make zlib zlib-devel gcc-c++ libtool
groupadd www && useradd www -g www -M -s /sbin/nologin
wget http://nginx.org/download/nginx-1.8.1.tar.gz
git clone https://github.com/happyfish100/fastdfs-nginx-module.git 
tar xf nginx-1.8.1.tar.gz
cd nginx-1.8.1

②编译安装nginx(这里提供一份自己常用的编译参数)

./configure --prefix=/usr/local/nginx \
    --sbin-path=${prefix}/sbin/nginx  \
    --conf-path=${prefix}/conf/nginx.conf   \
    --error-log-path=${prefix}/logs/error.log  \
    --http-log-path=${prefix}/logs/access.log   \
    --pid-path=${prefix}/logs/nginx.pid   \
    --lock-path=${prefix}/logs/nginx.lock  \
    --http-client-body-temp-path=${prefix}/cache/client_temp  \
    --http-proxy-temp-path=${prefix}/cache/proxy_temp  \
    --http-fastcgi-temp-path=${prefix}/cache/fastcgi_temp  \
    --http-uwsgi-temp-path=${prefix}/cache/uwsgi_temp  \
    --http-scgi-temp-path=${prefix}/cache/scgi_temp  \
    --user=www \
    --group=www   \
    --with-pcre \
    --with-http_ssl_module  \
    --with-http_spdy_module  \
    --with-http_stub_status_module \
    --with-http_realip_module  \
    --with-http_addition_module  \
    --with-http_sub_module  \
    --with-http_dav_module  \
    --with-http_flv_module  \
    --with-http_mp4_module  \
    --with-http_gunzip_module  \
    --with-http_gzip_static_module \
    --with-http_random_index_module \
    --with-http_secure_link_module \
    --with-http_degradation_module \
    --with-http_auth_request_module  \
    --with-file-aio \
    --add-module=../fastdfs-nginx-module/src/ \

 make -j8 && make install

③配置fastdfs模块

cp ../fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/
cp /tmp/fastdfs/conf/{anti-steal.jpg,http.conf,mime.types}     /etc/fdfs/
touch  /var/log/mod_fastdfs.log
chown www.www /var/log/mod_fastdfs.log

修改mod_fastdfs.conf参数,同组节点的配置。同前面,此处只列出需要修改的参数。

G1: SG11(172.16.100.214)

​ SG12(172.16.100.216)

vim /etc/fdfs/mod_fastdfs.conf
...
tracker_server=172.16.100.212:22122
tracker_server=172.16.100.213:22122
group_name=G1    # 注意这里是G1
url_have_group_name = true
store_path_count=1
store_path0=/data2
log_filename=/var/log/mod_fastdfs.log
group_count = 2
[group1]
group_name=G1
storage_server_port=23000
store_path_count=1
store_path0=/data2
[group2]
group_name=G2
storage_server_port=23000
store_path_count=1
store_path0=/data2

G2: SG21(172.16.100.215)

​ SG22(172.16.100.217)

vim /etc/fdfs/mod_fastdfs.conf
...
tracker_server=172.16.100.212:22122
tracker_server=172.16.100.213:22122
group_name=G2    # 注意这里是G2
url_have_group_name = true
store_path_count=1
store_path0=/data2
log_filename=/var/log/mod_fastdfs.log
group_count = 2
[group1]
group_name=G1
storage_server_port=23000
store_path_count=1
store_path0=/data2
[group2]
group_name=G2
storage_server_port=23000
store_path_count=1
store_path0=/data2

修改nginx配置文件,在server{}段添加:

G1组:

vim /usr/local/nginx-1.8.1/conf/nginx.conf
...
location /G1/M00{        #M00表示该台storage上的第1个虚拟磁盘路径 
    root /data2;         #第1个虚拟磁盘的数据目录
    ngx_fastdfs_module;
}    

G2组:

  vim /usr/local/nginx-1.8.1/conf/nginx.conf
  ...
  location /G2/M00{        #M00表示该台storage上的第1个虚拟磁盘路径 
   root /data2;         #第1个虚拟磁盘的数据目录
   ngx_fastdfs_module;
  }    

配置完成以后,重启nginx和fdfs_storaged服务,storage端的配置over。

server nginx restart
server fdfs_storaged restart

## Client客户端测试

选取另外一台服务器作为客户端测试,同样需要安装FastDFS服务,只需要配置下/etc/fdfs/client.conf文件,不需要安装nginx和配置其他东西。

vim /etc/fdfs/client.conf

connect_timeout=30
network_timeout=60 
base_path=/tmp 
tracker_server=172.16.100.212:22122 
tracker_server=172.16.100.213:22122 
log_level=info
use_connection_pool = false 
connection_pool_max_idle_time = 3600
load_fdfs_parameters_from_tracker=false 
use_storage_id = false 
storage_ids_filename = storage_ids.conf 
http.tracker_server_port=80
  • 查看集群状态:fdfs_monitor (输出结果省略部分)

    [root@localhost ~]# fdfs_monitor /etc/fdfs/client.conf 
    ...............
    
    tracker server is 172.16.100.212:22122    # 处理本次请求的调度器IP
    
    group count: 2    # 两个storage组
    
    Group 1:    
    group name = G1
    storage server count = 2
    active server count = 2
    store path count = 1
    ...............
        Storage 1:
            id = 172.16.100.214
            ip_addr = 172.16.100.214  ACTIVE
            store_path_count = 1
            ....................
        Storage 2:
            id = 172.16.100.216
            ip_addr = 172.16.100.216  ACTIVE
            store_path_count = 1
            ....................
        
    Group 2:
    group name = G2
    storage server count = 2
    active server count = 2
    store path count = 1
    ...............
    
        Storage 1:
            id = 172.16.100.215
            ip_addr = 172.16.100.215  ACTIVE    
            store_path_count = 1
            ....................
        Storage 2:
            id = 172.16.100.217
            ip_addr = 172.16.100.217  ACTIVE    
            store_path_count = 1
            ....................
  • 上传图片:fdfs_upload_file

    [root@localhost ~]# fdfs_upload_file /etc/fdfs/client.conf test.png G1/M00/00/00/rBBk1lmJcPKACDovAAKdnmAZNuY251.png

文件被上传到group1中某台storage的第一个虚拟磁盘路径(M00)下

  • 下载图片:fdfs_download_file

    [root@localhost ~]# fdfs_download_file /etc/fdfs/client.conf \ G1/M00/00/00/rBBk1lmJcPKACDovAAKdnmAZNuY251.png
  • 查看文件信息:fdfs_file_info

    [root@localhost ~]# fdfs_file_info /etc/fdfs/client.conf G1/M00/00/00/rBBk1lmJcPKACDovAAKdnmAZNuY251.png
    source storage id: 0
    source ip address: 172.16.100.214
    file create timestamp: 2017-11-08 00:53:10
    file size: 171422
    file crc32: 1612265190 (0x601936E6)
  • 删除文件:fdfs_delete_file

    [root@localhost ~]# fdfs_delete_file /etc/fdfs/client.conf \ G1/M00/00/00/rBBk1lmJcPKACDovAAKdnmAZNuY251.png
  • 剔除offline的storage server

    [root@SG11 ~]# fdfs_monitor    /etc/fdfs/client.conf    delete    172.16.100.214
  • 浏览器访问测试

mark

至此,一个简单的FastDFS分布式文件存储系统就搭建完毕了。暂时先到这里,更多的高级功能以后再总结。