Web集群实现共享存储的架构演变及MogileFS
本篇博客从Web集群中亟需解决的大容量存储问题引入,分析了几类常用的共享存储架构,重点解析了分布式存储系统的原理及配置实现;===================================================================
1 共享存储的架构演变
2 分布式存储系统
2.1 基础知识
2.2 分类
2.3 CAP理论
2.4 协议
3 MogileFS
3.1 特性
3.2 架构
3.3 组成
3.4 服务安装及启动
3.5 配置部署
3.6 配置前端代理Nginx
3.7 访问验证
3.8 后续扩展
===================================================================
1 共享存储的架构演变
[*]rsync+inotify:本地各保留一份完整数据,但通过rsync实时同步修改文件,双主模型哦
[*]NFS:多节点挂载后性能下降严重;存在单点故障,且多个客户端并发修改同一个文件时可能出现不一致的情况;
[*]SAN:存储区域网络,不适用于海量高并发的存储场景,且代价昂贵;可通过软件实现iSCSI存储网络;涉及GFS2/CLVM(LVM2)
[*]MooseFS:分布式文件系统,适用于海量小文件存储;支持FUSE,可被挂载使用;
[*]MogileFS:分布式存储系统,适用于海量小文件存储;不支持FUSE,只能通过API调用;
2 分布式存储系统
2.1 基础知识
定义:分布式存储系统是大量普通PC服务器通过Internet互联,对外作为一个整体提供存储服务
特性:
[*]可扩展:分布式存储系统可以扩展到几百台至几千台的集群规模,且随着集群规模的增长,系统整体性能表现为线性增长;
[*]低成本:分布式存储系统的自动容错、自动负载均衡机制使其可以构建在普通PC机之上;另外,线性扩展能力也使得增加、减少机器非常方便,可以实现自动运维;
[*]高性能:无论是针对整个集群还是单台服务器,都要求分布式系统具备高性能;
[*]易用:分布式存储系统需要能够提供易用的对外接口;另外,也要求具备完善的监控、运维工具,并能方便的与其他系统集成,如从Hadoop云计算系统导入数据;
挑战:在于数据、状态信息的持久化,要求在自动迁移、自动容错、并发读写的过程中保证数据的一致性;
2.2 分类
数据类型大致可分为非结构化数据(如文本、图片、视频等),结构化数据(一般存储在关系型数据库中),半结构化数据(如HTML文档);根据处理不同类型数据的需求,分布式存储系统可分为如下4类:
[*]分布式文件系统:用于存储Blob对象,如图片、视频等,这类数据以对象的形式组织,对象之间没有关联;如GFS,MogileFS等;
[*]分布式键值系统:用于存储关系简单的半结构化数据,它只提供基于主键的CRUD(Create/Read/Update/Delete)功能;如Memcache,Redis等;
[*]分布式表格系统:用于存储关系较为复杂的半结构化数据,不仅支持简单的CRUD操作,还支持扫描某个主键范围;如Google Bigtable、Megastore;
[*]分布式数据库:用于存储结构化数据,利用二维表格组织数据;如MySQL Sharding集群,Google Spanner等;
2.3 CAP理论
来自Berkerly的Eric Brewer教授提出了一个著名的CAP理论:一致性(Consistency),可用性(Availability)和分区容忍性(Tolerance of network Partition)三者不能同时满足:
[*]C:读操作总是能读取到之前完成的写操作结果,满足这个条件的系统成为强一致系统,这里的“之前”一般对同一个客户端而言;
[*]A:读写操作在单台机器发生故障的情况下依然能够正常执行,而不需要等待发生故障的机器重启或者其上的服务迁移到其他机器;
[*]P:机器故障、网络故障、机房停电等异常情况下仍然能够满足一致性和可用性;
分布式存储系统要求能够自动容错,即分区可容忍性总是需要满足的,因此,一致性和写操作的可用性就不能同时满足了,需要在这二者间权衡,是选择不允许丢失数据,保持强一致,还是允许少量数据丢失以获得更好的可用性;
2.4 协议
分布式协议涉及的协议很多,例如租约,复制协议,一致性协议,其中以两阶段提交协议和Paxos协议最具有代表性;
两阶段提交协议(Two-phase Commit,2PC)用以保证跨多个节点操作的原子性,即跨多个节点的操作要么在所有节点上全部执行成功,要么全部失败;
两个阶段的执行过程如下:
[*]阶段一:请求阶段(Prepare phase),在请求阶段,协调者通知事务参与者准备提交或者取消事务,然后进入表决过程;
[*]阶段二:提交阶段(Commit phase);
Paxos协议用于确保多个节点对某个投票(例如哪个节点为主节点)达成一致;
3 MogileFS
3.1 特性
[*]工作于应用层:无需特殊的核心组件;
[*]无单点:三大组件(tracker,mogstore,database)皆可实现高可用;
[*]自动文件复制:复制的最小单位不是文件,而是class;基于不同的class,文件可以被自动的复制到多个有足够存储空间的存储节点上;
[*]传输中立,无特殊协议:可以通过NFS或HTTP协议进行通信;
[*]简单的命名空间:文件通过一个给定的key来确定,是一个全局的命名空间;没有目录,基于域实现文件隔离;
[*]不共享数据:无需通过昂贵的SAN来共享磁盘,每个存储节点只需维护自己所属的存储设备(device)即可;
3.2 架构
http://s3.运维网.com/wyfs02/M00/28/6B/wKiom1N5jnXTNFaZAAITIAkEXNM059.jpg
Tracker:MogileFS的核心,是一个调度器;服务进程为mogilefsd;可以做负载均衡调度;
[*]主要职责有:
[*]数据删除;
[*]数据复制;
[*]监控:故障后生成新的数据副本;
[*]查询;
Database:Tracker访问Database,返回用户可用的Storage Node及文件的存放位置;
mogstored:数据存储的位置,通常是一个HTTP(WebDAV)服务器,用于数据的创建、删除、获取等;不可做负载均衡调度;
3.3 组成
MogileFS由3个部分组成:
server:主要包括mogilefsd和mogstored两个应用程序。
[*]mogilefsd实现的是tracker,它通过数据库来保存元数据信息,包括站点domain、class、host等;
[*]mogstored是存储节点(store node),它其实是个WebDAV服务,默认监听在7500端口,接受客户端的文件存储请求。
Utils(工具集):主要是MogileFS的一些管理工具,例如mogadm等;
[*]在MogileFS安装完后,要运行mogadm工具将所有的store node注册到mogilefsd的数据库里,mogilefsd会对这些节点进行管理和监控;
客户端API:MogileFS的客户端API很多,例如Perl、PHP、Java、Python等,用这个模块可以编写客户端程序,实现文件的备份管理功能等;
3.4 服务安装及启动
基本架构(在LNMT架构的基础上改进)
http://s3.运维网.com/wyfs02/M00/28/6B/wKioL1N5jryCLxbNAAcokoPHoI8707.jpg
服务器规划
http://s3.运维网.com/wyfs02/M02/28/6B/wKiom1N5jv6RaOl_AALC6DaRAQg067.jpg
服务安装及启动
数据库授权
MariaDB [(none)]> grant all on *.* to 'root'@'192.168.%.%' identified by 'magedu';
Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> grant all on mogdb.* to 'moguser'@'192.168.%.%' identified by 'mogpass';
Query OK, 0 rows affected (0.02 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]>
grant all on *.* to 'root'@'192.168.%.%' identified by 'magedu';
grant all on mogdb.* to 'moguser'@'192.168.%.%' identified by 'mogpass';
flush privileges;主机192.168.0.45(mogilefs+mogilestored)
# 所需程序包
# ls
MogileFS-Server-2.46-2.el6.noarch.rpm perl-MogileFS-Client-1.14-1.el6.noarch.rpm
MogileFS-Server-mogilefsd-2.46-2.el6.noarch.rpmperl-Net-Netmask-1.9015-8.el6.noarch.rpm
MogileFS-Server-mogstored-2.46-2.el6.noarch.rpmperl-Perlbal-1.78-1.el6.noarch.rpm
MogileFS-Utils-2.19-1.el6.noarch.rpm
# yum install -y *.rpm perl-IO-AIO
# 修改配置文件
# vi /etc/mogilefs/mogilefsd.conf # 调度器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 = /var/run/mogilefsd/mogilefsd.pid
# Database connection information
db_dsn = DBI:mysql:mogdb:host=192.168.0.45:3406 # 存储元数据的数据库信息,包括数据库mogdb及连接地址192.168.0.45:3406
db_user = moguser # 数据库用户名
db_pass = mogpass # 数据库登录密码
# IP:PORT to listen on for mogilefs client requests
listen = 192.168.0.45:7001
# vi /etc/mogilefs/mogstored.conf # 存储节点mogstored的配置文件
maxconns = 10000 # 最大连接数
httplisten = 0.0.0.0:7500 # http请求监听的地址和端口
mgmtlisten = 0.0.0.0:7501
docroot = /var/mogdata # 存储设备挂载目录,可修改
# 准备存储设备
# fdisk /dev/sda # 新建分区sda4,大小10G(实际生产环境中,此为整块磁盘,而非分区)
# kpartx -af /dev/sda
# partx -a /dev/sda
# cat /proc/partitions # 验证分区已创建成功
# mke2fs -t ext4 /dev/sda4 # 初始化分区
# mkdir /var/mogdata
# mount -t ext4 /dev/sda4 /var/mogdata/ # 挂载分区
# mkdir /var/mogdata/dev1 # 创建存储设备dev1(注:在192.168.0.46上,此为dev2)
# chown -R mogilefs.mogilefs /var/mogdata/
# 初始化数据库
# mogdbsetup --dbhost=192.168.0.45 --dbport=3406 --dbrootuser=root --dbrootpass=magedu --dbuser=moguser --dbpass=mogpass --dbname=mogdb --yes
# 初始化数据库执行一次即可,故在主机192.168.0.46上无需执行此步骤
# 启动服务
# service mogilefsd start
Starting mogilefsd
# service mogstored start
Starting mogstored 主机192.168.0.46(mogilefs+mogilestored)
同上,直至mogilefsd和mogstored服务都正常启动
3.5 配置部署(任意一个tracker节点上配置即可,如192.168.0.45)
添加节点
# echo "trackers = 192.168.0.45:7001" > /etc/mogilefs/mogilefs.conf # 管理程序mogadm的配置文件
# mogadm host add 192.168.0.45 --ip=192.168.0.45 --status=alive # 添加节点1
# mogadm host add 192.168.0.46 --ip=192.168.0.46 --status=alive # 添加节点2
# mogadm host list # 查看已添加节点
192.168.0.45 : alive
IP: 192.168.0.45:7500
192.168.0.46 : alive
IP: 192.168.0.46:7500添加设备
# mogadm device add 192.168.0.45 1 # 添加存储设备1,设备编号需与/var/mogdata目录下的dev1目录保持一致
# mogadm device add 192.168.0.46 2 # 添加存储设备2,设备编号需与/var/mogdata目录下的dev2目录保持一致
# mogadm device list # 查看已添加设备
192.168.0.45 : alive
used(G) free(G) total(G)weight(%)
dev1: alive 0.146 9.200 9.347 100
192.168.0.46 : alive
used(G) free(G) total(G)weight(%)
dev2: alive 0.146 9.199 9.346 100添加domain(域)
# mogadm domain add images
# mogadm domain add text
# mogadm domain list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
images default 2 MultipleHosts() NONE
text default 2 MultipleHosts() NONE添加class(文件类别)
# mogadm class add images class1 --mindevcount=2 # 在域images中添加类别class1和class2,最小文件复制份数为2
# mogadm class add images class2 --mindevcount=2
# mogadm class add text class1 --mindevcount=2 # 在域text中添加类别class1和class2,最小文件复制份数为2
# mogadm class add text class2 --mindevcount=2
# mogadm class list
domain class mindevcount replpolicy hashtype
-------------------- -------------------- ------------- ------------ -------
images class1 2 MultipleHosts() NONE
images class2 2 MultipleHosts() NONE
images default 2 MultipleHosts() NONE
text class1 2 MultipleHosts() NONE
text class2 2 MultipleHosts() NONE
text default 2 MultipleHosts() NONE3.6 配置前端代理Nginx
重新编译安装nginx,添加nginx-mogilefs-module-master模块
# cd /home/software/src/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=/home/software/tar/nginx-mogilefs-module-master
# make && make install配置Nginx,将静态文件和图片的访问都转发至后端MogileFS即可
# cat /etc/nginx/nginx.conf
worker_processes2;
error_log/var/log/nginx/nginx.error.log;
pid /var/run/nginx.pid;
events {
worker_connections1024;
}
http {
include mime.types;
default_typeapplication/octet-stream;
log_formatmain'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout65;
fastcgi_cache_path /www/cache levels=1:2 keys_zone=fcgicache:10m inactive=5m;
upstream mogfs_cluster { # 定义后端mogilefs集群
server 192.168.0.45:7001;
server 192.168.0.46:7001;
}
server {
listen 4040;
server_namexxrenzhe.lnmmp.com;
access_log/var/log/nginx/nginx-img.access.logmain;
root /www/lnmmp.com;
valid_referers none blocked xxrenzhe.lnmmp.com *.lnmmp.com;
if ($invalid_referer) {
rewrite ^/ http://xxrenzhe.lnmmp.com/404.html
}
location ~* ^(/images/.*)$ { # 图片访问直接转发至后端mogilefs集群
mogilefs_tracker mogfs_cluster;
mogilefs_domain images; # 指定images域
mogilefs_noverify on;
mogilefs_pass $1 { # 传输访问的全路径(/images/.*)
proxy_pass $mogilefs_path;
proxy_hide_header Content=Type;
proxy_buffering off;
}
}
}
server {
listen 80;
server_namexxrenzhe.lnmmp.com;
access_log/var/log/nginx/nginx-static.access.logmain;
location / {
root /www/lnmmp.com;
indexindex.php index.html index.htm;
}
location ~* ^(/text/.*)$ { # 文本访问直接转发至后端mogilefs集群
mogilefs_tracker mogfs_cluster;
mogilefs_domain text; # 指定text域
mogilefs_noverify on;
mogilefs_pass $1 { # 传输访问的全路径(/text/.*)
proxy_pass $mogilefs_path;
proxy_hide_header Content=Type;
proxy_buffering off;
}
}
gzip on;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/x-javascript text/xml application/xml;
gzip_disable msie6;
}
server {
listen 8080;
server_namexxrenzhe.lnmmp.com;
access_log/var/log/nginx/nginx-php.access.logmain;
location / {
root /www/lnmmp.com;
indexindex.php index.html index.htm;
}
error_page404 /404.html;
error_page500 502 503 504/50x.html;
location = /50x.html {
root /www/lnmmp.com;
}
location ~ \.php$ {
root /www/lnmmp.com;
fastcgi_pass 127.0.0.1:9000;
fastcgi_cachefcgicache;
fastcgi_cache_valid 200 302 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
fastcgi_cache_min_uses 1;
fastcgi_cache_key $request_method://$host$request_uri;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_indexindex.php;
fastcgi_paramSCRIPT_FILENAME$document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}启动nginx服务
# service nginx start
Starting nginx: 3.7 访问验证
上传文件测试分布式文件系统MogileFS的功能
# mogupload --domain=images --key='/images/fish.jpg' --file="/images/fish.jpg" # 上传图片文件,选择images域
# mogupload --domain=text --key='/text/index.html' --file="/text/index.html" # 上传文本文件,选择text域
# moglistkeys --domain=images # 列出已添加的key
/images/fish.jpg
# moglistkeys --domain=text
/text/index.html
# mogfileinfo --domain=images --key='/images/fish.jpg' # 查看已添加文件的具体信息,包括实际可访问地址
- file: /images/fish.jpg
class: default
devcount: 2
domain: images
fid: 9
key: /images/fish.jpg
length: 3225
- http://192.168.0.45:7500/dev1/0/000/000/0000000009.fid
- http://192.168.0.46:7500/dev2/0/000/000/0000000009.fid
# mogfileinfo --domain=text --key='/text/index.html'
- file: /text/index.html
class: default
devcount: 2
domain: text
fid: 8
key: /text/index.html
length: 15
- http://192.168.0.46:7500/dev2/0/000/000/0000000008.fid
- http://192.168.0.45:7500/dev1/0/000/000/0000000008.fidhttp://s3.运维网.com/wyfs02/M02/28/6C/wKioL1N5kDKSm8M5AAIFP5jSOZ4098.jpg
http://s3.运维网.com/wyfs02/M00/28/6C/wKioL1N5kEfyHb5GAAHQ2SleL4s408.jpg
说明:直接访问mogilefs提供的文件存储路径,访问正常;
结合Nginx,从前端访问测试
http://s3.运维网.com/wyfs02/M02/28/6C/wKioL1N5kHqRsxb9AAG1O1WVluU610.jpg
http://s3.运维网.com/wyfs02/M00/28/6C/wKioL1N5kI-Rfe30AAFcrLcKYOM853.jpg
说明:通过前端Nginx访问图片和文本文件一切正常,实现了对前端访问的透明性;
3.8 后续扩展
结合LNMT的架构,再通过Haproxy进行前端调度,就可以使用MogileFS这个分布式存储系统完全替代NFS,实现对图片文件和文本文件的存储和读写;
鉴于MogileFS的无目录性,无法直接挂载使用,故向mogilefs集群中添加文件则需要程序通过API调用上传(upload)文件,虽然对于运维人员有点不方便,但也保证了一定的高效性;
如果想体验直接挂载使用分布式文件系统的乐趣,则可以尝试使用MooseFS,在此就不多说了!
页:
[1]