cloudfs文件系统正确性,完整性验证:
对于上一层的应用程序而言,cloudfs文件系统的底层只提供上传,下载,删除功能。
明月需要验证这三个功能的正确性和完整性。需要先了解文件系统的构架以及工作方法。
上传功能:当一个文件上传时,cloudfs返回一个storageid,这个ID在整个文件系统是唯一的。并且在这个文件上传前,cloudfs会根据将要上传的文件的MD5,CRC32以及文件大小,在底层比对是否存在相同文件,如果有,就直接返回一个storageid给客户端,并将文件的引用计数加1。如果没有,则上传该文件,将文件的md5+crc32+size保存到redis里面,在将文件引用计数设置为1.
下载功能:通过nginx,直接将硬盘上的目录映射出来。
删除功能: 当一个文件删除时,找到这个文件对应的md5+crc32+size,将引用计算减1,当引用计数为0时,文件进入cloud-mq,等待销毁。cloud-mq是自主研发的消息队列,用于消息推送。
虽然只有简单的三个功能,但是测试却不简单。
第一个脚本:上传一个新文件到cloudfs
随机生成一个文件到/upload目录,使用的是系统自带的随机字符设备/dev/random。共获取1000行,行的定义其实就与遇到/r/n算一行,也就是文件大小也是不定的。不过一般都在2M以下。之后计算这个文件的MD5值,再上传到文件系统。上传完会获取到一个storageid。脚本根据这个storageid下载这个文件到download目录,然后计算下载文件的MD5值,比对是否是一致的。之后将storageid作为key,将filename+MD5作为value,存入到redis数据库中。在清空download目录中刚刚下载的文件。在存入redis之前,检索一下redis中是否已经存在这个storgid,这点是验证storageid是否会出现碰撞。如果出现碰撞,则一个storageid对应两个文件,这样文件系统就出毛病了。storageid必须是文件的唯一标识。
#!/usr/bin/perl################################################################################ 文件系统测试脚本1–上传新文件# 2012-11-22 V01.00.000 新建程序###############################################################################use strict;use constant VERSION => "V01.00.000"; #版本号use Data::Dumper;use Digest::MD5;use Redis;die("usage: $0 <ident> <cnt>\n") if ($#ARGV != 1);my $upload_path="/home/upload/"; #保存上传文件的目录。my $download_path="/home/download/"; #保存下载文件的目录,文件名是上传的文件名。my ($ident,$cnt) = @ARGV;my $redis = Redis->new(server => '127.0.0.1:7900');open IN,"/dev/urandom" or die "can't open file urandom !\n";foreach (0..$cnt-1){#生成测试文件my $file = "${upload_path}test_${ident}_${_}.log";open FH,">$file" or die "can't create file $file !\n";foreach(1..int rand(10000)){my $tmp=<IN>;print FH $tmp;}close(FH);#计算文件md5值open FH,"$file" or die "can't create file $file !\n";binmode(FH);my $c_md5sum = Digest::MD5->new->addfile(*FH)->hexdigest;print "\n\n———————-\n";print "生成的文件md5值是: $c_md5sum \n";close(FH);#上传文件,并获取文件系统上面的hash值。my @upload_result = `/usr/local/cloudfs/bin/dfs-cli put $file`;my $upload_result = join '', @upload_result;my $dfs_hash;print $upload_result;if($upload_result =~ /storageid:(.*)/){$dfs_hash=$1;}else{print "上传文件 ${file} 失败 /n";}#根据hash值下载文件,并计算文件MD5值验证是否同个文件。my @download_result = `/usr/local/cloudfs/bin/dfs-cli get $dfs_hash "${download_path}$dfs_hash"`;my $download_result = join '', @download_result;print $download_result;open FH1,"${download_path}$dfs_hash" or die "can't read file ${download_path}$dfs_hash !\n";binmode(FH1);my $d_md5sum = Digest::MD5->new->addfile(*FH1)->hexdigest;print "下载的文件md5值是: $d_md5sum \n";close(FH1);if($c_md5sum eq $d_md5sum){print "上传下载文件一致 \n";}else{print "上传下载文件内容不一致";}#检查redis中是否有fds-hash相同的文件,如果有,检查文件MD5值是否一致。如果不一致,则表示文件系统同一个hash值代表了两个不同文件。是否是hash算法产出碰撞,还是程序存在错误。if($redis->exists( $dfs_hash )){my $hash_value = $redis->get($dfs_hash);if ($hash_value eq "test_${ident}_${_}.log:$d_md5sum" ){print "下载文件与已有文件一致 \n";print "当前文件: $hash_value \n";print "已有文件: test_${ident}_${_}.log:$d_md5sum \n";}else{print "error: 下载文件与已有文件不一致 \n";print "当前文件: $hash_value \n";print "已有文件: test_${ident}_${_}.log:$d_md5sum \n";}}else{print "新文件: ${file}:$d_md5sum \n";$redis->set($dfs_hash => "test_${ident}_${_}.log:$d_md5sum");system("rm -rf ${download_path}$dfs_hash");}}
第二个脚本:在第一个脚本的基础上做修改,使用已经存在的目录(如/upload),将里面的文件重复上传到服务器上。
随机选择/upload目录下一个文件,然后上传,上传完根据storageid下载该文件。比对两次的文件MD5值是否一致。
#!/usr/bin/perl################################################################################ 文件系统测试脚本2–上传存在的文件# 2012-11-22 V01.00.000 新建程序###############################################################################use strict;use constant VERSION => "V01.00.000"; #版本号use Data::Dumper;use Digest::MD5;use Redis;die("usage: $0 <path> <cnt>\n") if ($#ARGV != 1);my $download_path="./download/";my $redis = Redis->new(server => '127.0.0.1:7900');my ($path,$cnt) = @ARGV;$path=~s/\/\s*$//;$path=~s/\s*$/\//;my @file = glob("${path}*");foreach (0..$cnt-1){#随机获取指定目录下一个文件上传my $file = $file[int rand($#file)];#计算文件md5值$file =~ s/\s+$//g;open FH,$file or die "can't open file $file !\n";binmode(FH);my $c_md5sum = Digest::MD5->new->addfile(*FH)->hexdigest;print "\n\n———————-\n";print "文件md5值是: $c_md5sum \n";close(FH);#上传文件,并获取文件系统上面的hash值。my @upload_result = `/usr/local/cloudfs/bin/dfs-cli put $file`;my $upload_result = join '', @upload_result;my $dfs_hash;print $upload_result;if($upload_result =~ /storageid:(.*)/){$dfs_hash=$1;}else{print "上传文件 ${file} 失败 /n";}#根据hash值下载文件,并计算文件MD5值验证是否同个文件。my @download_result = `/usr/local/cloudfs/bin/dfs-cli get $dfs_hash "${download_path}$dfs_hash"`;my $download_result = join '', @download_result;print $download_result;open FH1,"${download_path}$dfs_hash" or die "can't read file ${download_path}$dfs_hash !\n";binmode(FH1);my $d_md5sum = Digest::MD5->new->addfile(*FH1)->hexdigest;print "下载的文件${dfs_hash}的md5值是: $d_md5sum \n";close(FH1);if($c_md5sum eq $d_md5sum){print "上传下载文件一致 \n";}#检查redis中是否有fds-hash相同的文件,如果有,检查文件MD5值是否一致。如果不一致,则表示文件系统同#一个hash值代表了两个不同文件。可能是hash算法产出碰撞也可能是程序存在错误。if($redis->exists( $dfs_hash )){my $hash_value = $redis->get($dfs_hash);if ($hash_value eq "${file}:$d_md5sum" ){print "下载文件与已有文件一致 \n";print "当前文件: $hash_value \n";print "已有文件: ${file}:$d_md5sum \n";}else{print "error: 下载文件与已有文件不一致 \n";print "当前文件: $hash_value \n";print "已有文件: ${file}:$d_md5sum \n";}}else{print "新文件: ${file}:$d_md5sum \n";$redis->set($dfs_hash => "${file}:$d_md5sum");`rm -rf ${download_path}$dfs_hash`;}}
第三个脚本:上传新文件(同文件名不同内容),主要在于检查如果在不同服务器同时上传同名不同内容文件是,是否会发生异常。
#!/usr/bin/perl################################################################################ 文件系统测试脚本4–上传新文件(同文件名不同内容)# 2012-11-22 V01.00.000 新建程序###############################################################################use strict;use constant VERSION => "V01.00.000"; #版本号use Data::Dumper;use Digest::MD5;use Redis;die("usage: $0 <cnt>\n") if ($#ARGV != 0);my $upload_path="/home/samename/"; #保存上传文件的目录。my $download_path="/home/download/"; #保存下载文件的目录,文件名是上传的文件名。my $file="samefilename.log";my ($cnt) = @ARGV;my $redis = Redis->new(server => '127.0.0.1:7900');open IN,"/dev/urandom" or die "can't open file urandom !\n";foreach (0..$cnt-1){#生成测试文件open FH,">$file" or die "can't create file $file !\n";foreach(1..int rand(10000)){my $tmp=<IN>;print FH $tmp;}close(FH);#计算文件md5值open FH,"$file" or die "can't create file $file !\n";binmode(FH);my $c_md5sum = Digest::MD5->new->addfile(*FH)->hexdigest;print "\n\n———————-\n";print "生成的文件md5值是: $c_md5sum \n";close(FH);#上传文件,并获取文件系统上面的hash值。my @upload_result = `/usr/local/cloudfs/bin/dfs-cli put $file`;my $upload_result = join '', @upload_result;my $dfs_hash;print $upload_result;if($upload_result =~ /storageid:(.*)/){$dfs_hash=$1;}else{print "上传文件 ${file} 失败 /n";}#根据hash值下载文件,并计算文件MD5值验证是否同个文件。my @download_result = `/usr/local/cloudfs/bin/dfs-cli get $dfs_hash "${download_path}$dfs_hash"`;my $download_result = join '', @download_result;print $download_result;open FH1,"${download_path}$dfs_hash" or die "can't read file ${download_path}$dfs_hash !\n";binmode(FH1);my $d_md5sum = Digest::MD5->new->addfile(*FH1)->hexdigest;print "下载的文件md5值是: $d_md5sum \n";close(FH1);if($c_md5sum eq $d_md5sum){print "上传下载文件一致 \n";}else{print "上传下载文件内容不一致";}#检查redis中是否有fds-hash相同的文件,如果有,检查文件MD5值是否一致。如果不一致,则表示文件系统同一个hash值代表了两个不同文件。是否是hash算法产出碰撞,还是程序存在错误。if($redis->exists( $dfs_hash )){my $hash_value = $redis->get($dfs_hash);if ($hash_value eq "${file}:$d_md5sum" ){print "下载文件与已有文件一致 \n";print "当前文件: $hash_value \n";print "已有文件: ${file}:$d_md5sum \n";}else{print "error: 下载文件与已有文件不一致 \n";print "当前文件: $hash_value \n";print "已有文件: ${file}:$d_md5sum \n";}}else{print "新文件: ${file}:$d_md5sum \n";$redis->set($dfs_hash => "${file}:$d_md5sum");system("rm -rf ${download_path}$dfs_hash");}}
第四个脚本:不同名同内容的文件上传,是否会发生异常。
#!/usr/bin/perl################################################################################ 文件系统测试脚本4–上传新文件(不同文件同内容)# 2012-11-22 V01.00.000 新建程序###############################################################################use strict;use constant VERSION => "V01.00.000"; #版本号use Data::Dumper;use Digest::MD5;use Redis;die("usage: $0 <cnt>\n") if ($#ARGV != 0);my $upload_path="/home/samename/"; #保存上传文件的目录。my $download_path="/home/download/"; #保存下载文件的目录,文件名是上传的文件名。my $file="samefilename.log";my ($cnt) = @ARGV;my $redis = Redis->new(server => '127.0.0.1:7900');foreach (0..$cnt-1){#计算文件md5值open FH,"$file" or die "can't create file $file !\n";binmode(FH);my $c_md5sum = Digest::MD5->new->addfile(*FH)->hexdigest;print "\n\n———————-\n";print "生成的文件md5值是: $c_md5sum \n";close(FH);#上传文件,并获取文件系统上面的hash值。my @upload_result = `/usr/local/cloudfs/bin/dfs-cli put $file`;my $upload_result = join '', @upload_result;my $dfs_hash;print $upload_result;if($upload_result =~ /storageid:(.*)/){$dfs_hash=$1;}else{print "上传文件 ${file} 失败 /n";}#根据hash值下载文件,并计算文件MD5值验证是否同个文件。my @download_result = `/usr/local/cloudfs/bin/dfs-cli get $dfs_hash "${download_path}$dfs_hash"`;my $download_result = join '', @download_result;print $download_result;open FH1,"${download_path}$dfs_hash" or die "can't read file ${download_path}$dfs_hash !\n";binmode(FH1);my $d_md5sum = Digest::MD5->new->addfile(*FH1)->hexdigest;print "下载的文件md5值是: $d_md5sum \n";close(FH1);if($c_md5sum eq $d_md5sum){print "上传下载文件一致 \n";}else{print "上传下载文件内容不一致";}#检查redis中是否有fds-hash相同的文件,如果有,检查文件MD5值是否一致。如果不一致,则表示文件系统同一个hash值代表了两个不同文件。是否是hash算法产出碰撞,还是程序存在错误。if($redis->exists( $dfs_hash )){my $hash_value = $redis->get($dfs_hash);if ($hash_value eq "${file}:$d_md5sum" ){print "下载文件与已有文件一致 \n";print "当前文件: $hash_value \n";print "已有文件: ${file}:$d_md5sum \n";}else{print "error: 下载文件与已有文件不一致 \n";print "当前文件: $hash_value \n";print "已有文件: ${file}:$d_md5sum \n";}}else{print "新文件: ${file}:$d_md5sum \n";$redis->set($dfs_hash => "${file}:$d_md5sum");system("rm -rf ${download_path}$dfs_hash");}}
第五个脚本:删除文件系统上存在的文件,随机从redis获取一个storageid,然后删除。
#!/usr/bin/perl################################################################################ 文件系统测试脚本5–删除文件系统上存在的文件# 2012-11-26 V01.00.000 新建程序###############################################################################use strict;use constant VERSION => "V01.00.000"; #版本号use Data::Dumper;use Digest::MD5;use Redis;die("usage: $0 <cnt>\n") if ($#ARGV != 0);my $download_path="/home/download/";my $redis = Redis->new(server => '127.0.0.1:7900');my ($cnt) = @ARGV;foreach (0..$cnt-1){#随机获取一个storage idmy $dfs_hash = $redis->randomkey;my $hash_value = $redis->get($dfs_hash);print "REDIS保存的md5值是: $hash_value \n";#根据hash值下载文件,并计算文件MD5值验证是否同个文件。my @download_result = `/usr/local/cloudfs/bin/dfs-cli get $dfs_hash "${download_path}$dfs_hash"`;my $download_result = join '', @download_result;print $download_result;open FH1,"${download_path}$dfs_hash" or die "can't read file ${download_path}$dfs_hash !\n";binmode(FH1);my $d_md5sum = Digest::MD5->new->addfile(*FH1)->hexdigest;print "下载的文件${dfs_hash}的md5值是: $d_md5sum \n";close(FH1);if($hash_value =~ /$d_md5sum/){print "文件一致 \n";`rm -rf "${download_path}$dfs_hash"`;$redis->del($dfs_hash);}else{print "error: 上传文件和以前保存的文件值不一致。 \n"}}
然后明月用了一个脚本来调用这几个脚本:
#!/usr/bin/perl################################################################################ 文件系统测试脚本–开多进程# 2012-11-23 V01.00.000 新建程序###############################################################################use strict;use constant VERSION => "V01.00.000"; #版本号use Data::Dumper;#新建一批文件上传my $ident='a';my $cnt=1000;foreach(1..20){system("perl /home/dfs_newfile.pl $ident $cnt > /home/runlog/${ident}_${cnt}.log & ");$ident++;}sleep(60);#已上传文件再次上传my $cnt2=1000;foreach(1..20){system("perl /home/dfs_oldfolder.pl /home/upload $cnt2 > /home/runlog/upload_${cnt2}.log & ")}#同名不同内容的文件上传my $cnt3=1000;foreach(1..5){system("perl /home/dfs_oldfolder.pl /home/samecontent $cnt3 > /home/runlog/samecontent_${cnt3}.log & ")}#不同名同内容的文件上传my $cnt4=1000;foreach(1..10){system("perl /home/dfs_samefile.pl $cnt4 > /home/runlog/samename${cnt4}.log & ")}#删除已上传文件my $cnt5=1000;foreach(1..20){system("perl /home/dfs_delfile.pl $cnt5 > /home/runlog/del${cnt5}.log & ")}
原创文章,转载请注明: 转载自肚腩照明月'blog
本文链接地址: 分布式文件系统底层功能测试【原创】
文章的脚注信息由WordPress的wp-posturl插件自动生成
分布式文件系统底层功能测试【原创】