首页 > 代码库 > MogileFS + Nginx 实现基于CentOS7平台的分布式文件存储与访问

MogileFS + Nginx 实现基于CentOS7平台的分布式文件存储与访问

MogileFS是一个开源的分布式文件系统,Nginx是开源的4-7层web应用服务端以及反向代理服务端。本文基于CentOS7平台,进行MogileFS + Nginx的部署


  • MogileFS的一些注意事项 
    针对于MogileFS,有如下概念需要注意一下。

  1. MogileFS属于有中心节点形式的分布式文件系统,元数据默认存储在关系型数据库(MySQL)当中,在此处于单点,因此有必要对MySQL使用主从复制或者MHA。

  2. 按功能分为tracker,database,storage。其中tracker负责对于元数据信息进行管理,对整个MogileFS系统进行协调监控。其中database负责存储tracker所管理的元数据。其中storage负责存储数据文件。

  3. MogileFS依赖于perbal作为代理,一方面接收客户端的请求并将其发送至tracker进行检索,一方面接收tracker的检索结果并向storage发送获取请求,另一方面接收storage的响应并且传递给客户端所请求的内容。

  4. 亦可以使用Nginx作为代理,不过需要对原生的Nginx安装mogilefs的模块(或者称为打上mogilefs的补丁)

MogileFS管理文件的一些概念
  1. Domain: 一个MogileFS可以有多个Domain,用来存放不同文件(大小,类型),同一个Domain内key必须为一,不同Domain内,key可以相同。

  2. Class:文件属性管理,定位文件存储在不同设备上面的份数。

  3. 每一个storage称为一个主机,一个主机上可以有多个存储设备(单独的硬盘),每个设备都有ID号,Domain+Fid用来定位文件。

MogileFS各个功能组件的交互图示

技术分享


  • MogileFS针对客户端请求的工作流程图

技术分享

  • MogileFS搭建环境拓扑结构 
    笔者的拓扑结构如下图所示。其中一台Nginx作为反向代理,用于代理用户的客户端请求。两个tracker,两个storage,一个database。这里,笔者将一组tracker + storage + database部署在一台机器上面,将另一组tracker + storage部署在另一台机器上面。

技术分享


初始安装及初始配置

MogileFS是基于Perl语言构建的项目,因此需要从CPAN上面下载MogileFS的模块,因此需要保证被部署的机器能够直接或者通过代理连接至互联网,如果无法联网,则需要梳理模块的依赖关系,通过其他途径下载所有所需要的perl的模块,并且手工编译安装。

首先,在两台机器上面安装cpanm工具,用于安装模块:

wget http://xrl.us/cpanm -O /usr/bin/cpanm; sudo chmod +x /usr/bin/cpanm

cpanm安装完毕之后,在两台机器上面安装MogileFS所需要的模块:

cpanm App::cpanminus
cpanm IO::AIO
cpanm IO::WrapTie
cpanm Danga::Socket
cpanm DBD::mysql
cpanm MogileFS::Server
cpanm MogileFS::Client
cpanm MogileFS::Utils

模块安装完毕之后,对Sys::Syscall模块进行降级操作。默认情况下通过cpan安装完MogileFS之后,其依赖模块Sys::Syscall的版本为0.25,如果不降级的话,会在运行时的log里面出现crash信息,并且无法完成devcount的冗余。笔者这里下载的旧版本是0.23版本的模块压缩包。由于该模块的特性,可以直接跳过编译步骤,将解压之后的模块文件夹里面的lib/Sys/Syscall.pm直接拷贝到/usr/local/share/perl5/Sys/目录下面,对原有0.25版本的模块进行替换。

tar -zxvf Sys-Syscall-0.23
cp -f Sys-Syscall-0.23/lib/Sys/Syscall.pm /usr/local/share/perl5/Sys/

通过如下命令查看模块版本是否已经替换为0.23版本:

grep -E "VERSION\s" /usr/local/share/perl5/Sys/Syscall.pm

安装完毕之后,进入配置阶段。首先在两台机器上面创建/etc/mogilefs这个目录,用于存放配置文件。其次在两台机器上面创建mogilefs组和mogilefs用户,用于运行mogileFS相关的进程(笔者将上述用户和组创建为系统用户和系统组)。之后再在两台机器上面创建/mog_data目录,用于模拟storage的设备目录的父目录,并赋予mogilefs用户和mogilefs用户组权限。

mkdir /etc/mogilefs
groupadd -r mogilefs
useradd -r -g mogilefs -d /home/mogilefs -s /bin/bash -m mogilefs
mkdir /mog_data/
chown mogilefs.mogilefs /mog_data

由于利用CPAN安装的MogileFS并未涉及到配置文件,因此这里笔者使用了GitHub上面提供的mogilefsd.conf文件和mogstored.conf文件作为MogileFS系统的配置文件。mogilefsd.conf文件作为tracker的配置,而mogstored.conf为storage进行配置。将上述两个文件下载,并拷贝到两台机器的/etc/mogilefs目录下面

cp mogilefsd.conf /etc/mogilefs
cp mogstored.conf /etc/mogilefs

mogilefsd.conf配置文件的内容如下所示,其中几个比较重要的参数例如db_dsn用于定义database的IP地址(这里定义为笔者环境里面的192.168.11.130这台机器),db_user定义mogilefs进程连接数据库时所使用的用户名,db_pass定义mogilefs进程连接数据库时所使用的密码,listen定义tracker的监听套接字地址和端口:

# Enable daemon mode to work in background and use syslog
daemonize = 1
# Where to store the pid of the daemon (must be the same in the init script)
pidfile = /home/mogilefs/mogilefsd.pid
# Database connection information
db_dsn = DBI:mysql:mogilefs:host=192.168.11.130
db_user = mogile
db_pass = mogile
# IP:PORT to listen on for mogilefs client requests
listen = 0.0.0.0:7001
# Optional, if you don‘t define the port above.
conf_port = 7001
# Number of query workers to start by default.
query_jobs = 10
# Number of delete workers to start by default.
delete_jobs = 1
# Number of replicate workers to start by default.
replicate_jobs = 5
# Number of reaper workers to start by default.
# (you don‘t usually need to increase this)
reaper_jobs = 1
# Number of fsck workers to start by default.
# (these can cause a lot of load when fsck‘ing)
#fsck_jobs = 1
# Minimum amount of space to reserve in megabytes
# default: 100
# Consider setting this to be larger than the largest file you
# would normally be uploading.
#min_free_space = 200
# Number of seconds to wait for a storage node to respond.
# default: 2
# Keep this low, so busy storage nodes are quickly ignored.
#node_timeout = 2
# Number of seconds to wait to connect to a storage node.
# default: 2
# Keep this low so overloaded nodes get skipped.
#conn_timeout = 2
# Allow replication to use the secondary node get port,
# if you have apache or similar configured for GET‘s
#repl_use_get_port = 1

mogstored.conf配置文件的内容如下所示,定义最大连接数为10000,定义http接口以及管理接口的套接字端口,定义根目录(所有设备目录的父目录)为/mog_data。

maxconns = 10000
httplisten = 0.0.0.0:7500
mgmtlisten = 0.0.0.0:7501
docroot = /mog_data/

之后需要在database里面创建mogilefs的连接用户。登录mysql节点,做如下配置。其中的pwd代表用户的登录密码。

GRANT ALL PRIVILEGES ON *.* TO root@‘%‘ IDENTIFIED BY ‘pwd‘ WITH GRANT OPTION

GRANT ALL PRIVILEGES ON mogilefs.* TO mogile@‘%‘ IDENTIFIED BY ‘pwd‘ WITH GRANT OPTION

退出mysql命令行,在linux shell上面输入如下命令,用于初始化mogilefs数据库。

mogdbsetup --dbhost=192.168.11.130 --dbport=3306 --dbrootuser=root --dbrootpass=pwd --dbuser=mogile --dbpass=pwd

初始化完毕之后,登录mysql,可以查看一下新建的数据库:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| demo               |
| mogilefs           |
| mysql              |
| performance_schema |
| solo               |
| test               |
| wp                 |
+--------------------+
8 rows in set (0.00 sec)

MariaDB [(none)]> use mogilefs
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mogilefs]> show tables;
+----------------------+
| Tables_in_mogilefs   |
+----------------------+
| checksum             |
| class                |
| device               |
| domain               |
| file                 |
| file_on              |
| file_on_corrupt      |
| file_to_delete       |
| file_to_delete2      |
| file_to_delete_later |
| file_to_queue        |
| file_to_replicate    |
| fsck_log             |
| host                 |
| server_settings      |
| tempfile             |
| unreachable_fids     |
+----------------------+
17 rows in set (0.00 sec)

初始化数据库完毕之后,我们需要提供让tracker和storage启动工作的启动脚本。其实,让tracker和storage工作的命令非常简单,如下所示:

启动tracker
su - mogilefs -c "/usr/local/bin/mogilefsd -c /etc/mogilefs/mogilefsd.conf --daemon"

启动storage
su - mogilefs -c "/usr/local/bin/mogstored -c $configfile --daemon"

将上述命令封装为mogilefsd和mogstored启动脚本,内容如下所示:

  1. mogilefsd启动脚本:

#!/bin/bash -x
#
# chkconfig: - 85 15
# description: MogileFS tracker 
# processname: mogilefsd
# config: /etc/mogilefs/mogilefsd.conf 
# pidfile: /home/mogilefs/mogilefsd.pid

. /etc/rc.d/init.d/functions

lockfile=${LOCKFILE-/var/lock/subsys/mogilefsd} 
RETVAL=0

pidfile=‘/home/mogilefs/mogilefsd.pid‘

start() { 
        ulimit -n 65535
        echo -n $"Starting mogilefsd"
        su - mogilefs -c "/usr/local/bin/mogilefsd -c         /etc/mogilefs/mogilefsd.conf --daemon" &> /dev/null
        RETVAL=$?
        [ $RETVAL = 0 ] && success && touch ${lockfile} &&         pidof /usr/local/bin/mogilefsd > $pidfile         || failure
        echo
        return $RETVAL
}

stop() {
        echo -n $"Stopping mogilefsd" 
        netstat -nlp|grep "mogilefsd"|grep -v grep|awk ‘{print $7}‘        |awk -F"/" ‘{print $1}‘|xargs kill -9 
        RETVAL=$?
        [ $RETVAL = 0 ] && success && rm -f ${lockfile} || failure
        echo
}

reload() {
        echo -n $"Reloading mogilefsd: " 
        killall mogilefsd -HUP 
        RETVAL=$?
        [ $RETVAL = 0 ] && success || failure
        echo
}

case "$1" in
        start) 
                start
                ;; 
        stop)
                stop
                ;; 
        status) 
                status mogilefsd 
                RETVAL=$?
                ;;
        restart)
                stop
                sleep 1
                start
                ;;
        reload)
                reload
                ;; 
        *) 
                echo $"Usage: mogilefsd {start|stop|restart|reload|status}" 
                exit 1
esac
exit $RETVAL
  1. mogstored启动脚本

#!/bin/bash -x
#
# chkconfig: - 86 14
# description: MogileFS storage 
# processname: mogstored
# config: /etc/mogilefs/mogstored.conf 
# pidfile: /home/mogilefs/mogstored.pid

. /etc/rc.d/init.d/functions

lockfile=${LOCKFILE-/var/lock/subsys/mogstored} 
RETVAL=0

configfile=‘/etc/mogilefs/mogstored.conf‘
pidfile=‘/home/mogilefs/mogstored.pid‘

prog=$(which mogstored)

start() { 
        ulimit -n 65535
        echo -n $"Starting mogstored"
        su - mogilefs -c "/usr/local/bin/mogstored         -c $configfile --daemon"  &> /dev/null
        RETVAL=$?
        [ $RETVAL = 0 ] && success && touch ${lockfile}         && pidof /usr/local/bin/mogstored > $pidfile || failure
        echo
        return $RETVAL
}

stop() {
        echo -n $"Stopping mogstored" 
        netstat -nlp|grep "mogstored"|grep -v grep|awk ‘{print $7}‘        |awk -F"/" ‘{print $1}‘|xargs kill -9 
        RETVAL=$?
        [ $RETVAL = 0 ] && success && rm -f ${lockfile} ${pidfile} || failure
        echo
}

reload() {
        echo -n $"Reloading mogstored: " 
        killall mogstored -HUP 
        RETVAL=$?
        [ $RETVAL = 0 ] && success || failure
        echo
}

case "$1" in
        start) 
                start
                ;; 
        stop)
                stop
                ;; 
        status) 
                status mogstored 
                RETVAL=$?
                ;;
        restart)
                stop
                sleep 1
                start
                ;;
        reload)
                reload
                ;; 
        *) 
                echo $"Usage: mogstored {start|stop|restart|reload|status}" 
                exit 1
esac
exit $RETVAL

在两台机器上面将mogilefsd和mogstored启动起来,从而完成初步的安装和配置工作。查看一下端口是否正常监听

systemctl start mogilefsd.service mogstored.service

ss -tnl | grep -iE "7001|7500"
LISTEN     0      128          *:7500                     *:*                  
LISTEN     0      128          *:7001                     *:*

Tracker和Storage的配置

首先查看一下MogileFS所提供的命令行工具:

mogadm        mogdbsetup    mogfetch      mogfileinfo   moglistfids   mogrename     mogstored     mogupload     mogautomount  mogdelete     mogfiledebug  mogilefsd     moglistkeys   mogstats      mogtool

可以通过查阅man手册或者命令行的help工具来探索他们的用法。这里不再做详细的综述。

  • 添加storage节点

MogileFS启动之后,利用mogadm命令做一下检测。指明tracker为192.168.11.130和192.168.11.132这两个节点。

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 check    
Checking trackers...
  192.168.11.130:7001 ... OK
  192.168.11.132:7001 ... OK

Checking hosts...
No devices found on tracker(s).

需要添加hosts,即storage节点。同样通过mogadm命令进行添加。将添加的storage节点分别命名为store1和store2。添加完毕之后分别利用check和host list子命令来查看状态,正常情况下可以看到storage节点已经添加完毕,并且状态为alive。

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 host add store1 --ip=192.168.11.130 --status=alive

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 host add store2 --ip=192.168.11.132 --status=alive 

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 check
Checking trackers...
  192.168.11.130:7001 ... OK
  192.168.11.132:7001 ... OK

Checking hosts...
  [ 1] store1 ... OK
  [ 2] store2 ... OK

Checking devices...
  host device         size(G)    used(G)    free(G)   use%   ob state   I/O%
  ---- ------------ ---------- ---------- ---------- ------ ---------- -----
  ---- ------------ ---------- ---------- ---------- ------
             total:     0.000      0.000      0.000   0.00%
$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 host list
store1 [1]: alive
  IP:       192.168.11.130:7500

store2 [2]: alive
  IP:       192.168.11.132:7500
  • 给Storage节点添加设备device

需要给每一个storage节点添加device设备,用于存放文件。我们需要在mogstored.conf里面定义的docroot目录下面,创建多个名称为dev1, dev2, dev3, ……这样名称的目录。一般对于服务器而言,这些目录应该作为专门用于存储的磁盘的挂载点。假设dev1下面挂载了/dev/sde1分区,而该分区的大小为600GB,则MogileFS会认为,dev1可以使用的可用空间就为600GB。当然,这些目录下面也可以不用挂载磁盘设备。假设dev1下面并没有挂载磁盘设备,则MogileFS识别到的对应于dev1的存储可用空间大小,为dev目录所在磁盘的可用空间大小,即如果dev1目录位于/dev/sda1磁盘分区上面,而/dev/sda1分区的可用空间为100GB,则MogileFS会认为,dev1可以使用的可用空间就是100GB。

在笔者的环境下,docroot定义为/mog_data,而该目录位于根分区,因此dev所可以使用的空间便为根分区的可用空间。

在storage节点1上面创建/mog_data/dev1目录,在storage节点2上面创建/mog_data/dev2目录,并都赋予mogilefs用户权限和mogilefs组权限:

storage节点1:
$ mkdir -pv /mog_data/dev1
$ chown mogilefs.mogilefs /mog_data/dev1


storage节点2:
$ mkdir -pv /mog_data/dev2
$ chown mogilefs.mogilefs /mog_data/dev2

通过mogadm的device add子命令,在storage节点1上面添加dev1,在storage节点2上面添加dev2。添加完毕之后,用device list子命令进行查看。正常情况下,可以看到store1和store2下面分别多出了dev1和dev2设备,以及dev1和dev2设备的可用情况。 
注:在添加的时候,dev1的节点编号为1,dev2的节点编号为2,以此类推,devn的节点编号为n

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 device add store1 1

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 device add store2 2

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 device list
store1 [1]: alive
                    used(G)    free(G)   total(G)  weight(%)
   dev1:   alive     13.327     10.640     23.967        100

store2 [2]: alive
                    used(G)    free(G)   total(G)  weight(%)
   dev2:   alive     13.327     10.640     23.967        100

于此同时,在两个节点的设备目录下面,也多出了一个名为usage的文件以及test-write文件夹。

  • 创建Domain

如本文之前所提到,MogileFS使用Domain来存放文件。每一个Domain的实例,管理了一组key-value的”元数据-数据”对象,可以创建一个Domain的实例,名称为file,用于专门存储文本文件;可以创建另一个Domain的实例,名称为imgs,用于专门存储图片文件。每一Domain实例下面的key代表了一个被存储的文件的元数据索引,对应着被存储的文件本身,即value。

下面添加一个Domain实例,命名为imgs,用于存储图片。利用mogadm的domain add子命令添加,并利用domain list子命令进行查看。

$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 domain add imgs
$ mogadm --trackers=192.168.11.130:7001,192.168.11.132:7001 domain list
 domain               class               mindevcount   replpolicy   hashtype
-------------------- -------------------- ------------- ------------ -------
 imgs                 default                   2        MultipleHosts() NONE

添加Domain完毕之后,我们向上述imgs这个Domain里面上传一张图片。通过mogupload命令进行上传,并通过mogfileinfo命令进行查看。正常情况下,可以看到上传的1.jpg的devcount为2,即数据成功保存为了两份,并且访问地址分别为http://192.168.11.130:7500/dev1/0/000/000/0000000004.fid以及http://192.168.11.132:7500/dev2/0/000/000/0000000004.fid。

$ mogupload --trackers=192.168.11.130:7001,192.168.11.132:7001 --domain=imgs --key=‘1.jpg‘ --file=‘/root/konachan.png‘

$ mogfileinfo --trackers=192.168.11.130:7001,192.168.11.132:7001 --domain=imgs --key=‘1.jpg‘
- file: 1.jpg
     class:              default
  devcount:                    2
    domain:                 imgs
       fid:                    4
       key:                1.jpg
    length:              2697564
 - http://192.168.11.130:7500/dev1/0/000/000/0000000004.fid
 - http://192.168.11.132:7500/dev2/0/000/000/0000000004.fid

在storage节点上面,我们也可以看到相应的文件路径:

storage节点1上面:
$ file /mog_data/dev1/0/000/000/0000000004.fid   
/mog_data/dev1/0/000/000/0000000004.fid: PNG image data, 1800 x 1111, 8-bit/color RGBA, non-interlaced


storage节点2上面:
$ file /mog_data/dev2/0/000/000/0000000004.fid 
/mog_data/dev2/0/000/000/0000000004.fid: PNG image data, 1800 x 1111, 8-bit/color RGBA, non-interlaced

通过Chrome浏览器,http访问上述两个图片资源:

技术分享

技术分享

至此,MogileFS的tracker,database,storage的配置初步结束。


Nginx添加mogilefs模块,作为MogileFS的前端反向代理

由上文所示,如果直接以fid形式对资源进行访问,则会带来一定的不便性。而Nginx的第三方模块mogilefs-module支持将Nginx作为tracker和storage的反向代理,使访问者只通过定义的key值便可以获取到指定的资源。

mogilefs的模块源代码在GitHub上面可以下载到。该源码的作者已经许久没有更新该模块了,笔者用Nginx1.12版本的Nginx通过静态编译的方式可以让其工作,但是还会遇到一些问题:

  1. 目前只能够通过静态编译的方式将该模块编译到nginx当中。从Nginx1.9版本开始,已经支持动态模块的装载与卸载。但是笔者将该模块的config文件修改为适合于动态编译的格式之后,加载模块启动Nginx的时候总会提示Segmentation fault,经过trace之后发现是该模块报了空指针的错误,解决方法目前尚未找到。

  2. 如果Nginx已经使用的其他的动态模块,再将mogilefs模块静态编译进入nginx之后,会造成部分动态模块也报Segmentation fault错误。目前已知的模块有http-echo-module, ajp-module。解决方法目前尚未找到。

  3. 针对该模块的mogilefs_methods指令,GET方法和DELETE方法经测试没有问题,但是PUT方法一直存在问题,开启nginx的debug模式,通过curl工具进行PUT操作时,在log里面存在upstream timed out (110: Connection timed out) while reading upstream错误,目前没有找到解决方法。

因此,笔者强烈建议,使用了mogilefs的nginx不要安装其他模块,而且该nginx只为了实现mogilefs的反向代理,不做其他功能。

将源码包下载之后,解压到任意路径(笔者这里将源码包解压到nginx1.12的源码目录里面)。在编译之前,先进入mogilefs的源码目录,修改ngx_http_mogilefs_modile.c源代码,找到ngx_http_mogilefs_create_spare_location函数,注释掉定义ngx_http_core_loc_conf_t的结构体指针*pclcf,注释掉pclcf指针的赋值语句。

修改完毕之后,可以进行编译了。在编译的时候,添加--add-module选项,指向mogilefs的源码目录即可。

编译安装Nginx完毕之后,在配置文件里面添加如下内容,笔者使用7010端口作为Nginx反向代理mogilefs的端口,并且定义一个trackers的upstream服务器组,使用nginx默认的wrr轮询调度算法。定义mogilefs的domain为之前创建的imgs,

upstream trackers {
        server 192.168.11.130:7001;
        server 192.168.11.132:7001;
}
server {
        listen 7010;
        location / {
                mogilefs_tracker trackers;
                mogilefs_domain imgs;
                mogilefs_methods get delete;

                mogilefs_pass {
                        proxy_pass $mogilefs_path;
                        proxy_hide_header Content-Type;
                        proxy_buffering off;
                }
        }
}

编辑完毕之后,启动或者重启nginx进程,通过http://192.168.5.178:7010/1.jpg这个地址来访问之前上传的图片:

技术分享



一些总结

MogileFS是基于Perl语言研发的一款优秀的分布式文件系统,对于海量小文件的存储有着很大的优势,但是由于在新的CentOS7上面的模块兼容性问题,以及Nginx插件的老化问题,使得mogilefs渐渐被新的分布式文件系统所代替,诸如FastDFS,Ceph,SeaweedFS等产品。当然,笔者能力有限,在部署时所遇到的问题并未能够解决,如果有所进展,则会及时更新博文。

本文出自 “技术成就梦想” 博客,请务必保留此出处http://jiangche00.blog.51cto.com/4377920/1950261

MogileFS + Nginx 实现基于CentOS7平台的分布式文件存储与访问