mongodb備份與恢復(下)—ttlsa教程系列之mongodb(九)

一. 適用於mongodb任何架構(standalon、replic set、sharding)備份腳本
須要安裝perl的MongoDB模塊,安裝方法參見:使用cpanm安裝perl相關模塊 http://www.ttlsa.com/html/2030.html 。代碼這東西,仁者見仁智者見智,一分價錢一分貨,因此對於優秀的程序員不要摳門。對語言的熟練度高,編程經驗豐富的程序員,寫出來的代碼,兩個字:漂亮!html

下面的腳本只需更改變量$mongodb相關參數便可,若有更好的更便捷的方法請賜教。node

#!/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上執行:mongodb

# 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。less

相關文章
相關標籤/搜索