http://blog.prosight.me/index.php/2011/12/848
http://shen2.cn/2010/08/distributed-filesystems/
http://os.51cto.com/art/201011/233441.htm
Gluster集群文件系统研究
http://blog.csdn.net/liuben/article/details/6284551
如下功能:
考虑到Gluster不同模式针对的场景有所不同,方案应该针对不同的读写场景(文件大小,并发访问量)等,制定不同的策略。
Striped: 把一个数据划分为几个数据集(把大数据分成100个数据块,划到StripedNum个数据集中)不是大数据最好别做,放在一个地方存Cache命中率高。StripedNum = BricksNum
gluster volume create test-volume stripe 2 transport tcp server1:/exp1 server2:/exp2
Distributed Striped:文件在一个Server内部的不同bricks做条带化,尽量 把不同文件放在不同的Server上。N * StripedNum = BricksNum
gluster volume create test-volume stripe 4 transport tcp server1:/exp1 server2:/exp2 server3:/exp3 server4:/exp4 server5:/exp5 server6:/exp6 server7:/exp7 server8:/exp8
Replicated:高可用(文件在不同的Server上有副本);有副本后可以提高读性能 ReplicatedNum = BricksNum ?
gluster volume create test-volume replica 2 transport tcp server1:/exp1 server2:/exp2
Distributed Replicated:高可用(文件在不同的Server上有副本);有副本后可以提高读性能 N * ReplicatedNum = BricksNum
gluster volume create test-volume replica 2 transport tcp server1:/exp1 server2:/exp2 server3:/exp3 server4:/exp4
Striped Replicated:for MapReduce任务,一个文件打碎后,文件块在多个Server上 StripedNum * ReplicatedNum = BricksNum
Distributed Striped Replicated:for MapReduce任务,一个文件打碎后,文件块在多个Server上 N*StripedNum * ReplicatedNum = BricksNum
划分为多个Stripe能增加,如果本地磁盘读写800MB,而单节点网络带宽只有100MB,那么网络带宽是瓶颈,应该划分Stripe
从目前看来,划volume是由管理员指定bricks,那么这是不是没有实现自动负载均衡?
具体任务:
Server:201-204, port:241.101
Gluster安装配置(CentOS,)
一、安装
参考Installation_Guide
1.Install required prerequisites on the server using the following command
yum -y install wget fuse fuse-libs
2. Download the latest GlusterFS core and FUSE RPM files to each server in your cluster
(1)在http://bits.gluster.com/pub/gluster/glusterfs/3.3.0/x86_64/ 下载
glusterfs-3.3.0-1.x86_64.rpm
glusterfs-fuse-3.3.0-1.x86_64.rpm
glusterfs-geo-replication-3.3.0-1.x86_64.rpm
glusterfs-server-3.3.0-1.x86_64.rpm
安装glusterfs-3.3.0-1.x86_64.rpm时候如果报出如下的错误:
执行:#>yum install openssl098e
安装 glusterfs-server-3.3.0-1.x86_64.rpm如果报出如下的错误:
执行:#>yum install compat-readline5 compat-libtermcap
3.使用xfs格式化文件系统
[root@localhost zhxue]# yum install -y xfs,如果报错,执行
yum install -y xfs*
二、配置
1、启动服务(用chkconfig加入系统服务启动列表中,开机自动启动)
[root@serv202 ~]# /etc/init.d/glusterd start; chkconfig glusterd on
2、创建节点信任池
gluster peer probe server1
gluster peer probe server2
gluster peer probe server3
gluster peer probe server4
若遇到下面情况,可参考下面方案解决
[root@localhost zhxue]# gluster peer probe gluster002
Probe unsuccessful
Probe returned with unknown errno 107
发现 no route to server2
想到节点之间是互通的,估计是防火墙阻碍了gluster相关端口,关闭后即可。当然最好是打开对应的端口,而不要关掉整个防火墙。
3、创建卷
[root@gluster001 ~]# gluster volume create volsdb replica 2 transport tcp gluster001:/sdb gluster002:/sdb gluster003:/sdb gluster004:/sdb
Creation of volume volsdb has been successful. Please start the volume to access data.
[root@gluster001 ~]# gluster volume info
Volume Name: volsdb
Type: Distributed-Replicate
Volume ID: 7189d2f7-db94-4b79-9a22-87b9814672ec
Status: Created
Number of Bricks: 2 x 2 = 4
Transport-type: tcp
Bricks:
Brick1: gluster001:/sdb
Brick2: gluster002:/sdb
Brick3: gluster003:/sdb
Brick4: gluster004:/sdb
4、启动卷并挂载
在服务器端:[root@gluster001 ~]# gluster volume start volsdb
在客户端: sudo mount -t glusterfs gluster001:/volsdb /mnt/zhxue
挂载成功后,发现/mnt/zhxue的容量只有500+GB,一直不明白原因,重挂载几次后问题依旧。后来发现,在gluster002-gluster004上没有把磁盘挂上来,即忘了mount /dev/sdf等设备到本地磁盘/localdisk/sdf。相当于只有一个节点在服务。
后来正确执行后,不用再重新建卷或停止、启动卷,看到了8T的目录大小。挺智能,还不错。
5、删除卷
先停止,再删
[root@gluster001 ~]# gluster volume stop volsdd-test
停止后,客户端df命令,看不到所挂载的卷了。但用mount或cat /proc/mounts 还是能看到挂载。
此时,如果再启动被停止的卷。df命令就可以看到磁盘了,不需要重新挂载(这是因为mount点并没有被撤销)
[root@gluster001 ~]# gluster volume delete volsdd-test
如果删除了,客户端还是df看不到,mount可以看到。客户端只好umount,一切正常。
6、删除卷
root@new-2:/home/ubuntu# dd if=/dev/zero of=/mnt/10gfile bs=1MB count=1024x10
10240+0 records in
10240+0 records out
10240000000 bytes (10 GB) copied, 392.422 s, 26.1 MB/s
1024000000 bytes (1.0 GB) copied, 34.7465 s, 29.5 MB/s
setfattr -x trusted.glusterfs.volume-id /localdisk/sdc/rep4; setfattr -x trusted.gfid /localdisk/sdc/rep4; rm -rf /localdisk/sdc/rep4/.glusterfs; setfattr -x trusted.glusterfs.volume-id /localdisk/sdd/rep4; setfattr -x trusted.gfid /localdisk/sdd/rep4; rm -rf /localdisk/sdd/rep4/.glusterfs; setfattr -x trusted.glusterfs.volume-id /localdisk/sdb/rep4; setfattr -x trusted.gfid /localdisk/sdb/rep4; rm -rf /localdisk/sdb/rep4/.glusterfs
7.测试结果
7.1、性能测试
root@ubuntuDell:/home/yongyou# dd if=/dev/zero of=/mnt/50g bs=1MB count=1024x50
51200+0 records in
51200+0 records out
51200000000 bytes (51 GB) copied, 461.971 s, 111 MB/s
root@ubuntuDell:/home/yongyou# dd if=/dev/zero of=/var/lib/nova/instances/50g bs=1MB count=1024x50
51200+0 records in
51200+0 records out
51200000000 bytes (51 GB) copied, 994.198 s, 51.5 MB/s
物理机直接挂在gluster上,没有replica时是110MB基本满带宽,replica=2是50MB,replica=3是34MB,线性递减
答案:gluster把所有事情交给客户端了,当rep=2时,其实客户端在向两个gluster server努力写数据,客户端的实际网络流量是100MB,dd命令的带宽计算是根据文件大小除以传输时间,所以看似性能减半。本质是因为客户端传输了2倍的文件量。要想摆平这个问题,只能改写客户端的模式,即让客户端只向一个server写,被写server自己去向server做副本,把写副本事务转嫁给后台gluster服务器。但是这样做会有一个坏处,就是无法保障两个副本严格的一致性。
还发现一个问题,当replica=3时,3个副本在一台机器上,这是相当危险的!!!我们创建副本的脚本如下:
gluster volume create volsdg replica 3 transport tcp gluster001:/localdisk/sdg/test4 gluster001:/localdisk/sdg/test5 gluster001:/localdisk/sdg/test6 gluster002:/localdisk/sdg/test4 gluster002:/localdisk/sdg/test5 gluster002:/localdisk/sdg/test6 gluster003:/localdisk/sdg/test4 gluster003:/localdisk/sdg/test5 gluster003:/localdisk/sdg/test6 gluster004:/localdisk/sdg/test4 gluster004:/localdisk/sdg/test5 gluster004:/localdisk/sdg/test6
上述问题把节点依次错开就没事了,可能后端是轮询算法吧???
虚拟机挂载在gluster上,对自己的某个目录进行写,所挂目录replica=2,虚拟机内存8G:
5G文件 1MB块大小 30.7MB/s (写) 620MB(读)
10G文件 1MB块大小 26.7MB/s (写) 60MB/s(读)
使用raid10(raid0:stripe 2 ; raid1 replica 2)模式做实验的测试结果如下:
gluster volume create volsdg stripe 2 replica 2 transport tcp gluster001:/localdisk/sdg gluster002:/localdisk/sdg gluster003:/localdisk/sdg gluster004:/localdisk/sdg
物理机直接挂在gluster上,对自己的某个目录进行写和读:
20G文件 1MB块大小 48MB/s (写) 106MB(读)
多个计算节点挂同一个卷(4个存储节点各出一个磁盘构成)。
计算节点个数 存储系统带宽
1 100MB
2 200MB
3 240MB
4 220MB
3个就不行了,4个就更差了
这个测试告诉我们:多个节点写同一个卷可能会导致性能急速下滑。于是,我们将10个节点分别挂载在10个卷上(4个存储节点各出一个磁盘构成)
计算节点个数 存储系统带宽
10 1000MB
成功,证明上述推理是正确的。由于2个节点挂同一个卷时,性能还是线性的,于是,我们将20个节点分别挂载在10个卷上(4个存储节点各出一个磁盘构成),每个卷两个计算节点
计算节点个数 存储系统带宽
20 2000MB
也成功。后来经过多方测试,找到了多节点同写一个卷性能急速下滑的问题,如下所示:
这个问题有答案了,把卷的线程数放大到64后就没问题了,最大是65.我们用24个计算节点同时发起2400个进程连续写后端存储,很稳定,网络带宽达到了理想的2.4万兆,每个磁盘带宽都满了130MB左右。
关于Stripe问题
经多方测试,每次写一个文件,当stripe=n时,总容量就会增大n倍,很不合理。后来进行测试,方案如下:
创建一个stripe=8的卷,该卷由一个存储节点的8块磁盘构成。把卷的目录mount到客户端,从客户端写文件,看看最终结果:
1)写文件的脚本:
#!/bin/bash
for((i=0;i<690000;i++))
do
echo $i"****************************" >>mybd
done
2)结果分析
a. 从客户端看这个文件:
root@s201103113:/mnt/zhxuetest# du -smh ./mybd
254M ./mybd
换个命令,看看:
root@s201103113:/mnt/zhxuetest# ll -h ./mybd
-rw-r--r-- 1 root root 21M Jan 10 11:18 ./mybd
相差巨大!!!
把这个文件拷贝到本地目录下再看看:
root@s201103113:/mnt/zhxuetest# du -smh /tmp/mybd
21M /tmp/mybd
root@s201103113:/mnt/zhxuetest# ll -h /tmp/mybd
-rw-r--r-- 1 root root 21M Jan 10 12:12 /tmp/mybd
b. 从后端存储看:
[root@gluster001 sde]# du -smh /localdisk/sdb/3/mybd /localdisk/sdc/3/mybd /localdisk/sdd/3/mybd /localdisk/sde/3/mybd /localdisk/sdf/3/mybd /localdisk/sdg/3/mybd /localdisk/sdh/3/mybd /localdisk/sdi/3/mybd
32M /localdisk/sdb/3/mybd
32M /localdisk/sdc/3/mybd
32M /localdisk/sdd/3/mybd
32M /localdisk/sde/3/mybd
33M /localdisk/sdf/3/mybd
33M /localdisk/sdg/3/mybd
33M /localdisk/sdh/3/mybd
32M /localdisk/sdi/3/mybd
[root@gluster001 sde]# ll -h /localdisk/sdb/3/mybd /localdisk/sdc/3/mybd /localdisk/sdd/3/mybd /localdisk/sde/3/mybd /localdisk/sdf/3/mybd /localdisk/sdg/3/mybd /localdisk/sdh/3/mybd /localdisk/sdi/3/mybd
-rw-r--r-- 2 root root 21M Jan 10 11:18 /localdisk/sdb/3/mybd
-rw-r--r-- 2 root root 21M Jan 10 11:18 /localdisk/sdc/3/mybd
-rw-r--r-- 2 root root 21M Jan 10 11:18 /localdisk/sdd/3/mybd
-rw-r--r-- 2 root root 21M Jan 10 11:18 /localdisk/sde/3/mybd
-rw-r--r-- 2 root root 21M Jan 10 11:18 /localdisk/sdf/3/mybd
-rw-r--r-- 2 root root 21M Jan 10 11:19 /localdisk/sdg/3/mybd
-rw-r--r-- 2 root root 20M Jan 10 11:18 /localdisk/sdh/3/mybd
-rw-r--r-- 2 root root 20M Jan 10 11:18 /localdisk/sdi/3/mybd
8个磁盘的每个文件都有大量的占位符(holes),每间隔256KB的内容就有一行holes,有些节点在开头,有些在中间。
http://comments.gmane.org/gmane.comp.file-systems.gluster.user/9413
It's XFS doing pre-allocation of space (i.e. it doesn't expect you to leave holes in the file, which is how glusterfs striping works). There's a mount option to disable preallocation. Are you sure that striping is what you want, rather than simple distribution? It's appropriate if you have a small number of huge files, but if you are throwing a large number of small to medium-sized files around, distribution may be better. Each file then sits on a single filesystem; if you lose one brick, at least you haven't lost all your files.
http://comments.gmane.org/gmane.comp.file-systems.gluster.user/10373
The default stripe data layout conflicts with XFS default speculative preallocation behavior. XFS preallocates space beyond the end of files and the stripe translator continuously seeks past this space, making it permanent. You can address this by 1.) enabling the cluster.stripe-coalesce translator option in gluster or 2.) setting the allocsize mount option (i.e., allocsize=128k) in XFS. Note that using the latter option will increase the likelihood of fragmentation on the backend filesystem.
使用虚拟机性能折半问题
OpenStack默认是none模式(如果底层支持direct IO),它每次会测试一下底层系统是否支持direct IO,因为Gluster的fuse不支持direct IO,所以它把模式改成了write_Through。我们又把模式改为write_back,性能提升到了60MB,在xml中的配置文件改不了模式,它是后面自动生成的,要改就在:/usr/share/pyshared/nova/virt/libvirt/connection.py
1)看看Direct IO是否有用
现在试用direct IO模式,它的优劣参见:
http://www.makelinux.net/ldd3/chp-15-sect-3
在服务器上的测试结果表明和write through模式性能基本相同。比write behind慢了20MB左右。问题没解决,怎么办?继续找!!!
2)看看异步模式是否有用
我们写了一组测试程序,采用不同的读写模式(通过Open函数加O_sync:同步或者O_ASYNC:异步,等参数),同步、异步,发现异步比同步快很多。于是,我们觉得只要变成异步就ok。
我们首先用strace追踪了一下,看看虚拟机是否使用sync模式打开文件。
于是,满怀信心,想把KVM打开文件的模式改为Async。通过各种方式想在源码里面把aio=native加上去,都不好实现,最后利用Vm manager图形工具把它加上了。这个图形工具还不错,竟然能认到我们用openstack启动的那些虚拟机。拭目以待,迫不及待地开始测试,结果令人大失所望。和以前没什么变化。接下来,怎么办??
3)多线程模式(N对1:N个线程写同一个文件)
继续测!继续想办法解决!
再设计一个新的测试用例,来追踪问题。
虚拟机vm启动后,在其所在的主机host上,查出其进程号PID,用strace 追踪PID的行为,因为不管vm做了什么,都是通过这个PID表现出来的,包括写操作。采用如下命令追踪:其中,ff可以把该进程产生的子进程也可以追出来:
跑完后,把所有日志文件拿出来解析。发现主进程派生出多个子进程(还是多线程?)去执行写操作,写的量恰好是1GB文件,接着把所有数据拿出来(知道每个子进程负责写的文件区域),自己又编写了一个多线程程序去复现KVM的操作。(具体代码见博客:你会用c写文件吗?)
结果发现和我们KVM虚机做的测试性能几乎完全一致。我们又把这个程序跑在一个通过NFS挂载过来的GLuster文件系统上,性能也是100MB!这说明,这个程序基本模拟出来了KVM的写模式。因此,怀疑Gluster对多线程的支持有问题,于是,google后发现:http://www.infostor.com/index/blogs_new/Henry-Newman-Blog/blogs/infostor/Henry-Newman-Blog/post987_55440010.html,不知道这是不是罪魁祸首?
后来我们又把这个程序改了改,让它的Open变为(O——Async),还是用Gluster客户端挂载,结果性能重回100MB!!!
在改Gluster native client源码之前,我们再一次尝试,更改参数看能否有效。看了Gluster文档说不支持write cache。但看到有很多cache的参数,于是更改卷的属性,重新启动卷并重新挂载卷。结果还是不理想,老问题。
performance.cache-max-file-size 10GB
performance.flush-behind ON
performance.write-behind-window-size 2GB
mount -t glusterfs -o async gluster001:/voltest2 /tmp/zhxue/gluster001
春节期间我们做了一个长期测试:共启动了300多个虚机,其中170多个虚机上不停地跑IOZone,结果表明:
1)300多个虚机都在稳定运行;
2)170多个虚机上的IOZone也在持续稳定运行
3)后端四台存储聚合持续带宽550MB
不幸的是,春节回来后发现,性能下降很厉害,虚机只有15MB的性能,做了如下测试来判断问题所在:
1)物理机测试,性能还是100MB
使用NFS重新挂载Gluster,启动虚机,性能15MB
把GLuster弃掉,找一个计算节点作为NFS Server。把虚机映像放到上面,启动虚机,性能20MB
证明Gluster文件系统没问题。
2)重新找一个计算节点,重启后,启动虚机,性能15MB
3)重新搭建一个新的OpenStack,还是用Gluster,启动虚机,性能15MB
qemu对于cache的处理:
根据这篇文章的启示,把util/osdep.c的open函数改掉,让底层调用变为异步。这样无论上层如何,到了最后都是异步方式:
flags |=(!O_SYNC);
flags |=O_ASYNC;
结果没有改变!!
通过测试我们发现,
把一台做了Raid的服务器作为gluster服务器端。虚机性能达到100MB;
把一台基于SSD的服务器作为gluster服务器端。虚机性能达到100MB;
把一台普通服务器的tmpfs作为gluster服务器端。虚机性能达到100MB;
把一台做了Raid,但是raid cache为0的服务器作为gluster服务器端。虚机性能提升20%(70MB左右);
把一台做了Raid,但是raid cache为0的服务器作为gluster服务器端。使用gluster协议直接挂载的虚机性能提升20%(90MB左右);
性能问题又回到了gluster服务器端,之前我们认为服务器端的磁盘写速率在130MB,应该不是性能瓶颈,而且NFS或者物理机直接挂载都是100MB,所以注意力都放在了客户端上。现在问题又回到了gluster服务器端,这是否有矛盾???
后来发现了如下一个帖子,似乎佐证了这个办法:
http://lists.gnu.org/archive/html/gluster-devel/2012-05/msg00088.html
ben>>> While gluster processes do not implement write caching internally, there are at least 3 ways to improve write performance in a Gluster system.
- If you use a RAID controller with a non-volatile writeback cache, the RAID controller can buffer writes on behalf of the Gluster server and thereby reduce latency.
- XFS or any other local filesystem used within the server "bricks" can do "write-thru" caching, meaning that the writes can be aggregated and can be kept in the Linux buffer cache so that subsequent read requests can be satisfied from this cache, transparent to Gluster processes.
- there is a "write-behind" translator in the native client that will aggregate small sequential write requests at the FUSE layer into larger network-level write requests. If the smallest possible application I/O size is a requirement, sequential writes can also be efficiently aggregated by an NFS client.
当我们把server端做成raid0后,问题有出现了,还是50MB。后来把OpenStack里面的写模式由none改成了writethrough。性能重回100MB
7.2可用性测试
1)关掉四台中的任何一台gluster,发现挂载在其上的虚拟机运行正常。
2)关掉虚拟机所挂载的具体两个gluster,发现不正常,重启其中一台gluster后,问题依旧。
root@new-2:/home/ubuntu# mkdir hi
Segmentation fault
root@new-2:/home/ubuntu# mkdir hi
Segmentation fault
root@new-2:/home/ubuntu# cat hi>>hi
bash: hi: Read-only file system
root@new-2:/home/ubuntu# mkdir /mnt/
2gfile 5gfile lost+found/
root@new-2:/home/ubuntu# mkdir /mnt/hi
Segmentation fault
root@new-2:/home/ubuntu# cat hi>>/mnt/hi
cat: hi: No such file or directory
root@new-2:/home/ubuntu# echo hi>>/mnt/hi
出现read-only file system,这种情况通常都是由于系统发现磁盘硬件故障或文件系统中文件被损坏之后而采取的保护机制导致的。为了保护数据不破坏分区中已有内容,Linux在挂载文件系统时就只用read-only只读方式加载了。
上述例子告诉我们:虚拟机的两个目录即根目录和/mnt目录不在同一个gluster上。
把根目录所在的gluster服务器启动一台后,再在根目录下进行任何操作,还是提示无权限(按理说应该一切正常)。
root@new-2:/home/ubuntu# echo hi >>hi
bash: hi: Read-only file system
等了5分钟继续执行上述命令,错误依旧。把两个gluster都起来后,还是问题依旧。只好等明天再看看如何,到了第二天问题依旧。好现象,分析一下吧:
首先,文件是挂载在gluster上的,对于计算节点来说它是gluster的客户端,也就是说这个客户端可能缺乏NFS不断重连服务器的能力,于是研究gluster客户端看能否让其具备该能力。
1)在虚拟机上执行如下操作,均告失败
root@new-2:/home/ubuntu# mount -a
root@new-2:/home/ubuntu# echo test >>/test
bash: /test: Read-only file system
root@new-2:/home/ubuntu# mount -o remount rw /
mount: you must specify the filesystem type
root@new-2:/home/ubuntu# mount -t ext4 -o remount rw /
mount: cannot remount block device rw read-write, is write-protected
root@new-2:/home/ubuntu# mount -o remount rw /
mount: you must specify the filesystem type
root@new-2:/home/ubuntu# echo test >>/test
bash: /test: Read-only file system
2)在虚拟机所在的物理节点上:
root@ubuntuDell:/home/yongyou# umount /var/lib/nova/instances
umount: /var/lib/nova/instances: device is busy.
3)重启了虚拟机,解决。
当replica=2,如果两个存储节点同时坏了,之前所建的文件丢失了!。。。。
Gluster删除卷的问题
执行stop和delete后,再次在所在的brick上创建卷失败。
解决方案
1)在所有gluster服务器的对应brick上执行 for i in `attr -lq .`; do setfattr -x trusted.$i .; done
2)umount客户端所挂的老卷
3)在原先创建老卷的服务器上(其他gluster服务器上不行),重新创建卷
经过多次测试,上述方案有问题(由于gluster004的安装有问题,造成干扰,在其上做先关操作都不行),不是真实原因,真正如下:
1)在所有gluster服务器的对应brick上执行 for i in `attr -lq .`; do setfattr -x trusted.$i .; done
2)随便一个gluster服务器上重新创建卷
3) 在客户端虽然df 看不到挂载点了,但实际还在,要先umount 再mount即可
关于Gluster改进的一些想法
1)设置rep时,性能成倍递减问题
需要改动客户端读写流程,不能让客户端去同时写多个副本到多个gluster server上,应该只写一份,请gluster server内部去做。虽然通过nfs v3方式挂载
已经解决了此问题,而且把挂载的server停掉,也不会影响它的工作。但最好把客户端也改了。
2)rep时,容量成倍递减。
能否使用一些raid算法,像Panasas那样通过校验的方式把容量损失减少,比如:facebook号称他们的HDFS14个副本之占2.4多的容量?