您的位置:首页 > 数据库 > Mongodb

mongodb备份与恢复(下)

2013-09-03 22:40 309 查看

一. 适用于mongodb任何架构(standalon、replic set、sharding)备份脚本

需要安装perl的MongoDB模块,安装方法参见:使用cpanm安装perl相关模块 http://www.ttlsa.com/html/2030.html 。代码这东西,仁者见仁智者见智,一分价钱一分货,所以对于优秀的程序员不要抠门。对语言的熟练度高,编程经验丰富的程序员,写出来的代码,两个字:漂亮!
下面的脚本只需更改变量$mongodb相关参数即可,如有更好的更便捷的方法请赐教。

#!/bin/perl
#################################
### author: www.ttlsa.com     ###
### QQ群: 39514058            ###
### E-mail: service@ttlsa.com ###
#################################

use strict;
use File::Path;
use POSIX;
use MongoDB;
use Data::Dumper;

my $mongodump='/usr/local/mongodb/bin/mongodump';
my $mongodb={
'admin_1'=>{    #定义组别
'email'=>'39514058@qq.com',  #定义备份出错时邮件通知地址,此处未包含该功能。
'server'=>[     #定义mongodb相关信息
{
'replset'=>1,    #是否复制集
'sharding'=>0,   #是否分片
'setname'=>"TTLSA_COM",  #复制集名称
'mongodsvr'=>["10.1.11.155:27017","10.1.11.156:27017","10.1.11.157:27017"],   #mongod服务器IP和端口号
'configsvr'=>[],  #config server服务器IP和端口号
'mongossvr'=>[],  #mongos server服务器IP和端口号
'backupdir'=>"/data/backup/mongodb_ttlsa_com",  #备份目录
'user'=>"",      #用户名
'passwd'=>"",    #密码
'interval'=>15,  #备份轮滚周期
},

{
'replset'=>1,
'sharding'=>1,
'setname'=>"shard1",
'mongodsvr'=>["10.1.22.21:27029","10.1.22.22:27029","10.1.22.23:27029"],
'configsvr'=>["10.1.22.21:27028","10.1.22.22:27028","10.1.22.23:27028"],
'mongossvr'=>["10.1.22.21:27027","10.1.22.22:27027","10.1.22.23:27027"],
'backupdir'=>"/data/backup/mongodb_shard1",
'user'=>"",
'passwd'=>"",
'interval'=>15,
},

{
'replset'=>0,
'sharding'=>0,
'setname'=>"shard1",
'mongodsvr'=>["10.1.27.22:30000","10.1.27.22:30001","10.1.20.16"],
'configsvr'=>[],
'mongossvr'=>[],
'backupdir'=>"/data/backup/mongodb_standalon",
'user'=>"root",
'passwd'=>"www.ttlsa.com",
'interval'=>15,
}
]},
#'admin_2'=>{}
};

while(my($group,$value)=each(%$mongodb)){
foreach my $node (@{$value->{'server'}}){
my $tmp_stdout = tmpnam();
my $tmp_stderr = tmpnam();
if($node->{'replset'} && !$node->{'sharding'}){
my $dir = $node->{'backupdir'};
mkpath $dir unless -e $dir;
my $return=backup_rotate($dir,$node->{'interval'});
my $hosts = $node->{'setname'}.'/'.join(',', @{$node->{'mongodsvr'}});
if(($node->{'user'} ne '') && ($node->{'passwd'} ne '')){
my $retval=system("$mongodump -vvvvv -h $hosts -u $node->{'user'} -p $node->{'passwd'} --oplog -o $dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
}else{
my $retval=system("$mongodump -vvvvv -h $hosts --oplog -o $dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
}
}elsif($node->{'sharding'}){
my $mongod_hosts=$node->{'setname'}.'/'.join(',', @{$node->{'mongodsvr'}});
my $mongos_hosts=$node->{'setname'}.'/'.join(',', @{$node->{'mongossvr'}});
my $mongod_dir = $node->{'backupdir'}.'/'.'mongodsvr';
my $config_dir = $node->{'backupdir'}.'/'.'configsvr';
mkpath $mongod_dir unless -e $mongod_dir;
mkpath $config_dir unless -e $config_dir;
my $return=backup_rotate($mongod_dir,$node->{'interval'});
my $return=backup_rotate($config_dir,$node->{'interval'});
if(($node->{'user'} ne '') && ($node->{'passwd'} ne '')){
my $conn = MongoDB::Connection->new("host" => "mongodb://$mongos_hosts","db_name" => "admin", "username" => "$node->{'user'}", "password" => "$node->{'passwd'}");
my $db = $conn->get_database('config');
my $coll=$db->get_collection('settings');
my $ret=$coll->update({ _id => "balancer" }, { '$set' => { 'stopped'=> 'true' } },{'false'},{'true'});
my $retval=system("$mongodump -h $mongos_hosts -u $node->{'user'} -p $node->{'passwd'} --db config -o $config_dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
my $retval=system("$mongodump -h $mongod_hosts -u $node->{'user'} -p $node->{'passwd'} --oplog -o $mongod_dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
my $ret=$coll->update({ _id => "balancer" }, { '$set' => { 'stopped'=> 'false' } },{'false'},{'true'});
}else{
my $conn = MongoDB::Connection->new("host" => "mongodb://$mongos_hosts");
my $db = $conn->get_database('config');
my $coll=$db->get_collection('settings');
my $ret=$coll->update({ _id => "balancer" }, { '$set' => { 'stopped'=> 'true' } },{'false'},{'true'});
my $retval=system("$mongodump -h $mongos_hosts --db config -o $config_dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
my $retval=system("$mongodump -h $mongod_hosts --oplog -o $mongod_dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
my $ret=$coll->update({ _id => "balancer" }, { '$set' => { 'stopped'=> 'false' } },{'false'},{'true'});
}
}else{
foreach my $each (@{$node->{'mongodsvr'}}){
my $dir = $node->{'backupdir'}.'/'.$each;
mkpath $dir unless -e $dir;
my $return=backup_rotate($dir,$node->{'interval'});
if(($node->{'user'} ne '') && ($node->{'passwd'} ne '')){
my $retval=system("$mongodump -h $each -u $node->{'user'} -p $node->{'passwd'} -o $dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
}else{
my $retval=system("$mongodump -h $each -o $dir/dump.1 >$tmp_stdout 2>$tmp_stderr");
}
}
}
}
}

sub backup_rotate {
my $backup_dir=shift;
my $retral=shift;
my @aa=sort{$b<=>$a} 1..$retral;

if(chdir "/$backup_dir"){
for my $num (@aa){
my $old=$num+1;
if(-e "dump.$num"){
if(-e "dump.$old"){
system("rm -rf dump.$old && mv dump.$num dump.$old");
}else{
system("mv dump.$num dump.$old");
}
}
}
}else{
return "Failed to change dir $backup_dir : $!";
}
}


二. MongoDB增量备份方法

上一篇《mongodb备份与恢复(上)》http://www.ttlsa.com/html/1938.html 说到的方法都需要拷贝所有数据,即使数据发生很少的改变。如果数据量很大的话,备份整个数据库将消耗更多的时间和磁盘空间。这时增量备份将会是个必然的选择,记录前一次的完整备份点,后续的备份只备份从该点发生改变的数据。

这种方法需要一台专门的备份服务器backup_server,当然backup_server需要一个完整的备份,然后通过mongooplog工具来拷贝并应用mongodb_server的oplog日志。

在mongodb_server上执行以下操作:
> op = db.oplog.rs.find().sort({$natural: -1}).limit(1).next();
> start = op['ts']['t']/1000

在backup_server上执行:

# mongooplog --from A --seconds SECOND

SECOND值位于start值与当前时间之间。

mongooplog工具介绍:
mongooplog从远程拉取oplog日志并应用。

# ./mongooplog --help
--help                          显示帮助信息
-v [ --verbose ]                打印出更多信息,如时间等等 -vvvvv
--version                       打印版本信息
-h [ --host ] arg               指定连接的mongodb主机,复制集时设置为<set name>/s1,s2
--port arg                      指定mongodb端口号,也可以这么指定--host hostname:port
--ipv6                          启用支持IPv6
-u [ --username ] arg           用户名
-p [ --password ] arg           密码
--dbpath arg                    直接访问mongod的数据库文件,而不是连接到mongodb服务器。需要锁定数据目录,如果mongod当前在访问相同路径将不能使用。也就是说,mongod运行的情况下不能使用--dbpath,mongod未运行的情况下可以直接指定--dbpath
--directoryperdb                每个db一个单独的目录,需要指定dbpath
--journal                       启用journaling
-d [ --db ] arg                 指定数据库
-c [ --collection ] arg         指定集合(some commands)
-f [ --fields ] arg             逗号分隔的列名,如-f name,age
--fieldFile arg                 file with fields names - 1 per line
-s [ --seconds ] arg            seconds to go back default:86400
--from arg                      host to pull from
--oplogns arg (=local.oplog.rs) ns to pull from


三. 10gen发布MongoDB增量备份服务

提供支持按照指定时间点恢复的持续增量备份功能, 不过需要支付的。

提供的特性有:mongodb备份与恢复(下)

1. 用于数据传输的SSL加密

2. 高可用性

3. 指定时间点恢复

4. 支持分片集群

5. 较低的开销
工作原理:
是一个轻量级代理,它从所有正在备份的副本集合中收集oplog,将其压缩并加密,然后通过SSL发送到运行备份服务的数据中心。
此方法的好处有:
1. 数据是增量备份的,因此传输的数据相对较小
2. 备份服务中的数据与主系统中的数据在时间上非常接近
3. 对主系统的影响不会比向副本集合中添加另一个副本大(后者非常缓慢, 可先恢复到最新备份状态,然后在加入集群中同步)
4. oplog支持将副本集合恢复到任意时间点。

有两个备份选项:快照和自定义快照。
备份服务依据一套策略创建和维持备份快照。这些快照中的任何一个都可以用于恢复。同样的,用户也可以指定一个自己希望使用的精确时间点创建一份快照。在这种情况下,将使用该时间点之前最新的快照,并会根据用户指定的时间点应用oplog。

上篇《mongodb备份与恢复(上)》 http://www.ttlsa.com/html/1938.html
如需转载请注明出处:mongodb备份与恢复(下) http://www.ttlsa.com/html/2052.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: