分布式存储MogileFS应用

分布式存储MogileFS是一个典型的分布式系统,由调度节点和存储节点组成,因为调度节点和存储节点藕和性低,所以调度节点和存储节点可以放在同一台主机上面,调度节点需要关系型数据库来存储key和value,所有的资源请求和上传都交由调度节点,由调度节点返回应该去哪获取和应该存储到哪,调度节点还会各调度存储节点将数据存储多份。存储在不同的节点上面,防止单点故障。

特性:

1.Server端:分tracker和mogstore节点。tracker存储数据的元数据,数据存放在关系型数据库,mogstore存储真实数据。Client都会向tracker发送key,由tracker通过查询数据库,得出key对应的Value,并发送给Client,然后Client再照着Value去取。

2.Client端:通过mogileFS API调用MogileFS。MogileFS准确来说并不是分布式文件系统,它可以叫做分布式存储,因为其不能被挂载使用,只能通过API进行调用。当然,MogileFS是可以通过额外扩展进行挂载使用的

3.utils: 管理工具

因为Server端的服务都是以Daemon的形式运行,耦合性又低,所以所谓的节点都可以运行在一个服务器上面,比如我后面要实现的架构

Tracker:

转换成抽象的架构图就为:

前端由Nginx做反代。通过MogileFS API对后端MogileFS Cluster进行调用。而为了防止Nginx自身成为单点故障点,所以需要对Nginx做高可用,不过这里我并没有去实现,有需要的朋友可以往后面翻,后面有多篇对Service进行高可用的实现方案。后端DB Server也是单点故障点,所以也需要对其进行高可用,Mariadb和MySQL基本一致,高可用方案也可以往后面翻。这里主要实现MogileFS,对其他只需要能使用就行。

这就是完整的数据获取过程。

我们现在开始搭建MogfileFS。

安装:

Source: https://github.com/mogilefs cpan:https://metacpan.org/search?q=mogilefs

安装方法:

# yum -y install make gcc unzip perl-DBD-MySQL perl perl-CPAN perl-YAML perl-Time-HiRes
# cpan           //使用cpan进行安装
cpan[1]> install App::cpanminus 
cpan[1]> install  MogileFS::Server 
cpan[1]> install  MogileFS::Utils 
cpan[1]> install  IO::AIO 
cpan[1]> install  IO::WrapTie 
cpan[1]> install  Danga::Socket

or

# perl Makefile.PL   //相当于./configure
# make
# make test          //这步可要可不要
# make install 

# useradd mogilefs    //因为MogilfeFS并没有使用1024以下端口,所以mogilefs只需要普通用户就行

mogilefsd服务脚本:

#!/bin/bash
#
# mogilefsd - Startup script for the MogileFS tracker
#
# chkconfig: - 85 15
# description: MogileFS tracker 
# processname: mogilefsd
# config: /etc/mogilefs/mogilefsd.conf 
# pidfile: /var/run/mogilefsd/mogilefsd.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Path to the apachectl script, server binary, and short-form for messages.
lockfile=${LOCKFILE-/var/lock/subsys/mogilefsd} 
RETVAL=0

prog=$(which mogilefsd)

start() { 
    ulimit -n 65535
    echo -n $"Starting mogilefsd"
    su - mogilefs -c "$prog -c /etc/mogilefs/mogilefsd.conf --daemon" 
    RETVAL=$?
    [ $RETVAL = 0 ] && success && touch ${lockfile} || 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
#
# mogstored - Startup script for the MogileFS storage
#
# chkconfig: - 86 14
# description: MogileFS storage 
# processname: mogstored
# config: /etc/mogilefs/mogstored.conf 
# pidfile: /var/run/mogilefsd/mogstored.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Path to the apachectl script, server binary, and short-form for messages.
lockfile=${LOCKFILE-/var/lock/subsys/mogstored} 
RETVAL=0

configfile='/etc/mogilefs/mogstored.conf'

prog=$(which mogstored)

start() { 
    ulimit -n 65535
    echo -n $"Starting mogstored"
    su - mogilefs -c "$prog -c $configfile --daemon"  &> /dev/null
    RETVAL=$?
    [ $RETVAL = 0 ] && success && touch ${lockfile} || 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} || 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

安装数据库

# yum -y install mysql-server mysql
# service mysqld start

tracker初始化

# mogdbsetup -h
 --dbhost=   //数据库IP or Hostname
 --dbport=   //不指定默认使用数据库默认端口
 --dbname=       //指定MogileFS数据库名字,不指定默认为mogilefs
 --dbrootuser=
 --dbrootpass=   //不指定默认为空 
 --dbuser=       //指定MogileFS数据库管理用户名字,不指定默认为mogile
 --dbpass=       //指定MogileFS数据库管理用户密码,不指定默认为空
  --type=        //数据库类型。默认MySQL
  --yes          //设定这个选项所[yes/no]选项全部自动填yes

# mogdbsetup --dbhost=192.168.100.201 \   //数据选项
> --dbname=mogdb \   
> --dbrootuser=root \
> --dbuser=moguser \
> --dbpass=mogpass \
> --yes
//如果报错请自行创建用户,创建库名。再进行使用mogdbsetup创建表名
# mysql
mysql> SHOW TABLES;
+----------------------+
| Tables_in_mogdb      |
+----------------------+
| 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     |
+----------------------+
//自动创建的各表

配置tracker:

# vim /etc/mogilefs/mogilefsd.conf 
daemonize = 1    //是否以服务的方式运行
pidfile = /var/run/mogilefsd/mogilefsd.pid
db_dsn = DBI:mysql:mogdb:host=192.168.100.201   //mysql数据库,mogdb库,mysql server ip为192.168.100.201
db_user = moguser
db_pass = mogpass
listen = 0.0.0.0:7001       //0.0.0.0表示监听所有地址
conf_port = 7001
query_jobs = 30         //查询线程数
delete_jobs = 2         //删除线程数
replicate_jobs = 5      //复制线程数
# service mogilefsd start

配置store:

# vim /etc/mogilefs/mogstored.conf
maxconns = 10000            //最大连接请求数
httplisten = 0.0.0.0:7500   //http监听端口
mgmtlisten = 0.0.0.0:7501
docroot = /mogfs/mogdata    //数据存放目录(下面建立设备目录。让磁盘挂载)
# mkdir -pv  /mogfs/mogdata
# chown -R mogilefs.mogilefs /mogfs/mogdata
# service mogstored start

不同的store节点上面可以挂载一个或者多个devied。所有的devied组合起来成为一个大空间。在上面创建domain。比如存放图片的就叫做images,再在上面创建class,class是MogileFS的传输备份单位,MogileFS不会每次都将一个1K的数据单独用一个线程进行传输,他是用一个class作为单位,class里面只有1k的话,当然也需要传输,但是class建议不要大于64M。因为MogileFS的block大小就为64M。再大就需要切开传输了

Domain:

Class

通过Fid+Domain来定位文件

mogadm使用方法:

host模块:
    查看
    # mogadm --trackers=192.168.100.201:7001 host list
    添加store主机:
    # mogadm --trackers=192.168.100.201:7001 host add 192.168.100.201 --ip=192.168.100.201 --status=alive --port=7500

    or

    # mogadm --trackers=192.168.100.201:7001 host add node3 --ip=192.168.100.203 --status=alive --port=7500

device模块:
    查看
    # mogadm --trackers=192.168.100.201:7001 device list

    添加store device:
        store# mkdir /mogfs/mogdata/dev1
        store#  chown -R mogilefs.mogilefs /mogfs/mogdata

    # mogadm --trackers=192.168.100.201:7001 device add 192.168.100.202 001  //001为设备ID号,建议和dev1对应起来

    如果是闲添加的device,后面再创建dev文件夹,然后查看的时候不显示:
                            1.重启对应设备所在机器的mogstored
                            2.删除device,再创建(建议。)

domin模块:
    查看
    # mogadm --trackers=192.168.100.201:7001 domain list
    添加domian:
    # mogadm --trackers=192.168.100.201:7001 domain add images
    # mogadm --trackers=192.168.100.201:7001 domain add text

class模块:
    查看
    # mogadm --trackers=192.168.100.201:7001 class list
    添加:
    # mogadm --trackers=192.168.100.201:7001 class add text text1


other:

上传
# mogupload --trackers=192.168.100.201:7001 --domain=images --key='/test.png' --file='/usr/share/backgrounds/default_1920x1440.png'

下载:
# mogfetch --trackers=192.168.100.201:7001 --domain=images --key='/test.png' --file='/tmp/test.png'
# ls /tmp/test.png 
/tmp/test.png

查看key值:
# mogfileinfo --trackers=192.168.100.201:7001 --domain=images --key="/test.png"
- file: /test.png
     class:              default
  devcount:                    2
    domain:               images
       fid:                    4
       key:            /test.png
    length:              1756831
 - http://192.168.100.202:7500/dev2/0/000/000/0000000004.fid
 - http://192.168.100.203:7500/dev3/0/000/000/0000000004.fid

我就是按照这种方式部署的:

我们需要在tracker节点上面添加所有的三个stroe节点

//192.168.100.201 or 192.168.100.202 上面都运行由tracker,都可以运行下面的命令
# mogadm --trackers=192.168.100.201:7001 host add 192.168.100.201 --ip=192.168.100.201 --status=alive --port=7500
# mogadm --trackers=192.168.100.201:7001 host add 192.168.100.2012--ip=192.168.100.202 --status=alive --port=7500
# mogadm --trackers=192.168.100.201:7001 host add node3 --ip=192.168.100.203 --status=alive --port=7500
//除了--status=alive如果不指定默认为down之外,其他都没啥好解释的

这个时候可以换另一个节点看效果

可以看到因为我们之前设置的node3,所以上面显示也是node3.

添加device:在节点1的/mogfs/mogdata/下面创建dev1,在节点2的创建dev2,在节点3创建dev3,如果是生产环境这个地方还需要挂载硬盘。然后将属主属组改成mogilefs

# mkdir /mogfs/mogdata/dev1
# mount /dev/sdb1 /mogfs/mogdata/dev1
# chown -R mogilefs.mogilefs /mogfs/mogdata

这个时候就可以在tracker节点为store添加device了:

# mogadm --tracker=192.168.100.202:7001 device add 192.168.100.201 001
# mogadm --tracker=192.168.100.202:7001 device add 192.168.100.202 002
# mogadm --tracker=192.168.100.202:7001 device add 192.168.100.203 003

创建domain

# mogadm --tracker=192.168.100.202:7001 domain add images
# mogadm --tracker=192.168.100.202:7001 domain add text

创建class

# mogadm --tracker=192.168.100.202:7001 class add
      --hashtype=s         //指定hash算法
      --mindevcount=i      //指定备份次数

# mogadm --tracker=192.168.100.202:7001 class images img1
# mogadm --tracker=192.168.100.202:7001 class text text1

上传一个文件

# mogupload --trackers=192.168.100.201:7001 --domain=images --key='/test.png' --file='/usr/share/backgrounds/default_1920x1440.png'

查看其状态和value

# mogfileinfo --trackers=192.168.100.201:7001 --domain=images --key="/test.png"
- file: /test.png           
     class:              default      
  devcount:                    2     //备份次数
    domain:               images
       fid:                    4
       key:            /test.png
    length:              1756831
 - http://192.168.100.202:7500/dev2/0/000/000/0000000004.fid
 - http://192.168.100.203:7500/dev3/0/000/000/0000000004.fid
//从后门这个value就可以看出这个文件被备份了2份,一份在202的dev2上面,一份在203的dev3上面

可以直接用浏览器访问value访问到文件,也就证明了Store是支持GET请求的。其实它就是一个Web Service,不过是webDAV而已

Nginx安装和配置

Nginx安装:

//需要下载nginx_mogilefs_module-1.0.4.tar.gz
# tar xf nginx-1.10.1.tar.gz
# tar xf nginx_mogilefs_module-1.0.4.tar.gz
# cd nginx-1.10.1.tar.gz
# ./configure  --add-module=/path/to/nginx_mogilefs_module-1.0.4  
//编译安装添加此模块需要指定nginx_mogilefs_module-1.0.4 的路径,Nginx其他安装参数情自行配置
# make && make  install

Nginx配置:

//在Nginx配置中添加上如下项
http {
    upstream mogilefs {
        server 192.168.100.201:7001;
        server 192.168.100.202:7001;
    }

    location /text/ {
            mogilefs_tracker mogilefs;
            mogilefs_domain text;      

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

        location /images/ {
            mogilefs_tracker mogilefs;
            mogilefs_domain images;

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

文字测试页面请自行提供

上面配置的Nginx在转发的时候会把192.168.100.20/text/index.html 中的/index.html当key,如果像让/text/index.html当key,就需要更改下面几项

http {
    upstream mogilefs {
        server 192.168.100.201:7001;
        server 192.168.100.202:7001;
    }

    location ~* ^(/text/.*)$ {     //更改位置1
            mogilefs_tracker mogilefs;
            mogilefs_domain text;      

           mogilefs_pass $1 {    //更改位置2
             proxy_pass $mogilefs_path;
             proxy_hide_header Content-Type;
             proxy_buffering off;
           }
        }

        location ~* ^(/images/.*)$ {
            mogilefs_tracker mogilefs;
            mogilefs_domain images;

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

好了,MogileFS的应用到这里就差不多了,Nginx的HA和MySQL的Master-Slaver都没有去实现,有兴趣或者由需要的朋友都可以去试试。实现起来都比较简单。