一、关于MogileFS
二、常见分布式文件系统
三、MogileFS基本原理
四、MogileFS的实现
一、关于MogileFS
当下我们处在一个互联网飞速发展的信息社会,在海量并发连接的驱动下每天所产生的数据量必然以几何方式增长,随着信息连接方式日益多样化,数据存储的结构也随着发生了变化。在这样的压力下使得人们不得不重新审视大量数据的存储所带来的挑战,例如:数据采集、数据存储、数据搜索、数据共享、数据传输、数据分析、数据可视化等一系列问题。传统存储在面对海量数据存储表现出的力不从心已经是不争的事实,例如:纵向扩展受阵列空间限制、横向扩展受交换设备限制、节点受文件系统限制。
然而分布式存储的出现在一定程度上有效的缓解了这一问题,之所以称之为缓解是因为分布式存储在面对海量数据存储时也并非十全十美毫无压力,依然存在的难点与挑战例如:节点间通信、数据存储、数据空间平衡、容错、文件系统支持等一系列问题仍处在不断摸索和完善中。
* 一致性(Consistency)---所有节点在同一时间具有相同的数据
* 可用性(Availability)---保证每个请求不管成功或者失败都有响应
* 分隔容忍(Partition tolerance)---系统中任意信息的丢失或失败不会影响系统的继续运作
根据定理,分布式系统只能满足三项中的两项而不可能满足全部三项。
对于大型站点,可用性(Availability)与分隔容错性(Partition Tolerance)的优先级会高于一致性(Consistency),这里并不是指完全舍弃一致性,而是通过其他手段实现数据的弱一致性,例如:用户微博的浏览数和评论可以容忍相对长时间的不一致,几乎不会影响用户体验,而股票价格的数据则异常敏感,即便是10秒钟的数据不一致也无法容忍下面列出了"各种一致性".强一致性
ACID
在单机环境中,强一致性可以由数据库的事务来保证
在多级环境中,强一致性很难做到
分布式事务:性能太差,在化联网的应用中不适合
弱一致性(包括最终一致性)
通过提交处理的半同步、半异步或全异步,取得最终一致性效果
最终一致性使得数据的提交具有延时性,而在一定范围时的延时性范围内(比如一秒),应用的可用性时正常的
集群内一致性算法实施过程案例
基于合法票数(Quorum)和向量时钟(Vector Clock)
Quorum算法:
N :数据复制的节点量
R :成功读取所依赖的最少节点数
W :成功写操作所依赖的最少节点数
W+R>N 表示强一致性 ;W+R<=N 属于弱一致性(保证最终一致性)
二、常见分布式存储文件系统
Google Filesystem | GFS+MapReduce擅长处理单个大文件 |
Hadoop Distributed Filesystem | GFS的山寨版+MapReduce,擅长处理单个大文件 |
ClusterFS | 擅长处理单个大文件 |
Taobao Filesystem | 擅长处理海量小文件 |
MogileFS | 擅长处理海量小文件 |
Ceph | PB级别的分布式文件系统 |
MooseFS | 通用简便,适用于研发能力不强的公司 |
Lustre | 一种平行分布式文件系统 |
MogileFS是一个开源的分布式文件系统,用于组建分布式文件集群,由LiveJournal旗下DangaInteractive公司开发,Danga团队开发了包括 Memcached、MogileFS、Perlbal等不错的开源项目:(注:Perlbal是一个强大的Perl写的反向代理服务器)。MogileFS是一个开源的分布式文件系统。主要特性包括:应用层的组件、无单点故障、自动文件复制、具有比RAID更好的可靠性、无需RAID支持等……核心角色如下:
tracker节点:MgileFS的核心,借助数据库保存各节点文件的元数据信息保存每个域中所有键的存储位置分布,方便检索定位数据位置的同时监控各节点,告诉客户端存储区位置并指挥storage节点复制数据副本,服务进程名为mogilefsd(7001);除此之外它还负责数据的删除、复制、监控、查询等、可以作为负载均衡.
database节点:为tracker节点提供数据存取服务。
storage节点:数据存储的位置、将指定域中的键转换为其特有的文件名存储在指定的设备文件中,转换后的文件名为值,storage节点自动维护键值的对应关系,storage节点由于使用http进行数据传输,因此依赖于perlbal,storage节点前端可以使用nginx进行反向代理,但需要安装nginx-mogilefs-module-master模块进行名称转换,进程名mogstored(7501),perbal(7500)。
▲MogileFS管理的几个概念:
1、Domain:一个MogileFS可以有多个Domain,用来存放不同文件(大小,类型),同一个Domain内key必须为一,不同Domain内,key可以相同;
2、每一个存储节点称为一个主机,一个主机上可以有多个存储设备(单独的硬盘),每个设备都有ID号,Domain+Fid用来定位文件。
3、Class:文件属性管理,定位文件存储在不同设备上的份数;
Client libray、tracker、Database、mogstore的关系图 |
MofileFS工作流程图 |
四、MogileFS的实现
2)Nginx根据反向代理+负载均衡机制随机代理到后端Tracker(node1)(任意一台)。
3)Tracker(node1)向mysql服务器发起查询请求。
4)mysql服务器返回查询结果给Tracker(node1)。
5)Tracker(node1)将查询结果返回给Nginx。
6)Nginx将查询结果根据模块转换为合理的url发送给后端的Storage存储服务器(node3)。
7)Storage存储服务器(node3)将文件内容通过http协议返回给Nginx。
8)Nginx将结果返回给应用层的请求。
说明:大家一眼就可以看出来这个拓扑规划的缺陷,首先是前端nginx代理服务器单点故障所在处、如果高并发的情况下一台根本就支撑不了,此时前端可以考虑Nginx+keepalived或者是Haproxy+keepalived,其次是后端的mysql,就算前端一台nginx支撑得了,但是读写操作都压在了一台mysql上面,很明显mysql就需要扩展了,构建主从的架构适宜,最后的Tracker和Storage完全可以在一台主机上运行,他们之间没有任何影响;但是本文的重点在于如何去部署一个MogileFS的应用场景,其他并未考虑,请各位朋友不要误解!
2.实验步骤:
MariaDB [(none)]> use mysql #删除有安全隐患的账户 MariaDB [mysql]> DELETE FROM user WHERE host = '::1'; MariaDB [mysql]> DELETE FROM user WHERE user = ''; #授权root用户能远程登录 MariaDB [mysql]> GRANT ALL ON *.* TO 'root'@'172.16.%.%' IDENTIFIED BY '123.com' #授权moguser用户 MariaDB [mysql]> GRANT ALL ON mogdb.* TO 'moguser'@'172.16.%.%' IDENTIFIED BY '123.com'; #刷新授权表 MariaDB [mysql]> FLUSH PRIVILEGES;
#→下面三个是Tracker和Storage端必装的程序包. MogileFS-Server-2.46-2.el6.noarch.rpm MogileFS-Server-mogilefsd-2.46-2.el6.noarch.rpm MogileFS-Server-mogstored-2.46-2.el6.noarch.rpm #→这是在维护MogileFS时使用的工具包 MogileFS-Utils-2.19-1.el6.noarch.rpm #→MogileFS客户端程序 perl-MogileFS-Client-1.14-1.el6.noarch.rpm #→这个软件包是在跨网络或者跨机房是所使用的包 perl-Net-Netmask-1.9015-8.el6.noarch.rpm #→这是用perl所编写的web程序,它是在mostored上提供webDAV的方式接受客户web服务请求的. perl-Perlbal-1.78-1.el6.noarch.rpm #这是perl程序所依赖的包 perl-IO-AIO.x86_64 #→说明如果在配置安装过程当中遇依赖关系时,解决就行了. #→然后将几个软件包都拷贝至其它两个节点上. [root@node1 ~]# scp *.rpm 172.16.41.2:/root/ [root@node1 ~]# scp *.rpm 172.16.41.3:/root/
[root@node1 ~]# yum install *.rpm perl-IO-AIO #→其他两个节点的安装过程在node1上面的一样.
(3)配置node1.example.com
#→安装好tracker后会在/var/run/下面生成该目录,改变目录属主.属组 [root@node1 ~]# chown -R mogilefs.mogilefs /var/run/mogilefsd
[root@node1 ~]# mogdbsetup --dbrootuser=root --dbname=mogdb --dbhost=172.16.41.5 --dbport=3306 --dbrootpass=123.com --dbuser=moguser --dbpass=123.com --yes
<3>验证初始化数据库结果:
<4>修改tracker配置文件,如下内容:
[root@node1 ~]# vim /etc/mogilefs/mogilefsd.conf #→修改下面4项即可其它参数根据工作环境自定 db_dsn = DBI:mysql:mogdb:host=172.16.41.5 db_user = moguser db_pass = 123.com listen = 172.16.41.1:7001
<5>修改storage配置文件,如下内容:
[root@node1 ~]# vim /etc/mogilefs/mogstored.conf maxconns = 10000 #→存储系统的最大连接数. httplisten = 0.0.0.0:7500 #→这个就是webDAV服务使用的端口,但是这里我们不知使用它. mgmtlisten = 0.0.0.0:7501 #→mogilefs的管理端口. docroot = /data/mogdata #→该项决定了数据的在storage上存储的实际位置,建议使用的是一个单独挂载使用的磁盘.这里我就不用演示了. [root@node1 ~]# mkdir -p /data/mydata/dev1 #→这里一定要改变数据存放目录的属主属组,应为mogilefs服务程序必须是以普通用户来运行的,否则服务启动将失败! [root@node1 ~]# chown -R mogilefs.mogilefs /data/mogdata/dev1
<6>启动tracker和storage服务:
[root@node2 ~]# service mogilefsd start Starting mogilefsd [ OK ] [root@node2 ~]# service mogstored start Starting mogstored [ OK ] [root@node2 ~]#
<7>在node1上面将自己添加mogstore存储主机
[root@node1 ~]# mogadm --trackers=172.16.41.1:7001 host add 172.16.41.1 --ip=172.16.41.1 --status=alive
下面继续配置:
<8>现将两个配置文件拷贝至两个节点中--要保证各个程序包都已经安装了,否则在拷贝后安装会覆盖两个配置文件.
[root@node1 ~]# scp /etc/mogilefs/* 172.16.41.2:/etc/mogilefs/ mogilefsd.conf 100% 1462 1.4KB/s 00:00 mogstored.conf 100% 93 0.1KB/s 00:00 [root@node1 ~]# scp /etc/mogilefs/* 172.16.41.3:/etc/mogilefs/ mogilefsd.conf 100% 1462 1.4KB/s 00:00 mogstored.conf 100% 93 0.1KB/s 00:00 [root@node1 ~]#
(4)配置node2.example.com
<1>程序包已经安装
<2>设定数据库已经完毕,该节点与node3节点无需重复此操作
<3>配置tracker.
#→安装好tracker后会在/var/run/下面生成该目录,改变目录属主.属组 [root@node2 ~]# chown -R mogilefs.mogilefs /var/run/mogilefsd
<4>修改tracker配置文件,如下内容:
[root@node2 ~]# vim /etc/mogilefs/mogilefsd.conf #→修改下面4项即可其它参数根据工作环境自定 db_dsn = DBI:mysql:mogdb:host=172.16.41.5 db_user = moguser db_pass = 123.com listen = 172.16.41.2:7001
<5>修改storage配置文件,如下内容:
[root@node2 ~]# vim /etc/mogilefs/mogstored.conf maxconns = 10000 httplisten = 0.0.0.0:7500 mgmtlisten = 0.0.0.0:7501 docroot = /data/mogdata#→该项决定了数据的在storage上存储的实际位置,建议使用的是一个单独挂载使用的磁盘.这里我就不用演示了. [root@node2 ~]# mkdir -p /data/mydata/dev2 #→这里一定要改变数据存放目录的属主属组,应为mogilefs服务程序必须是以普通用户来运行的,否则服务启动将失败! [root@node2 ~]# chown -R mogilefs.mogilefs /data/mogdata/dev2
<6>启动tracker和storage服务:
[root@node2 ~]# service mogilefsd start Starting mogilefsd [ OK ] [root@node2 ~]# service mogstored start Starting mogstored [ OK ] [root@node2 ~]#
[root@node2 ~]# mogadm --trackers=172.16.41.2:7001 host add 172.16.41.2 --ip=172.16.41.2 --status=alive
此时两个节点都加入到了MogileFS系统中,第三个节点配置与第二个一样,只是配置文件修改一下即可,这里不在赘述!
下面就可以在node1节点上控制其他两个节点即可!
(5)管理配置MogileFS集群系统
#→添加的第一个设备,设备号不能重名 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 device add 172.16.41.1 1 #→添加的第二个设备 [root@node1 ~]# mogadm --trackers=172.16.41.2:7001 device add 172.16.41.2 2 #→添加的第三个设备 [root@node1 ~]# mogadm --trackers=172.16.41.3:7001 device add 172.16.41.3 3 [root@node1 ~]# mogadm --trackers=172.16.41.3:7001 device list
<2>添加域domain-----域用来存储不同应用类型的数据的容器
#→创建的图片存放域 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 domain add p_w_picpaths #→创建的html等文件存放域 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 domain add files [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 domain list
<3>添加类class
[root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class add p_w_picpaths class0 --mindevcount=2 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class add p_w_picpaths class1 --mindevcount=2 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class add p_w_picpaths class3 --mindevcount=2 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class add files class0 --mindevcount=2 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class add files class1 --mindevcount=2 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class add files class2 --mindevcount=2 [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 class list
这里再次提一下关于这两个概念
域(domain)
在一个 MogileFS 中,可以有多个域,用来存放不同的文件,比如,不同大小的文件,不同类型的文件.在上图中所有 alive 的"设备"是一个大的整体,形成一个统一的存储空间,里面的数据可以根据 "域" domain 和类 class 来分类管理,属于同一个 domain,即使是属于不同的class,文件的key也必须是唯一的.不同域的 key 才能重复.
类(class)
在一个域中,可以有多个类,主要是用来控制复制单元的,类是用来做属性管理的,类是比域 domain 低一个级别,可以定义一个文件存储在不同 device 中的份数.一个文件必须通过 domain,class 和 key 才能找出来.我们可以给不同的重要程度的文件,不同热度的文件,来分别用类来控制份数.
使用mogupload工具在这里是为了测试,实际环境中上传是由程序员在代码中使用mogilefs的API进行交互的。
[root@node1 ~]# mogupload --trackers=172.16.41.1:7001 --domain=p_w_picpaths --key='tux_1.jpg' --file='/root/my_test_data/1.jpg' #→--key='tux_1.jgp' 是我要上传后的键是什么 #→ --file 指的是我要上传的文件
通过将它给出的路径来访问一下看能不能正常的访问到?
模拟某个节点故障,看文件是否还在?
看到我们的文件还有一份保存在另外一节点上面的,通过那个路径也能访问到该文件,而且在每个storage节点上都能看到这个文件,之前说过啦,他们用的都是一个数据库;
OK!此时我们MogileFS系统基本上部暑基本完毕;
下面介绍Nginx做为MogileFS的前端客户端是如何实现的!
Nginx做为MogileFS的前端客户端,我们使用Nginx来吐文件,做前端的查询代理时,我们需要使用到mogilefs的这个模块,可以下载这个模块编译进Nginx就行了,直接使用 ./configure -add-module=这个参数就可以了,最新的这个模块的下载地址是:https://github.com/vkholodkov/nginx-mogilefs-module
#这里需要安装个pcre-devel包 [root@node4 ~]# yum install -y pcre-devel #解压获取到的mogilefs模块包 [root@node4 ~]# unzip nginx-mogilefs-module-master.zip #解压、编译安装nginx [root@node4 ~]# tar -xf nginx-1.4.7.tar.gz -C /usr/src/ [root@nginx ~]# cd /usr/src/nginx-1.4.7/ [root@nginx nginx-1.4.7]# ./configure \ --prefix=/usr \ --sbin-path=/usr/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/var/run/nginx/nginx.pid \ --lock-path=/var/lock/nginx.lock \ --user=nginx \ --group=nginx \ --with-http_ssl_module \ --with-http_flv_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --http-client-body-temp-path=/var/tmp/nginx/client/ \ --http-proxy-temp-path=/var/tmp/nginx/proxy/ \ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \ --http-scgi-temp-path=/var/tmp/nginx/scgi \ --with-pcre \ --with-debug \ --add-module=/root/nginx-mogilefs-module-master
2.为nginx提供SysV init脚本:
[root@nginx ~]# vim /etc/rc.d/init.d/nginx #!/bin/sh # # nginx - this script starts and stops the nginx daemon # # chkconfig: - 85 15 # description: Nginx is an HTTP(S) server, HTTP(S) reverse \ # proxy and IMAP/POP3 proxy server # processname: nginx # config: /etc/nginx/nginx.conf # config: /etc/sysconfig/nginx # pidfile: /var/run/nginx.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0 nginx="/usr/sbin/nginx" prog=$(basename $nginx) NGINX_CONF_FILE="/etc/nginx/nginx.conf" [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx lockfile=/var/lock/subsys/nginx make_dirs() { # make required directories user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -` options=`$nginx -V 2>&1 | grep 'configure arguments:'` for opt in $options; do if [ `echo $opt | grep '.*-temp-path'` ]; then value=`echo $opt | cut -d "=" -f 2` if [ ! -d "$value" ]; then # echo "creating" $value mkdir -p $value && chown -R $user $value fi fi done } start() { [ -x $nginx ] || exit 5 [ -f $NGINX_CONF_FILE ] || exit 6 make_dirs echo -n $"Starting $prog: " daemon $nginx -c $NGINX_CONF_FILE retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart() { configtest || return $? stop sleep 1 start } reload() { configtest || return $? echo -n $"Reloading $prog: " killproc $nginx -HUP RETVAL=$? echo } force_reload() { restart } configtest() { $nginx -t -c $NGINX_CONF_FILE } rh_status() { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|configtest) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" exit 2 esac [root@nginx ~]# chmod +x /etc/rc.d/init.d/ [root@nginx ~]# chkconfig --add nginx [root@nginx ~]# chkconfig nginx on #启动nginx [root@nginx ~]# service nginx start Starting nginx: [ OK ] [root@nginx ~]# ss -tnl | grep :80 LISTEN 0 128 *:80 *:* [root@nginx ~]#
3.修改nginx主配置文件:
[root@nginx ~]# vim /etc/nginx/nginx.conf worker_processes 2; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; server { listen 80; server_name www.magelinux.com; location / { root html; index index.html index.htm; } ################About p_w_picpaths############### location /p_w_picpaths/ { mogilefs_tracker 172.16.41.1:7001; mogilefs_domain p_w_picpaths; mogilefs_pass { proxy_pass $mogilefs_path; proxy_hide_header Content-Type; proxy_buffering off; } } ################About files############### location /files/ { mogilefs_tracker 172.16.41.1:7001; mogilefs_domain p_w_picpaths; mogilefs_pass { proxy_pass $mogilefs_path; proxy_hide_header Content-Type; proxy_buffering off; } } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
4.测试:
下面我上传一个html文档看能否代理成功?
此时我查看到了在两个域类有两个key,注意它们在上传的时候输入的类容,以及在去观察在nginx反代中的书写方法有是有一定区别的,先测试,稍后说
ok!fiels测试没有问题,但是我们可以将nginx的配置修改一下,让我在定义键的时候也改一下.
nginx中只需要修改 location /files/ 和proxy pass这段内容即可,这种方式定义p_w_picpaths也一样适用,先看看效果吧.
重新加载nginx、再次访问测试:
这两种定义方法可根据实际场景应用!
重新加载nginx、再次访问测试:
#################################################################### #→显示当前mogilefs的配置信息(host,domain,class)状态,如果加上--stats="domains"可以只显示domian相关的信息. [root@node1 ~]# mogstats --config=/etc/mogilefs/mogilefsd.conf #################################################################### #→显示一个具体文件的信息,包括所在域、副本数、文件ID、key、复制到了哪些tracker上面. [root@node1 ~]# mogfileinfo --trackers=172.16.41.1:7001 --domain=p_w_picpaths --key="tux_1.jpg" #################################################################### #→上传一个本地文件到指定的域内,同时必须指定key. [root@node1 ~]# mogupload --trackers=172.16.41.1:7001 --domain=p_w_picpaths --key='tux_1.jpg' --file='/root/my_test_data/1.jpg' #################################################################### #→删除指定域内的一个key. [root@node1 ~]# mogdelete --trackers=172.16.41.1:7001 --domain=p_w_picpaths --key='test1.html #################################################################### #→查看指定域内的文件有哪些. [root@node1 ~]# moglistkeys --trackers=172.16.41.1:7001 --domain=files #################################################################### #→检查整个mogilefs系统. [root@node1 ~]# mogadm --trackers=172.16.41.1:7001 check #################################################################### ................................ ................................ #→以上工具使用较为方便,其他工具使用请找"man"!
至此,mogilefs的部署已经完成,后续还有许多地方需要改进;
以上内容若有错误,请朋友们指出!
写博、不易,比不了别人,就做好自己!