1、请描述本地文件系统和分布式文件系统的特点
本地文件系统
本地文件系统主要是指Ext2,Ext3,Btrfs,XFS这类,它们通常提供以下功能:
- 扩展性:随着系统容量的增加保持性能,不随容量变化而导致性能震荡。比如一个目录下的海量文件,在EXT2/3中由于目录设计问题会导致较大的性能问题。再比如EXT2/3中的Metadata的占用和inode的划分可能会导致空间的浪费。
-
数据一致性
- Checksum: Checksum与对应的数据块分开放置,避免silent corruption
- COW事务: COW事务参考文件系统特性 – COW事务
- Log: Log被一些文件系统用作WAL模式来加快写操作,并且保证写操作的原子性
-
多设备管理:传统上Linux往往使用LVM进行多设备的管理,现代文件系统往往增加对多设备的支持。如ZFS和Btrfs会有存储池模型对应LVM的逻辑卷组,文件系统会对底层的多设备进行并行的访问。
- 快照和克隆:采用COW事务模型的文件系统通常具有这个特性
- 软件RAID支持:现代文件系统通过对多设备的管理可以很好的支持软件RAID,如Btrfs对Metadata进行RAID1的默认保护
- 针对SSD的优化: 除了SSD对于随机读这一特性的优化外,还有对SSD擦除操作的优化。另外,SSD在使用容量接近100%时会导致极差的写入性能,文件系统也可以对SSD的分配策略和重平衡进行一定的优化。
- 压缩和加密: 现在的IO速度远远跟不上CPU的发展,因此对磁盘文件进行压缩读写是个很好的选择,现代文件系统往往支持多种压缩格式,而且可以支持整个文件系统的加密或者某个文件和目录的加密
- 去重: 文件系统系统去重是个大话题,主要是计算块的checksum方法或者客户端计算文件的hash来决定是否是一个新文件。
分布式文件系统
分布式文件系统的架构和实现有非常大的差异,如NFS这种传统的基于存储服务器的网络文件系统,基于SAN的GPFS,然后现在的集群式架构,比如HDFS这种有中心的分布式,如GlusterFS这种无中心分布式,再如Ceph这种部分在内核态部分在用户态等等。
NFS
GPFS
HDFS
GlusterFS
由于架构上的差异和本身文件系统的设计目标,通常分布式文件系统可以根据接口类型分成块存储、对象存储和文件存储。如Ceph具备块存储(Experiment)、文件存储和对象存储的能力,GlusterFS支持对象存储和文件存储的能力。而MogileFS只能作为对象存储并且通过key来访问。
- 扩展能力: 毫无疑问,扩展能力是一个分布式文件系统最重要的特点。分布式文件系统中元数据管理一般是扩展的重要问题,GFS采用元数据中心化管理,然后通过Client暂存数据分布来减小元数据的访问压力。GlusterFS采用无中心化管理,在客户端采用一定的算法来对数据进行定位和获取。
- 高可用性: 在分布式文件系统中,高可用性包含两层,一是整个文件系统的可用性,二是数据的完整和一致性。整个文件系统的可用性是分布式系统的设计问题,类似于NOSQL集群的设计,比如有中心分布式系统的Master服务器,网络分区等等。数据完整性则通过文件的镜像和文件自动修复等手段来解决,另外,部分文件系统如GlusterFS可以依赖底层的本地文件系统提供一定支持。
- 协议和接口: 分布式文件系统提供给应用的接口多种多样,Http RestFul接口、NFS接口、Ftp等等POSIX标准协议,另外通常会有自己的专用接口。
- 弹性存储: 可以根据业务需要灵活地增加或缩减数据存储以及增删存储池中的资源,而不需要中断系统运行。弹性存储的最大挑战是减小或增加资源时的数据震荡问题。
- 压缩、加密、去重、缓存和存储配额: 这些功能的提供往往考验一个分布式文件系统是否具有可扩展性,一个分布式文件系统如果能方便的进行功能的添加而不影响总体的性能,那么这个文件系统就是良好的设计。这点GlusterFS就做的非常好,它利用类似GNU/Hurd的堆栈式设计,可以让额外的此类功能模块非常方便的增加。
2、总结常用的分布式文件系统的应用场景及常规的维护方式;
常见的分布式文件系统有,GFS、HDFS、Lustre 、Ceph 、GridFS 、mogileFS、TFS、FastDFS等。各自适用于不同的领域。它们都不是系统级的分布式文件系统,而是应用级的分布式文件存储服务。
GFS(Google File System)
Google公司为了满足本公司需求而开发的基于Linux的专有分布式文件系统。。尽管Google公布了该系统的一些技术细节,但Google并没有将该系统的软件部分作为开源软件发布。
下面分布式文件系统都是类 GFS的产品。
HDFS
Hadoop 实现了一个分布式文件系统(hadoop Distributed File System),简称HDFS。 Hadoop是Apache Lucene创始人Doug Cutting开发的使用广泛的文本搜索库。它起源于Apache Nutch,后者是一个开源的网络搜索引擎,本身也是Luene项目的一部分。Aapche Hadoop架构是MapReduce算法的一种开源应用,是Google开创其帝国的重要基石。
Ceph
是加州大学圣克鲁兹分校的Sage weil攻读博士时开发的分布式文件系统。并使用Ceph完成了他的论文。
说 ceph 性能最高,C++编写的代码,支持Fuse,并且没有单点故障依赖, 于是下载安装, 由于 ceph 使用 btrfs 文件系统, 而btrfs 文件系统需要 linux 2.6.34 以上的内核才支持。可是ceph太不成熟了,它基于的btrfs本身就不成熟,它的官方网站上也明确指出不要把ceph用在生产环境中。
Lustre
Lustre是一个大规模的、安全可靠的,具备高可用性的集群文件系统,它是由SUN公司开发和维护的。
该项目主要的目的就是开发下一代的集群文件系统,可以支持超过10000个节点,数以PB的数据量存储系统。
目前Lustre已经运用在一些领域,例如HP SFS产品等。
MogileFS
由memcahed的开发公司danga一款perl开发的产品,目前国内使用mogielFS的有图片托管网站yupoo等。
MogileFS是一套高效的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上。
MogileFS由3个部分组成:
第1个部分是server端,包括mogilefsd和mogstored两个程序。前者即是 mogilefsd的tracker,它将一些全局信息保存在数据库里,例如站点domain,class,host等。后者即是存储节点(store node),它其实是个HTTP Daemon,默认侦听在7500端口,接受客户端的文件备份请求。在安装完后,要运行mogadm工具将所有的store node注册到mogilefsd的数据库里,mogilefsd会对这些节点进行管理和监控。
第2个部分是utils(工具集),主要是MogileFS的一些管理工具,例如mogadm等。
第3个部分是客户端API,目前只有Perl API(MogileFS.pm)、PHP,用这个模块可以编写客户端程序,实现文件的备份管理功能。
mooseFS
持FUSE,相对比较轻量级,对master服务器有单点依赖,用perl编写,性能相对较差,国内用的人比较多
MooseFS与MogileFS的性能测试对比
FastDFS
是一款类似Google FS的开源分布式文件系统,是纯C语言开发的。
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
TFS(Taobao !FileSystem)
是一个高可扩展、高可用、高性能、面向互联网服务的分布式文件系统,主要针对海量的非结构化数据,它构筑在普通的Linux机器 集群上,可为外部提供高可靠和高并发的存储访问。TFS为淘宝提供海量小文件存储,通常文件大小不超过1M,满足了淘宝对小文件存储的需求,被广泛地应用 在淘宝各项应用中。它采用了HA架构和平滑扩容,保证了整个文件系统的可用性和扩展性。同时扁平化的数据组织结构,可将文件名映射到文件的物理地址,简化 了文件的访问流程,一定程度上为TFS提供了良好的读写性能。
官网 : http://code.taobao.org/p/tfs/wiki/index/
GridFS文件系统
MongoDB是一种知名的NoSql数据库,GridFS是mongodb的一个内置功能,它提供一组文件操作的API以利用MongoDB存储文件,GridFS的基本原理是将文件保存在两个Collection中,一个保存文件索引,一个保存文件内容,文件内容按一定大小分成若干块,每一块存在一个Document中,这种方法不仅提供了文件存储,还提供了对文件相关的一些附加属性(比如MD5值,文件名等等)的存储。文件在GridFS中会按4MB为单位进行分块存储。
MongoDB GridFS 数据读取效率 benchmark
3、从理论原理到实战案例来阐述MogileFS体系
简介
MogileFS是一个开源的分布式文件存储系统,由LiveJournal旗下的DangaInteractive公司开发。Danga团队开发了包括 Memcached、MogileFS、Perlbal 等多个知名的开源项目。目前使用MogileFS 的公司非常多,如日本排名先前的几个互联公司及国内的yupoo(又拍)、digg、豆瓣、1号店、大众点评、搜狗和安居客等,分别为所在的组织或公司管理着海量的图片。
MogileFS组成部分
MogileFS由3个部分组成:
1、server:主要包括mogilefs和mogstored两个应用程序。mogilefs实现的是tracker,它通过数据库来保存元数据信息,包括站点domain、class、hots等;mogstored是存储节点(storgenode’),它其实是个WsbDAV服务,默认监听在7500 端口,接受客户端的文件存储请求。在Mogilefs安装完后,要运行mogadm工具将所有storge node注册到mogilefs的数据库里,mogilefs会对这些节点进行管理和监控。
2、utils(工具集):主要是Mogilefs的一些管理工具,例如mogadm等
3、客户端API:mogilefs的客户端API很多,例如Perl、PHP、java、python等,用这个模块可以编写客户端程序,实现文件的备份管理功能等;
MogileFS特性
1、 工作与应用层
2、 无单点:三大组件(tracker、mogstore,database)皆可实现高可用;
3、 自动完成文件复制:复制的最小单位不是文件,而是class,文件可以被自动复制到多个有足够存储空间的存储节点上;
4、 传输无需特殊协议:可以通过NFS或HTTP协议进行通信;
5、 名称空间:文件通过一个给定的key来确定,是一个全局的命名空间,没有目录基于域实现文件隔离;
6、 不共享任何数据:无需通过昂贵的SAN来共享磁盘,每个存储节点只需维护自己所属的存储设备(device);
MogileFS原理
术语解释
tracker:借助数据库保存各个节点的元数据信息,便于检索定位数据位置并监控各个节点,告知客户端存储区的位置并指挥storage节点复制数据副本,进程为mogilefsd
database:为tracker节点存储节点文件的元数据信息;
storage:将指定域中的键转换我I特有的文件名存储与在特定的设备文件中,转换后文件名为值,storage自动维护键值之间的对应关系,storage节点使用http进行数据传输,依赖于perbl,进程为mogstored,perbal;
Domain:一个域中的键值为唯一的,一个Mogilefs可以有多个域来存储不同类型的文件;
Class:复制的最小单位,管理文件属性,定义文件存储在不同设备上的分数;
device:一个存储节点,可以有多个device,就是用来存放文件的目录,每个设备都有一个设备ID,需要在mogstored配置文件中docroot配置,设备不能删除,只能将设备的状态置为dead,置为dead之后数据就无法恢复了,并且设备ID也无法使用。(建议每个节点只有一个device,文件存储多份时,有多余数据备份在当前节点其他设备,等于没有备份,若只备份2份,节点发生故障,数据就会丢失);
Mogilefs架构图
上图为Mogilefs架构图,下面也描述了图中体现出一次数据请求过程。
1、 客户端在发起一次数据请求,假设请求banner.jpg,请求首先到达前端代理perbal(当然此处可利用Nginx实现)
2、 perbal或nginx会将请求代理至Mogilefs client(这里解释下,MogileFS本身就是一个Web服务可以提高返回数据信息,不过普通的浏览器或web客户端是不具备利用获取的Mogilefs返回的数据位置信息再次请求storage节点获取数据的,所以此处需要一个特定的客户端来访问Mogilefs,而此客户端在Nginx代理时,是nginx的特定的模块。)
3、 mogilefs client模块将请求发往trackers节点,trackers向DB server发起查询
4、 tracker将以banner.jpg为key查询到的vlaue值发给nginx。
5、 Nginx通过Mogilefs API向storage 节点请求数据。
这就是一次完整的数据获取过程。
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.实验步骤:
(1).安装、配置mysql 172.16.41.5
1 yum -y install mariadb-server mariadb
2
3
4
5
6
7
8
9
10
|
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;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
yum -y install perl-IO-AIO perl-Net-Netmask perl-core #解决perl依赖关系
#→下面这些包是Tracker和Storage端必装的程序包.
yum -y install *.rpm
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-Utils-2.19-1.el6.noarch.rpm
perl-5.10.1-144.el6.i686.rpm
Perlbal-1.78-1.el6.noarch.rpm
Perlbal-doc-1.78-1.el6.noarch.rpm
perl-Danga-Socket-1.61-1.el6.rf.noarch.rpm
perl-MogileFS-Client-1.14-1.el6.noarch.rpm
perl-Net-Netmask-1.9015-8.el6.noarch.rpm
perl-Perlbal-1.78-1.el6.noarch.rpm
注意:
mogilefs 0.25模块会导致MogileFS复制不正常 , 发现文件少于指定的份数
解决方法
如果发现是显示上面的 0.25 就一定会出问题.建议退回到 0.23 就不会在出问题了.
所以建议大家在安装完 MogileFS 后,先退回这个模块到 0.23.
perl -MSys::Syscall -e ‘print $Sys::Syscall::VERSION’ #查看版本
wget http://search.cpan.org/CPAN/authors/id/B/BR/BRADFITZ/Sys-Syscall-0.23.tar.gz
perl Makefile.PL
make
make install
|
1
2
|
#→安装好tracker后会在/var/run/下面生成该目录,改变目录属主.属组
[root@node1 ~]# chown -R mogilefs.mogilefs /var/run/mogilefsd
|
1
|
[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配置文件,如下内容:
1
2
3
4
5
6
|
[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 = 0.0.0.0:7001
|
<5>修改storage配置文件,如下内容:
1
2
3
4
5
6
7
8
|
[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上存储的实际位置,建议使用的是一个单独挂载使用的磁盘.这里我就不用演示了.
pidfile = /var/run/mogilefsd/mogstored.pid
[root@node1 ~]# mkdir -p /data/mogdata/dev1
#→这里一定要改变数据存放目录的属主属组,应为mogilefs服务程序必须是以普通用户来运行的,否则服务启动将失败!
[root@node1 ~]# chown -R mogilefs.mogilefs /data/mogdata/dev1
|
<6>启动tracker和storage服务:
1
2
3
4
5
|
[root@node2 ~]# service mogilefsd start
Starting mogilefsd [ OK ]
[root@node2 ~]# service mogstored start
Starting mogstored [ OK ]
[root@node2 ~]#
|
<7>在node1上面将自己添加mogstore存储主机
1
|
[root@node1 ~]# mogadm –trackers=172.16.41.1:7001 host add 172.16.41.1
–ip=172.16.41.1 –status=alive
|
下面继续配置:
<8>现将两个配置文件拷贝至两个节点中–要保证各个程序包都已经安装了,否则在拷贝后安装会覆盖两个配置文件.
1
2
3
4
5
6
7
|
[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.
1
2
|
#→安装好tracker后会在/var/run/下面生成该目录,改变目录属主.属组
[root@node2 ~]# chown -R mogilefs.mogilefs /var/run/mogilefsd
|
<4>修改tracker配置文件,如下内容:
1
2
3
4
5
6
|
[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 = 0.0.0.0:7001
|
<5>修改storage配置文件,如下内容:
1
2
3
4
5
6
7
8
|
[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服务:
1
2
3
4
5
|
[root@node2 ~]# service mogilefsd start
Starting mogilefsd [ OK ]
[root@node2 ~]# service mogstored start
Starting mogstored [ OK ]
[root@node2 ~]#
|
<7>在node1上面将自己添加mogstore存储主机
1
|
[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集群系统
1
2
3
4
5
6
7
|
#→添加的第一个设备,设备号不能重名
[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—–域用来存储不同应用类型的数据的容器
1
2
3
4
5
|
#→创建的图片存放域
[root@node1 ~]# mogadm –trackers=172.16.41.1:7001 domain add images
#→创建的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
1
2
3
4
5
6
7
|
[root@node1 ~]# mogadm –trackers=172.16.41.1:7001 class add images class0 –mindevcount=2
[root@node1 ~]# mogadm –trackers=172.16.41.1:7001 class add images class1 –mindevcount=2
[root@node1 ~]# mogadm –trackers=172.16.41.1:7001 class add images 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进行交互的。
1
2
3
|
[root@node1 ~]# mogupload –trackers=172.16.41.1:7001 –domain=images –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
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
|
#这里需要安装个pcre-devel包
[root@node ~]# yum install -y pcre-devel
#解压获取到的mogilefs模块包
[root@node4 ~]# tar -zxvf nginx_mogilefs_module-1.0.4.tar.gz
#解压、编译安装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-1.0.4
make
make install
make时出现以下错误,解决办法:# vim objs/Makefile (修改objs/Makefile文件,
“去掉其中的”-Werror” CFLAGS = -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -g ),
然后就能够正常编译了. 先./configure 后在删除,最后make
/root/nginx-mogilefs-module-master/ngx_http_mogilefs_module.c:748:37: 错误:变量‘request’被设定但未被使用 [-Werror=unused-but-set-variable]
ngx_str_t request, domain;
^
/root/nginx-mogilefs-module-master/ngx_http_mogilefs_module.c: 在函数‘ngx_http_mogilefs_create_spare_location’中:
/root/nginx-mogilefs-module-master/ngx_http_mogilefs_module.c:1541:39: 错误:变量‘pclcf’被设定但未被使用 [-Werror=unused-but-set-variable]
ngx_http_core_loc_conf_t *clcf, *pclcf, *rclcf;
^
cc1: all warnings being treated as errors
make[1]: *** [objs/addon/nginx-mogilefs-module-master/ngx_http_mogilefs_module.o] 错误 1
make[1]: 离开目录“/root/nginx-1.10.3”
make: *** [build] 错误 2
|
2.为nginx提供SysV init脚本:
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
[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主配置文件:
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
37
38
39
40
41
42
43
44
45
|
[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 images###############
location /images/ {
mogilefs_tracker 172.16.41.1:7001;
mogilefs_domain images;
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 images;
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这段内容即可,这种方式定义images也一样适用,先看看效果吧.
重新加载nginx、再次访问测试:
这两种定义方法可根据实际场景应用!
朋友们大概注意到了我在nginx的配置文件中,只是配置了将客户端请求代理到后端的一台tracker上面,如果要将多个tracker基于负载均衡的方式来提供服务,于是我们就需要定义upstream啦;请看以下配置:
重新加载nginx、再次访问测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
####################################################################
#→显示当前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=images –key=”tux_1.jpg”
####################################################################
#→上传一个本地文件到指定的域内,同时必须指定key.
[root@node1 ~]# mogupload –trackers=172.16.41.1:7001 –domain=images –key=’tux_1.jpg’ –file=’/root/my_test_data/1.jpg’
####################################################################
#→删除指定域内的一个key.
[root@node1 ~]# mogdelete –trackers=172.16.41.1:7001 –domain=images –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”!
|
4、自动化运维工具ansible的应用实例
1.ansible
ansible是新出现的自动化运维工具,基于Python研发。糅合了众多老牌运维工具的优点实现了批量操作系统配置、批量程序的部署、批量运行命令等功能。仅需在管理工作站上安装ansible程序配置被管控主机的IP信息,被管控的主机无客户端。ansible应用程序存在于epel(第三方社区)源,依赖于很多python组件
参考站点:http://www.ansible.com.cn
2.ansible特性
模块化设计,调用特定的模块来完成特定任务,本身是核心组件,短小精悍;
基于Python语言实现,由Paramiko(python的一个可并发连接ssh主机功能库), PyYAML和Jinja2(模板化)三个关键模块实现;
部署简单,agentless无客户端工具;
主从模式工作;
支持自定义模块功能;
支持playbook剧本,连续任务按先后设置顺序完成;
期望每个命令具有幂等性:
3.ansible架构
ansible core:ansible自身核心模块
host inventory:主机库,定义可管控的主机列表
connection plugins:连接插件,一般默认基于ssh协议连接
modules:core modules(自带模块)、custom modules(自定义模块)
playbooks:剧本,按照所设定编排的顺序执行完成安排任务
4.配置文件:
(1)ansible应用程序的主配置文件:/etc/ansible/ansible.cfg
(2) Host Inventory定义管控主机:/etc/ansible/hosts
遵循INI风格;中括号中的字符是组名;一个主机可同时属于多个组;
示例:
# Ex 1: Ungrouped hosts, specify before any groupheaders.直接在任何组的头部前面指定,不属于任何组的主机
green.example.com
blue.example.com
192.168.100.1
192.168.100.10
# Ex 2: A collection of hosts belonging to the’webservers’ group;一批主机属于一个组,例如定义为‘webservers’的组
[webservers]
alpha.example.org
beta.example.org
192.168.1.100
192.168.1.110
注意:默认是以root用户执行,但是基于ssh连接操作要多次输入密码,为方便可以使用基于ssh密钥方式进行认证
二、ansible应用程序命令
1.ansible-doc命令:获取模块列表,及模块使用格式;
ansible-doc -l:获取列表
ansible-doc -s module_name:获取指定模块的使用信息
2.ansible命令格式
ansible <host-pattern> [-f forks] [-m module_name] [-a args]
<host-pattern> |
指明管控主机,以模式形式表示或者直接给定IP,必须事先定义在文件中;all设置所有 |
[-f forks] |
指明每批管控多少主机,默认为5个主机一批次 |
[-m module_name] |
使用何种模块管理操作,所有的操作都需要通过模块来指定 |
[-a args] |
指明模块专用参数;args一般为key=value格式 注意:command模块的参数非为kv格式,而是直接给出要执行的命令即可; |
注意:<host-pattern>默认读取/etc/ansible/hosts,也可以指明自定义文件路径
-iPATH, –inventory=PATH:指明使用的host inventory文件路径;
常用模块(module_name):
1)command:默认模块,可省略。在远程主机上进行操作命令
-a ‘COMMAND’
注意:comand模块的参数非key=value格式,直接给出要执行的命令
[root@localhost ~]# ansible all -m command -a ‘ifconfig’
2)user:
-a ‘name= state={present(创建)|absent(删除)} force=(是否强制操作删除家目录) system= uid= shell= home=’
[root@localhost ~]# ansible all -m user -a ‘name=ansible state=present’
3)group:
-a ‘name= state={present|absent} gid= system=(系统组)‘
[root@localhost ~]# ansible all -m group -a ‘name=mygroup state=presentsystem=true’
4)cron:
-a ‘name= state= minute= hour= day= month= weekday= job=’
[root@localhost ~]# ansible all -m cron -a ‘name=’Time’ state=presentminute=’*/5′ job=’/usr/sbin/ntpdate 172.168.0.1 &> /dev/null”
5)ping:
无参数
[root@localhost ~]# ansible all -m ping
6)file:文件管理
-a ‘path= mode= owner= group= state={file|directory|link|hard|touch|absent} src=(link,链接至何处)‘
[root@localhost ~]# ansible all -m file -a ‘path=/tmp/testdirstate=directory’
[root@localhost ~]# ansible all -m file -a ‘path=/tmp/test.txt state=touchmod=600 owner=user1’
7)copy:
-a ‘dest=(远程主机上路径) src=(本地主机路径) content=(直接指明内容) owner= group= mode=’
[root@localhosttmp]# ansible web -m copy -a ‘src=/etc/yum.repos.d/aliyun.repodest=/etc/yum.repos.d/’
8)template
-a ‘dest= src=\’#\'” content= owner= group= mode=’
9)yum:
-a ‘name= conf_file=(指明配置文件) state={present|latest|absent} enablerepo= disablerepo=’
[root@localhost ~]# ansible all -m yum ‘name=httpd state=present’
10)service:
-a ‘name= state={started|stopped|restarted} enabled=(是否开机自动启动) runlevel=’
[root@localhost ~]# ansible all -m service -a ‘name=httpd state=started’
11)shell:
-a ‘COMMAND’ 运行shell命令
[root@localhost ~]# ansible all -m shell -a echo “123456789” |passwd –stdin user1′
12)script:
-a ‘/PATH/TO/SCRIPT’运行脚本
[root@localhost ~]# ansible all -m script -a ‘/tmp/a.sh’
13)setup:获取指定主机的facts变量;
三、Playbooks剧本
1.playbook组织格式:YAML语言格式
playbooks是ansible更强大的配置管理组件,实现基于文本文件编排执行的多个任务,且多次重复执行
(1)YAML简介
YAML:YAML Ain’t Markup Language; Yet Another Markup Language;
类似于半结构化数据,声明式配置;可读性较高的用来表达资料序列的格式,易于与脚本语言交互
官方站点:http://www.yaml.org
(2)语法格式
1)任何书记结构都用缩进来标识,可以嵌套
2)每一行是一个键值数据key:value,冒号隔开。若想在一行标识需要用{ }和,分隔格式
3)列表用 – 标识
2.inventory参数:主机库ssh参数设置
ansible基于ssh连接inventory中指定的远程主机时,将以此处的参数指定的属性进行;
ansible_ssh_port |
指定ssh端口 |
ansible_ssh_user |
指定ssh用户 |
ansible_ssh_pass |
指定ssh用户登录是认证密码,明文密码不安全 |
ansible_sudo_pass |
指明sudo时候的密码 |
实例:
[websrvs]
192.168.0.101 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=xuding
192.168.0.102
注意:在/etc/ansible/hosts中直接定义连接时候的密码不安全,一般建议基于ssh的密钥认证方式实现
3.playbooks
(1)核心元素
Tasks任务、Variables变量、Templates模板、Handlers处理器、Roles角色
(2)playbooks中定义任务:
– name: task description 注释描述信息
module_name: module_args 声明模块:定义ansible模块参数
(3)ansible-playbook执行命令:
ansible-playbook <filename.yml> … [options]
4.playbook— 变量
(1)变量命名:字母、数字和下划线组成,仅能以字母开头;
(2)变量种类:
1)facts:由远程主机发回的主机特有的属性信息,这些信息被保存在ansible变量中;无须声明,可直接调用;
2)自定义变量:
通过命令行传递:ansible-playbook test.yml –extra-vars “host=www user=test”
通过roles传递
3)主机变量:定义在inventory中的主机之后的变量;直接传递给单个主机的变量
实例:
[root@localhost ~]# vim /etc/ansible/hosts中直接定义在主机之后
[web]
192.168.0.101 host=mail
192.168.0.102
192.168.0.103
4)组变量:定义在inventory中的组上的变量(例如在默认的文件/etc/ansible/hosts上编辑)
[group_name:vars]
var1=value
var2=value
注意:组名要事先存在,实例如下:
[websrvs]
192.168.0.101
192.168.0.102
[websrvs:vars]
host=mail
变量使用示例:
[root@localhost~]# vim useradd.yml
– hosts: websrvs
remote_user: root
vars:
username: testuser
password: xuding
tasks:
-name: add user
user: name={{ username }} state=present
-name: set password
shell: /bin/echo {{ password }} |/usr/bin/passwd –stdin {{ username }}
注释:
1) {{ }} 调用变量
2) #ansible-playbook /PATH/TO/SOME_YAML_FILE { -eVARS|–extra-vars=VARS} 变量的重新赋值调用方法
[root@localhost ~]# ansible-playbookuseradd.yml –extra-vars “username=ubuntu”
5.playbook— tasks
(1)条件测试:
在某task后面添加when子句即可实现条件测试功能;when语句支持Jinja2语法;
实例:当时RedHat系列系统时候调用yum安装
tasks:
-name: install web server package
yum: name=httpd state=present
when: ansible_os_family == “RedHat”
(2)迭代:item
在task中调用内置的item变量;在某task后面使用with_items语句来定义元素列表;
tasks:
-name: add four users
user: name={{ item }} state=present
with_items:
-testuser1
-testuser2
-testuser3
-testuser4
注意:迭代中,列表中的每个元素可以为字典格式;
实例:
-name: add two users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
– { name: ‘testuser5’, groups: ‘wheel’ }
– { name: ‘testuser6’, groups: ‘root’ }
6.playbook— handlers:处理器;触发器
只有其关注的条件满足时,才会被触发执行的任务;
实例:配置文件发生改变触发重启服务
-hosts: websrvs
remote_user: root
tasks:
-name: install httpd
yum:name=httpd state=present
-name: install config file
copy: src=/root/httpd.confdest=/etc/httpd/conf/httpd.conf
notify: restart httpd
-name: start httpd service
service: name=httpd state=started
handlers:
-name: restart httpd
service: name=httpd state=restarted
7.playbook模板
templates:
用于生成文本文件(配置文件);模板文件中可使用jinja2表达式,表达式要定义在{{}},也可以简单地仅执行变量替换;
roles:
roles用于实现“代码复用”;
roles以特定的层次型格式组织起来的playbook元素(variables,tasks, templates, handlers);
可被playbook以role的名字直接进行调用;
用法:在roles/下建立[group_name]子目录,并非全部都要创建;例如:
/etc/ansible/roles/(在/etc/ansible/ansible.cfg定义roles目录)
webserver/
files/:此角色中用到的所有文件均放置于此目录中;
templates/:Jinja2模板文件存放位置;
tasks/:任务列表文件;可以有多个,但至少有一个叫做main.yml的文件;
handlers/:处理器列表文件;可以有多个,但至少有一个叫做main.yml的文件;
vars/:变量字典文件;可以有多个,但至少有一个叫做main.yml的文件;
meta/:此角色的特殊设定及依赖关系;
原创文章,作者:N27_Vicent,如若转载,请注明出处:http://www.178linux.com/84059
评论列表(1条)
文章的广度和深度让人印象深刻,再接再励。