MogileFS 分布式存储

Posted by Sunday on 2018-09-07

什么是分布式存储

分布式存储系统,是将数据分散存储在多台独立的设备上。传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,它不但提高了系统的可靠性、可用性和存取效率,还易于扩展

CAP理论

C:Consistency(一致性) 任何一个读操作总是能够读取之前完成的写操作。
A:Availability(可用性) 每一次操作总是能够在确定的时间返回。
P: Partition Tolerance ( 分区容错性 ) 在出现网络分区的情况下,仍然能够满足一致性和可用性。

有科学家都在致力于 CAP 三元素并存的时候,Eric.Brewer教授指出 CAP 永远无法兼顾,只能根据具体应用来权衡和取舍,并且至多两个元素可以共存,后来由两位麻省理工学院的科学家证明此观点是具有前瞻性的,由此形成Brewer的 CAP定理 。

正所谓鱼和熊掌不可兼得,关注一致性就需要处理因系统不可用而带来写操作失败的情况,反之关注可用性就无法保证每次都能读取到最新的写入操作。传统 关系型数据库 侧重于CA ,而 非关系型键值数据库 则侧重于 AP 。

强一致性(ACID) :在单机环境中,强一致性可以由数据库的事务来保证;在分布式环境中,强一致性很难做到,即便是做到也会因为分布式事物所带来的性能低下,不适合在互联网的环境中应用。

弱一致性(包括最终一致性) : 系统不能保证后续访问返回最新的值,在访问到最新值之前这段时间称之为 不一致窗口 。

最终一致性 :是弱一致性的一种特例,存储系统保证如果对象有多次更新,在渡过 不一致窗口之后必将放回最后更新的值。

MogilesFS介绍

MogilesFS简介

MogileFS是一个开源的分布式文件系统,用于组建分布式文件集群,由LiveJournal旗下DangaInteractive公司开发,Danga团队开发了包括 Memcached、MogileFS、Perlbal等不错的开源项目:(注:Perlbal是一个强大的Perl写的反向代理服务器)。MogileFS是一个开源的分布式文件系统。
目前使用 MogileFS 的公司非常多,比如国外的一些公司,日本前几名的公司基本都在使用这个,国内所知道的使用 MogileFS 的公司有图片托管网站 yupoo又拍,digg, 土豆, 豆瓣,1 号店, 大众点评,搜狗,安居客等等网站.分别为所在的组织或公司管理着海量的图片。

MogileFS特性

1 ) 支持多节点冗余
2)可实现自动的文件复制
3)使用名称空间(命名空间),每个文件通过key来确定,比如123.jpg是一个key,真正存储的位置可能是/000/000/00/01/md5hash.fid
4)不需要RAID,应用层可直接实现RAID,不共享任何东西,通过”集群接口”提供服务
5)工作于应用层,没有特殊的组件要求
6)不用共享任何数据,MogileFS不需要依靠昂贵的SAN来共享磁盘,每个机器只用维护好自己的磁盘

MogileFS的工作原理
11

MogileFS的架构
MogileFS主要由三部分构成:tracker节点、database节点、storage节点

1)Tracker–跟踪器,调度器
MogileFS的核心,是一个调度器,mogilefsd进程就是trackers进程程序,trackers的主要职责有:删除数据、复制数据、监控、查询等等,这个是基于事件的( event-based ) 父进程/消息总线来管理所有来自于客户端应用的交互, 包括将请求负载平衡到多个”query workers”中,然后让 mogilefs的子进程去处理,mogadm,mogtool的所有操作都要跟trackers打交道,Client的一些操作也需要定义好trackers,因此最好同时运行多个trackers来做负载均衡,trackers也可以只运行在一台机器上,使用负载均衡时可以使用一些简单的负载均衡解决方案,如haproxy,lvs,nginx等,tarcker的配置文件为/etc/mogilefs/mogilefsd.conf,监听在TCP的7001端口

2)Database–数据库部分
主要用来存储mogilefs的元数据(命名空间和文件在哪里等),是trackers来操作和管理它,可以用mogdbsetup程序来初始化数据库,所有的元数据都存储在数据库中,因此,这个数据相当重要,如果数据库挂掉,所有的数据都不能用于访问,因此,建议应该对数据库做高可用

3)storage–存储节点
这个是MogileFS存储数据的真正节点,也是mogstored节点,也叫storage server,一台存储节点要启动一个mogstored服务,扩容就是增加这些主机节点实际存放数据的地方
配置文件为/etc/mogilefs/mogstored.conf,监听在TCP的7500端口

MogileFS管理
1、Domain:一个mogilefs可以有多个domain,用来存放不同文件(大小、类型),同一个domain内key必须唯一,不同domain内key可以是相同的
2、每个存储节点称为一个host主机,一个主机上可以有多个存储设备dev(单独的硬盘),每个设备都有一个ID号,Domain+Fid来定位文件
3、Class:文件属性管理,复制文件的最小单位不是文件,而是class,定位文件存储在不同设备上的份数,也就是定义副本的数量

环境

准备三台主机

node1: tracker节点、database节点、storage节点
node2: storage节点
node3: storage节点
注意关掉防火墙和selinux,iptables -F && setenforce 0

安装

安装 mogilefs-server
三台主机下载安装 MogileFS rpm
链接: https://pan.baidu.com/s/1lJqligm7yQlaD6dQM2DcMg 密码: m4m3

1
2
3
4
5
6
7
8
9
10
11
12
[root@node0 mogilefs]# ls -l
total 648
-rw-r--r-- 1 root root 1916 Feb 21 2017 MogileFS-Server-2.46-2.el6.noarch.rpm
-rw-r--r-- 1 root root 176308 Feb 21 2017 MogileFS-Server-mogilefsd-2.46-2.el6.noarch.rpm
-rw-r--r-- 1 root root 26872 Feb 21 2017 MogileFS-Server-mogstoraged-2.46-2.el6.noarch.rpm
-rw-r--r-- 1 root root 75916 Feb 21 2017 MogileFS-Utils-2.19-1.el6.noarch.rpm
-rw-r--r-- 1 root root 5880 Feb 21 2017 Perlbal-1.78-1.el6.noarch.rpm
-rw-r--r-- 1 root root 1624 Feb 21 2017 Perlbal-doc-1.78-1.el6.noarch.rpm
-rw-r--r-- 1 root root 28111 Feb 21 2017 perl-Danga-Socket-1.61-1.el6.rf.noarch.rpm
-rw-r--r-- 1 root root 30312 Feb 21 2017 perl-MogileFS-Client-1.14-1.el6.noarch.rpm
-rw-r--r-- 1 root root 25140 Feb 21 2017 perl-Net-Netmask-1.9015-8.el6.noarch.rpm
-rw-r--r-- 1 root root 268620 Feb 21 2017 perl-Perlbal-1.78-1.el6.noarch.rpm

1
2
yum install -y perl-Net-Netmask perl-IO-String perl-Sys-Syslog perl-IO-AIO
yum install -y ./*

配置 tracker

tracker配置

1
2
3
4
5
6
vim /etc/mogilefs/mogilefsd.conf 

db_dsn = DBI:mysql:mogilefs:host=192.168.10.101
db_user = mogilefs
db_pass = mogilefs
listen = 192.168.10.101:7001

MySQL配置

1
2
3
4
5
6
7
8
yum install -y mariadb-server
systemctl start mariadb
MySQL [(none)]> grant all privileges on mogilefs.* to 'mogilefs'@'192.168.10.101' identified by 'mogilefs';
MySQL [(none)]> flush privileges;

mogdbsetup --dbpass=mogilefs #一路按Y即可
MySQL [(none)]> use mogilefs;
MySQL [mogilefs]> show tables; #查看到有表就成功了

启动tracker服务

1
systemctl start mogilefsd

配置 storage

创建存储目录
storage节点添加设备,生产环境最好单独挂载一个新的磁盘,专门用来存储数据
node1创建目录dev1,node2创建目录dev2,node3创建目录dev3
注:dev 1、2、3为设备的ID号,必须唯一。

1
2
mkdir -p /data/mogdata
chown -R mogilefs.mogilefs /data/mogdata

1
2
mkdir /data/mogdata/dev1
chown -R mogilefs.mogilefs /data/mogdata/dev1
1
2
3
4
5
6
vim /etc/mogilefs/mogstoraged.conf 

maxconns = 10000
httplisten = 0.0.0.0:7500
mgmtlisten = 0.0.0.0:7501
docroot = /data/mogdata

启动storaged服务

1
systemctl start mogstoraged

添加 管理 storage 节点

添加storage节点

1
2
3
mogadm --tracker=192.168.10.101:7001 host add node1 --ip=192.168.10.101 --port=7500 --status=alive
mogadm --tracker=192.168.10.101:7001 host add node2 --ip=192.168.10.102 --port=7500 --status=alive
mogadm --tracker=192.168.10.101:7001 host add node3 --ip=192.168.10.103 --port=7500 --status=alive

添加存储设备

1
2
3
mogadm --tracker=192.168.10.101:7001 device add node1 1
mogadm --tracker=192.168.10.101:7001 device add node2 2
mogadm --tracker=192.168.10.101:7001 device add node3 3

查看状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mogadm --tracker=192.168.10.101:7001 check
Checking trackers...
192.168.10.101:7001 ... OK

Checking hosts...
[ 1] node1 ... OK
[ 2] node2 ... OK
[ 3] node3 ... OK

Checking devices...
host device size(G) used(G) free(G) use% ob state I/O%
---- ------------ ---------- ---------- ---------- ------ ---------- -----
[ 1] dev1 16.986 2.636 14.350 15.52% writeable N/A
[ 2] dev2 16.986 1.796 15.191 10.57% writeable N/A
[ 3] dev3 16.986 1.739 15.247 10.24% writeable N/A
---- ------------ ---------- ---------- ---------- ------
total: 50.959 6.171 44.788 12.11%

1
2
3
4
5
6
7
8
9
mogadm --tracker=192.168.10.101:7001 host list
node1 [1]: alive
IP: 192.168.10.101:7500

node2 [2]: alive
IP: 192.168.10.102:7500

node3 [3]: alive
IP: 192.168.10.103:7500

修改storage节点

1
2
3
4
mogadm --trackers=192.168.10.101:7001 host mark node3 down
mogadm --trackers=192.168.10.101:7001 host list | grep node3
node3 [3]: down
mogadm --trackers=192.168.10.101:7001 host mark node3 alive

创建域

1
2
3
4
5
6
7
8
mogadm --trackers=192.168.10.101:7001 domain add file
mogadm --trackers=192.168.10.101:7001 domain add img
mogadm --trackers=192.168.10.101:7001 domain list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
file default 2 MultipleHosts() NONE

img default 2 MultipleHosts() NONE

domain:区域
class:复制文件的最小单位 (最大为64M,如果一个单文件超出此大小将拆分为多个class存储)
mindevcount:最小复制文件的份数
replpolicy:复制份数
hashtype:采用的hash的类型

创建类

默认最小复制文件的份数

1
mogadm --trackers=192.168.10.101:7001 class add img png

指定默认最小复制文件为3份

1
mogadm --trackers=192.168.10.101:7001 class add img jpeg --mindevcount=3

1
2
3
4
5
6
7
8
mogadm --trackers=192.168.10.101:7001 class list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
file default 2 MultipleHosts() NONE

img default 2 MultipleHosts() NONE
img png 2 MultipleHosts() NONE
img jpeg 3 MultipleHosts() NONE

class限制,不要副本

1
2
3
mogadm --trackers=192.168.10.101:7001 class add file text --mindevcount=1
mogadm --trackers=192.168.10.101:7001 class list | grep text
file text 1 MultipleHosts() NONE

设置class至少3个保留副本

1
2
3
4
5
6
7
8
9
10
11
mogadm --trackers=192.168.10.101:7001 class add file html --replpolicy="MultipleHosts(3)"
mogadm --trackers=192.168.10.101:7001 class list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
file default 2 MultipleHosts() NONE
file html 2 MultipleHosts(3) NONE
file text 1 MultipleHosts() NONE

img default 2 MultipleHosts() NONE
img jpeg 3 MultipleHosts() NONE
img png 2 MultipleHosts() NONE

文件上传

1
2
3
4
5
6
7
8
9
10
11
mogupload --trackers=192.168.10.101 --domain=img --class=png --key='1.jpg' --file='/root/clara.jpg'
mogfileinfo --trackers=192.168.10.101:7001 --domain=img --key='1.jpg'
- file: 1.jpg
class: png
devcount: 2
domain: img
fid: 35
key: 1.jpg
length: 183975
- http://192.168.10.101:7500/dev1/0/000/000/0000000035.fid
- http://192.168.10.103:7500/dev3/0/000/000/0000000035.fid
1
2
3
4
5
6
7
8
9
10
11
12
mogupload --trackers=192.168.10.101:7001 --domain=img --class=jpeg --key='2.jpg' --file='/root/clara.jpg'
mogfileinfo --trackers=192.168.10.101:7001 --domain=img --key='2.jpg'
- file: 2.jpg
class: jpeg
devcount: 3
domain: img
fid: 36
key: 2.jpg
length: 183975
- http://192.168.10.103:7500/dev3/0/000/000/0000000036.fid
- http://192.168.10.102:7500/dev2/0/000/000/0000000036.fid
- http://192.168.10.101:7500/dev1/0/000/000/0000000036.fid
1
2
3
4
5
6
7
8
9
10
11
12
mogupload --trackers=192.168.10.101:7001 --domain=file --class=html --key='fstab.txt' --file='/etc/fstab'
mogfileinfo --trackers=192.168.10.101:7001 --domain=file --key='fstab.txt'
- file: fstab.txt
class: html
devcount: 3
domain: file
fid: 38
key: fstab.txt
length: 529
- http://192.168.10.102:7500/dev2/0/000/000/0000000038.fid
- http://192.168.10.103:7500/dev3/0/000/000/0000000038.fid
- http://192.168.10.101:7500/dev1/0/000/000/0000000038.fid

如何解决MogileFS的无法复制 bug问题

注:MogileFS在centos7上有个致命的错误,就是没有复制副本到其他的节点上,解决如下(每台)

1
2
3
4
5
6
yum install -y make gcc unzip perl-DBD-MySQL perl perl-CPAN perl-YAML perl-Time-HiRes
wget http://pkgs.fedoraproject.org/repo/pkgs/perl-Sys-Syscall/Sys-Syscall-0.23.tar.gz/be6dc2d791684a6f8abb3dd39ff2d1de/Sys-Syscall-0.23.tar.gz
tar -xf Sys-Syscall-0.23.tar.gz
cd Sys-Syscall-0.23/
perl Makefile.PL
make && make install

若mogilefs已配置运行,重启这两个服务,重新上传文件就可以生效

1
2
systemctl restart mogilefsd 
systemctl restart mogstoraged

MogileFS的只读模式和耗尽(Drain) 模式

如果你想要冻结设备上所有的文件,你要使用只读模式就行了。这将停掉 MogileFS 存放新文件到这个设备上,但它也将阻止删除文件,代替的删除的操作是会给这些内容放到队列中等待为您标记为’alive’着或’drain’。

1
2
mogadm device mark node1 1 readonly
mogadm device mark node2 2 drain

耗尽(Drain) 模式, 在 2.40 和更高以上,告诉 MogileFS不会有新的文件应写入设备. 但是在耗尽(Drain) 模式文件可能被删除,所以如果你不希望写文件到这个设备上,可以设置为drain 的模式
注:耗尽(Drain) 模式在 MogileFS 的早期版本,将会从设备删除 FIDS现在它已经被重新均衡的功能取代。
重新复制文件
如果有一个硬盘坏了,MogileFS 可以自动的让请求不在访问这个设备,但是不会自动的重新复制这个硬盘的文件,你必须通过 mogadm 来手工来标志成 ‘dead’. 只要你这样做, MogileFS 将开始删除设备上的文件,并试图在集群间重新复制它们到其它的设备上.

MogileFS的rebalance功能

MogileFS的rebalance功能可以平衡各个storage节点磁盘的使用情况,将磁盘剩余空间很少的磁盘中的数据搬到磁盘剩余空间大的磁盘上,使磁盘的使用率基本达到平衡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[root@node1 dev1]#mogadm check
Checking trackers...
192.168.10.101:7001 ... OK

Checking hosts...
[ 1] node1 ... OK
[ 2] node2 ... OK
[ 3] node3 ... OK

Checking devices...
host device size(G) used(G) free(G) use% ob state I/O%
---- ------------ ---------- ---------- ---------- ------ ---------- -----
[ 1] dev1 49.976 0.039 49.936 0.08% writeable 0.2
[ 2] dev2 49.976 0.531 49.445 1.06% writeable N/A
[ 3] dev3 49.976 0.065 49.911 0.13% writeable 0.0
[root@node1 app]#mogadm rebalance policy --options="from_hosts=2 to_percent_free=99" #设置rebalance策略,表示从设备id为2,搬到剩余空间为99%的存储设备
[root@node1 app]#mogadm rebalance test #查看一下策略
Tested rebalance policy...
Policy: from_hosts=2 to_percent_free=99
Source devices:
- 2
Destination devices:
- 1
- 3
[root@node1 app]#mogadm rebalance start #运行此策略
[root@node1 app]#mogadm rebalance stop #停止rebalance策略

命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
列出所有keys
moglistkeys --trackers=192.168.10.101:7001 --domain=img

列出所有fid
moglistfids --trackers=192.168.10.101:7001

上传
mogupload --trackers=192.168.10.101:7001 --domain=img --class=jpeg --key='1.jpg' --file='/root/clara.jpg'

下载
mogfetch --trackers=192.168.10.101:7001 --domain=img --key='1.jpg' --file='1.jpg'

查看
mogfileinfo --trackers=192.168.10.101:7001 --domain=file --key='1.jpg'

重命名
mogrename --trackers=192.168.10.101 --domain=img --old_key='1.jpg' --new_key='11.jpg'

删除
mogdelete --trackers=192.168.10.101:7001 --domain=img --key='11.jpg'

查看状态、统计数据
mogstats --db_dsn="DBI:mysql:mogilefs:host=192.168.10.101" --db_user='mogilefs' --db_pass='mogilefs' --verbose --stats='devices,files'
mogstats --db_dsn="DBI:mysql:mogilefs:host=192.168.10.101" --db_user='mogilefs' --db_pass='mogilefs' --verbose --stats='all'

删除操作

先删除文件 全部

1
2
mogdelete --trackers=192.168.10.101:7001 --domain=img --key='11.jpg'
...

删除类 全部

1
2
mogadm --trackers=192.168.10.101:7001 class delete img jpg
...

删除域

1
mogadm domain delete img

删除storaged节点

1
2
3
4
5
6
mogadm --tracker=192.168.10.101:7001 host mark node3 down
mogadm --tracker=192.168.10.101:7001 host delete node3
Failure deleting host: host_not_empty Unable to delete host; it contains devices still #需删除数据库信息,才能移除

mysql -e "delete from mogilefs.device where hostid!=4"
mogadm --tracker=192.168.10.101:7001 host delete node3

nginx-mogilefs-module

1
2
3
4
5
6
cd /usr/local/src/nginx_module
wget http://www.grid.net.ru/nginx/download/nginx_mogilefs_module-1.0.4.tar.gz
./configure --prefix=/usr/local/webserver/nginx --with-file-aio --with-poll_module --with-http_realip_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_slice_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/local/src/nginx_module/nginx_mogilefs_module-1.0.4
make
sed -i 's#^CFLAGS(.*)-Werror -g#CFLAGS\1-g#' objs/Makefile
make && make install

http://www.grid.net.ru/nginx/mogilefs.en.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
upstream trackers {
server 192.168.10.101:7001;
}

server{
listen 80;
server_name 192.168.10.101;

location /upload/img/ {
allow 192.168.2.0/24;
deny all;

mogilefs_tracker trackers;
#mogilefs_domain img;
mogilefs_methods GET PUT DELETE;
#mogilefs_class jpeg png;
mogilefs_noverify on;
mogilefs_pass {
proxy_pass $mogilefs_path;
proxy_hide_header Content-Type;
proxy_buffering off;
}
}

location /upload/file/ {
mogilefs_tracker 192.168.10.101:7001;
mogilefs_domain file;
mogilefs_methods GET PUT DELETE;
mogilefs_noverify on;
mogilefs_pass {
proxy_pass $mogilefs_path;
proxy_hide_header Content-Type;
proxy_buffering off;
}
}
}

访问:
http://192.168.10.101/upload/img/1.jpg
http://192.168.10.101/upload/file/fstab.txt

1
2
curl -X PUT -T './3.jpg' http://192.168.10.101/upload/img/3.jpg #上传不能实现 
curl -X DELETE http://192.168.10.101/upload/img/1.jpg #删除可以实现的

若上传的--key指定/,则nginx localtion img后不带/

1
2
3
4
mogupload --trackers=192.168.10.101:7001 --domain=img --class=jpeg --key='2.jpg' --file='/root/clara.jpg'
location ~* /img {
...
}

若上传的--key未指定/,则localtion ~* /img { } img需带/

1
2
3
4
mogupload --trackers=192.168.10.101:7001 --domain=img --class=jpeg --key='2.jpg' --file='/root/clara.jpg'
location ~* /img/ {
...
}

报错解决

启动报错

1
2
3
4
5
6
7
journalctl -xe
Sep 07 11:48:08 node1 systemd[1]: PID file /var/run/mogilefsd/mogstoraged.pid not readable (yet?) after start.
Sep 07 11:48:08 node1 systemd[1]: Failed to start SYSV: MogileFS storage.

解决:
mkdir /var/run/mogilefsd/
chown -R mogilefs.mogilefs /var/run/mogilefsd/

nginx-mogilefs-module报错

1
2
3
4
5
6
7
8
9
10
11
12
/usr/local/src/nginx_module/nginx_module/nginx_mogilefs_module-1.0.4/ngx_http_mogilefs_module.c: In function ngx_http_mogilefs_create_request’:
/usr/local/src/nginx_module/nginx_module/nginx_mogilefs_module-1.0.4ngx_http_mogilefs_module.c:748:37: error: variable request’ set but not used [-Werror=unused-but-set-variable]
ngx_str_t request, domain;
^
/usr/local/src/nginx_module/nginx_module/nginx_mogilefs_module-1.0.4/ngx_http_mogilefs_module.c: In function ngx_http_mogilefs_create_spare_location’:
/usr/local/src/nginx_module/nginx_module/nginx_mogilefs_module-1.0.4/ngx_http_mogilefs_module.c:1541:39: error: variable pclcf’ set but not used [-Werror=unused-but-set-variable]
ngx_http_core_loc_conf_t *clcf, *pclcf, *rclcf;

vim objs/Makefile
CFLAGS = -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g
修改为
CFLAGS = -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -g

https://www.jianshu.com/p/f3b47de0d9c0