hx0011yy 发表于 2019-2-1 08:28:01

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

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


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

[*]  MogileFS属于有中心节点形式的分布式文件系统,元数据默认存储在关系型数据库(MySQL)当中,在此处于单点,因此有必要对MySQL使用主从复制或者MHA。
[*]  按功能分为tracker,database,storage。其中tracker负责对于元数据信息进行管理,对整个MogileFS系统进行协调监控。其中database负责存储tracker所管理的元数据。其中storage负责存储数据文件。
[*]  MogileFS依赖于perbal作为代理,一方面接收客户端的请求并将其发送至tracker进行检索,一方面接收tracker的检索结果并向storage发送获取请求,另一方面接收storage的响应并且传递给客户端所请求的内容。
[*]  亦可以使用Nginx作为代理,不过需要对原生的Nginx安装mogilefs的模块(或者称为打上mogilefs的补丁)
MogileFS管理文件的一些概念
[*]  Domain: 一个MogileFS可以有多个Domain,用来存放不同文件(大小,类型),同一个Domain内key必须为一,不同Domain内,key可以相同。
[*]  Class:文件属性管理,定位文件存储在不同设备上面的份数。
[*]  每一个storage称为一个主机,一个主机上可以有多个存储设备(单独的硬盘),每个设备都有ID号,Domain+Fid用来定位文件。
MogileFS各个功能组件的交互图示https://s2.运维网.com/wyfs02/M00/9C/B0/wKioL1l0rPfickOUAAGd8Uuyx2Y873.png-wh_500x0-wm_3-wmp_4-s_2412988641.png



[*]  MogileFS针对客户端请求的工作流程图
https://s5.运维网.com/wyfs02/M01/9C/B0/wKioL1l0rRSDJK0hAAKiZhlsERw180.png-wh_500x0-wm_3-wmp_4-s_3616026712.png

[*]  MogileFS搭建环境拓扑结构
笔者的拓扑结构如下图所示。其中一台Nginx作为反向代理,用于代理用户的客户端请求。两个tracker,两个storage,一个database。这里,笔者将一组tracker + storage + database部署在一台机器上面,将另一组tracker + storage部署在另一台机器上面。
https://s4.运维网.com/wyfs02/M02/9C/B0/wKioL1l0rT3TXln-AABDJXZseMA503.png-wh_500x0-wm_3-wmp_4-s_2683601085.png
初始安装及初始配置
MogileFS是基于Perl语言构建的项目,因此需要从CPAN上面下载MogileFS的模块,因此需要保证被部署的机器能够直接或者通过代理连接至互联网,如果无法联网,则需要梳理模块的依赖关系,通过其他途径下载所有所需要的perl的模块,并且手工编译安装。
首先,在两台机器上面安装cpanm工具,用于安装模块:
wget http://xrl.us/cpanm -O /usr/bin/cpanm; sudo chmod +x /usr/bin/cpanmcpanm安装完毕之后,在两台机器上面安装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/mogilefsmogilefsd.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 = 1mogstored.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 > 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启动脚本,内容如下所示:

[*]  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
[*]  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   mogautomountmogdelete   mogfiledebugmogilefsd   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 : alive
IP:       192.168.11.130:7500
store2 : 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 : alive
                  used(G)    free(G)   total(G)weight(%)
   dev1:   alive   13.327   10.640   23.967      100
store2 : 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访问上述两个图片资源:
https://s3.运维网.com/wyfs02/M01/9C/B0/wKioL1l0rbzSN_A0ABVkOxX7l28085.png-wh_500x0-wm_3-wmp_4-s_1437808344.png
https://s2.运维网.com/wyfs02/M01/9C/B0/wKiom1l0rdrR8gwRABVkJFNoZFA401.png-wh_500x0-wm_3-wmp_4-s_13817767.png
至此,MogileFS的tracker,database,storage的配置初步结束。
Nginx添加mogilefs模块,作为MogileFS的前端反向代理
由上文所示,如果直接以fid形式对资源进行访问,则会带来一定的不便性。而Nginx的第三方模块mogilefs-module支持将Nginx作为tracker和storage的反向代理,使访问者只通过定义的key值便可以获取到指定的资源。
mogilefs的模块源代码在GitHub上面可以下载到。该源码的作者已经许久没有更新该模块了,笔者用Nginx1.12版本的Nginx通过静态编译的方式可以让其工作,但是还会遇到一些问题:

[*]  目前只能够通过静态编译的方式将该模块编译到nginx当中。从Nginx1.9版本开始,已经支持动态模块的装载与卸载。但是笔者将该模块的config文件修改为适合于动态编译的格式之后,加载模块启动Nginx的时候总会提示Segmentation fault,经过trace之后发现是该模块报了空指针的错误,解决方法目前尚未找到。
[*]  如果Nginx已经使用的其他的动态模块,再将mogilefs模块静态编译进入nginx之后,会造成部分动态模块也报Segmentation fault错误。目前已知的模块有http-echo-module, ajp-module。解决方法目前尚未找到。
[*]  针对该模块的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这个地址来访问之前上传的图片:
https://s4.运维网.com/wyfs02/M02/9C/B0/wKioL1l0riHySAxoABUy5rqX8bk633.png-wh_500x0-wm_3-wmp_4-s_3177585845.png
  

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



页: [1]
查看完整版本: MogileFS + Nginx 实现基于CentOS7平台的分布式文件存储与访问