分布式存储MogileFS是一个典型的分布式系统,由调度节点和存储节点组成,因为调度节点和存储节点藕和性低,所以调度节点和存储节点可以放在同一台主机上面,调度节点需要关系型数据库来存储key和value,所有的资源请求和上传都交由调度节点,由调度节点返回应该去哪获取和应该存储到哪,调度节点还会各调度存储节点将数据存储多份。存储在不同的节点上面,防止单点故障。
特性:
- 1.应用层协议提供服务。
- 2.无单点
- 3.自动文件复制:复制的最小单位不是文件,而是class
- 4.传输中立:可以通过NFS或HTTP实现通信
- 5.简单命名空间:没有目录,直接存在存储空间上,通过domain隔离
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:
- MogileFS的核心,是一个调度器,服务进程为mogilefsd,职责:删除数据、复制数据、监控、查询等
-
基于事件驱动模型工作:一个进程生成多个线程(子进程),一个子进程负责响应多个请求。
mogstored:
- 数据存储的位置,通常是一个HTTP(webDAV)服务器,用来做数据的创建(put)、删除(delete)、获取(get),监听端口7500
转换成抽象的架构图就为:
前端由Nginx做反代。通过MogileFS API对后端MogileFS Cluster进行调用。而为了防止Nginx自身成为单点故障点,所以需要对Nginx做高可用,不过这里我并没有去实现,有需要的朋友可以往后面翻,后面有多篇对Service进行高可用的实现方案。后端DB Server也是单点故障点,所以也需要对其进行高可用,Mariadb和MySQL基本一致,高可用方案也可以往后面翻。这里主要实现MogileFS,对其他只需要能使用就行。
- 1.Nginx通过MogileFS API向tracker请求index.html页面
- 2.tarcker向DB Server发起查询
- 3.tracker将以index.html为key查询到的value的值发给Nginx
- 4.Nginx通过MogileFS API向store请求数据
这就是完整的数据获取过程。
我们现在开始搭建MogfileFS。
安装:
Source: https://github.com/mogilefs
cpan:https://metacpan.org/search?q=mogilefs
- MogileFS-Server: tracker&store
- perl-MogileFS-Client: MogileFS API
- MogileFS-Utils: Utils
安装方法:
# 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:
- 一个MogileFS可以有多个Domian
- 用来存放不同的文件(大小,类型)
- 同一个Domain内,key必须唯一
- 不同Domain,key可以相同
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都没有去实现,有兴趣或者由需要的朋友都可以去试试。实现起来都比较简单。