酸菜没窖养 發表於 2018-11-8 01:43:00

瞧一瞧!这儿实现了MongoDB的增量备份与还原(含部署代码)

<h2>一 需求描述</h2>
<p>我们知道数据是公司的重要资产,业务的系统化、信息化就是数字化。数据高效的存储与查询是系统完善和优化的方向,而数据库的稳定性、可靠性是实现的基础。高可用和RPO(RecoveryPointObjective,复原点目标,指能容忍的最大数据丢失量)是衡量一个数据库优劣的重要指标。作为一个DBA,搭建数据库可靠性体系时,一定会要考虑对数据库进行容灾备份。例如,SQL Server类型的数据库,我们一定会部署作业,定期进行完整备份、差异备份和日志备份;MySQL 数据库同样如此,也是定期进行完整备份、binlog备份等。</p>
<p>可能很多公司的DBA认为自己的数据库已采用了新的高可用方案,是多结点冗余了,不再需要冗余备份了,例如SQL Server 的AlwaysOn,MySQL的MHA。可是,我们还是要强调两点。</p>
<p>1.墨菲定律:如果有两种或两种以上的方式去做某件事情,而其中一种选择方式将导致灾难,则必定有人会做出这种选择。</p>
<p>过往无数的惨痛教训说明,将损失放大的原因就是备份数据也损坏了(大家不重视,实际上很可能就没做)。</p>
<p>2.容灾备份不仅仅可以解决物理故障,还可以将一些其它误操作回滚,将数据的损害降至最低。</p>
<p>数据容灾备份是为数据的灾难恢复加固了最后一道保障墙。</p>
<p>国务院信息化工作办公室领导编制的《重要信息系统灾难恢复指南》也对灾难恢复能力等级做了详细划分。</p>
<p>&nbsp;</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="text-align: center" valign="top" width="139">
<p align="left"><strong>&nbsp; &nbsp; &nbsp;灾难恢复能力等级</strong></p>
</td>
<td style="text-align: center" valign="top" width="180">
<p align="center"><strong>RTO</strong></p>
</td>
<td style="text-align: center" valign="top" width="204">
<p align="left"><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RPO</strong></p>
</td>
</tr>
<tr>
<td valign="top" width="139">
<p align="center">1</p>
</td>
<td valign="top" width="180">
<p align="center">2天以上</p>
</td>
<td valign="top" width="204">
<p align="center">1天至7天</p>
</td>
</tr>
<tr>
<td valign="top" width="139">
<p align="center">2</p>
</td>
<td valign="top" width="180">
<p align="center">24小时以后</p>
</td>
<td valign="top" width="204">
<p align="center">1天至7天</p>
</td>
</tr>
<tr>
<td valign="top" width="139">
<p align="center">3</p>
</td>
<td valign="top" width="180">
<p align="center">12小时以上</p>
</td>
<td valign="top" width="204">
<p align="center">数小时至1天</p>
</td>
</tr>
<tr>
<td valign="top" width="139">
<p align="center">4</p>
</td>
<td valign="top" width="180">
<p align="center">数小时至2天</p>
</td>
<td valign="top" width="204">
<p align="center">数小时至1天</p>
</td>
</tr>
<tr>
<td valign="top" width="139">
<p align="center">5</p>
</td>
<td valign="top" width="180">
<p align="center">数分钟至2天</p>
</td>
<td valign="top" width="204">
<p align="center">0至30分钟</p>
</td>
</tr>
<tr>
<td valign="top" width="139">
<p align="center">6</p>
</td>
<td valign="top" width="180">
<p align="center">数分钟</p>
</td>
<td valign="top" width="204">
<p align="center">0</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>随着MongoDB使用的越来越普及,存储的数据越来越重要,对其进行定期备份很有必要。现在业内普遍流行的做法是每天定时进行一次全库备份,出故障时,进行全库还原。但是一天一次的备份,很难保证恢复后的数据时效性,RPO较差,会有几个小时的数据丢失。例如,每天5点进行完整备份,如果故障点是晚上20:00,那么就会丢失15个小时的数据。对比上面的“灾难恢复能力等级“”列表,会发现,我们的灾难能力等级比较低。</p>
<p>如果每小时做一次全部备份,那么对存储空间的要求较高,还有就是对性能也会有影响。所以,<span style="color: rgba(255, 0, 0, 1)"><strong>探究Mongodb的增量备还与原很有必要!!!</strong></span></p>
<h2>二 原理说明</h2>
<p>关系型数据库,例如MySQL ,SQL Server 都有事务日志(或bin log),会将数据库的DML 、DDL、DCL等操作记录在事务文件中,可以通过日志备份来搭建增量容灾还原体系。MongoDB没有此类机制和数据文件,难以实现。但是MongoDB副本集有通过oplog(位于local数据库oplog.rs集合中) 实现节点间的同步,此集合记录了整个mongod实例在一段时间内的所有变更(插入/更新/删除)操作。基于此,是否可以考虑通过oplog.rs集合的备份还原来实现实例的增量备份与增量还原。</p>
<p>查看mongodb备份命令Mongodump,其中有一个相关参数oplog。</p>
<p align="left"><strong>Mongodump&nbsp;</strong><strong>中</strong><strong>--oplog</strong><strong>参数</strong></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="277">
<p style="text-align: center"><span style="font-size: 14px"><strong>参数</strong></span></p>
</td>
<td valign="top" width="277">
<p style="text-align: center"><span style="font-size: 14px"><strong>参数说明</strong></span></p>
</td>
</tr>
<tr>
<td valign="top" width="277">
<p style="text-align: center"><span style="font-size: 14px"><strong>--oplog</strong></span></p>
</td>
<td valign="top" width="277">
<p><span style="font-size: 15px">Use oplog for taking a point-in-time snapshot</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>该参数的主要作用是在导出库集合数据的同时生成一个oplog.bson文件,里面存放了开始进行dump到dump结束之间所有的op log 操作。</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201810/780228-20181022204059487-1011211891.png"></p>
<p>&nbsp;</p>
<p><strong>注意:--oplog选项只对全库导出有效。</strong></p>
<p><strong><span lang="EN-US">相应的 Mongorestore 中与&nbsp;<span lang="EN-US">Oplog 相关的参数</span></span></strong></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="text-align: center" valign="top" width="189">
<p><strong><span style="font-size: 14px">参数</span></strong></p>
</td>
<td style="text-align: center" valign="top" width="365">
<p><strong><span style="font-size: 14px">参数说明</span></strong></p>
</td>
</tr>
<tr>
<td style="text-align: center" valign="top" width="189">
<p><strong><span style="font-size: 14px">oplogReplay</span></strong></p>
</td>
<td valign="top" width="365">
<p><span style="font-size: 14px">replay oplog for point-in-time restore</span></p>
</td>
</tr>
<tr>
<td style="text-align: center" valign="top" width="189">
<p><strong><span style="font-size: 14px">oplogLimit</span></strong></p>
</td>
<td valign="top" width="365">
<p><span style="font-size: 14px">only include oplog entries before the provided Timestamp</span></p>
</td>
</tr>
<tr>
<td style="text-align: center" valign="top" width="189">
<p><strong><span style="font-size: 14px">oplogFile</span></strong></p>
</td>
<td valign="top" width="365">
<p><span style="font-size: 14px">oplog file to use for replay of oplog</span></p>
<p><span style="font-size: 14px">&nbsp;</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;<strong>仔细观察oplogReplay参数下的还原过程,我们发现,是先还原数据库文件,再重放还原<strong><strong>oplog.bson种的数据。这就启发了我们,如果还原路径下,只有<strong><strong><strong>oplog.bson文件,没有数据库备份文件,是不是只进行重放还原操作。如此,如果<strong><strong><strong><strong><strong><strong>oplog.bson中记录都是上次备份后的变化操作(op log),还原<strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>oplog.bson</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>就可以实现了增量还原。</strong></strong></strong></strong></strong></strong><strong>考虑到副本集的变化操作(op log</strong><strong>)保存在<strong>oplog.rs</strong>集合中,只要连续从oplog.rs导出操作的相关数据进行备份,就可以实现增量备份。</strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>即理论上,<strong>从oplog.rs导出的数据完全可以替代mongodump过程中产生的oplog.bson,进行增量还原。</strong></strong></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong><strong>实际生产中经过多次验证,也是完全可以。</strong></strong></span></p>
<p><em><strong><strong>-----具体原理及验证内容还可参考本人博客 --https://www.cnblogs.com/xuliuzai/p/9832333.html</strong></strong></em></p>
<h2>三 代码实现【<span style="font-size: 16px"><em>重点推荐</em>】</span></h2>
<p>在容灾体系建设中,既有全库的完整备份也有增量备份。下面是我们的实现代码,因为MongoDB多是在Linux系统下部署,所以这些备份代码都是通过shell语言实现。<span style="color: rgba(0, 0, 0, 1)"><strong>这些代码大家只要稍微改动,调整部分参数,即可部署应用。</strong></span></p>
<p><strong>1. 实现完整(全库)备份的代码</strong></p>
<div class="cnblogs_code">
<pre>#!/bin/<span style="color: rgba(0, 0, 0, 1)">bash
sourcepath</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb/mongobin344/bin</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
targetpath</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb_back/bkXXX_2XXXX</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
nowtime</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">+%Y%m%d</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
start()
{
${sourcepath}</span>/mongodump --host <span style="color: rgba(128, 0, 128, 1)">172</span>.XXX.XXX.XXX --port 2XXXX -u 用户名-p <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">密码</span><span style="color: rgba(128, 0, 0, 1)">"</span> --oplog --<span style="color: rgba(0, 0, 255, 1)">gzip</span> --authenticationDatabase <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">"</span> --out ${targetpath}/<span style="color: rgba(0, 0, 0, 1)">${nowtime}
}
execute()
{

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">================================ $(date) bakXXX 2XXXX mongodb back start${nowtime}=========</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">

start
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ $? -eq <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">The MongoDB BackUp Successfully!</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">The MongoDB BackUp Failure</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ ! -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${targetpath}/${nowtime}/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">mkdir</span> ${targetpath}/<span style="color: rgba(0, 0, 0, 1)">${nowtime}
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
execute

baktime</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-3 days</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">+%Y%m%d</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${targetpath}/${baktime}/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">rm</span> -rf <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${targetpath}/${baktime}/</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">=======${targetpath}/${baktime}/===删除完毕==</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">fi</span>

<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">================================ $(date) bakXXX 2XXXX mongodb back end ${nowtime}=========</span><span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p>&nbsp;</p>
<p>代码说明:</p>
<p>1.完整备份的脚本,通过crontab触发执行,每天执行一次。</p>
<p>2.备份完整后,会将三天前的备份文件自动删除。</p>
<p>3.sourcepath 定义了MongoDB 运行程序所在路径;targetpath定义了归档文件存放的文件夹(请提前创建)。</p>
<p>&nbsp;</p>
<p><strong>2. 实现增量备份的代码</strong></p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">#
# This </span><span style="color: rgba(0, 0, 255, 1)">file</span><span style="color: rgba(0, 0, 0, 1)"> is used by cron to Backup the data of oplog collection,the collection is part of local DB.
# The oplog (operations log) is a special capped collection that keeps a rolling record of all operations
# that modify the data stored </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> your databases.All replica set members contain a copy of the oplog,
# </span><span style="color: rgba(0, 0, 255, 1)">in</span> the local.oplog.rs collection, <span style="color: rgba(0, 0, 255, 1)">which</span><span style="color: rgba(0, 0, 0, 1)"> allows them to maintain the current state of the database.
# Each operation </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> the oplog is idempotent. That is, oplog operations produce the same results
# whether applied once or multiple times to the target dataset.
#
# We backup the collections by periodicity to restore the DB</span><span style="color: rgba(0, 0, 255, 1)">in</span> <span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> ofDB disaster
# The version is defined V.</span><span style="color: rgba(128, 0, 128, 1)">001</span><span style="color: rgba(0, 0, 0, 1)">
# Version   ModifyTime                ModifyBy            Desc
# Ver001    </span><span style="color: rgba(128, 0, 128, 1)">2018</span>-<span style="color: rgba(128, 0, 128, 1)">11</span>-<span style="color: rgba(128, 0, 128, 1)">06</span> <span style="color: rgba(128, 0, 128, 1)">17</span>:<span style="color: rgba(128, 0, 128, 1)">00</span><span style="color: rgba(0, 0, 0, 1)">         xuchangpei             Create the Scripts File
#
#
#</span>!/bin/<span style="color: rgba(0, 0, 0, 1)">bash

#### 请在此处输入关键参数,例如程序路径,账号,密码,实例端口###
command_linebin</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb/mongobin344/bin/mongo</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
username</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户名</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
password</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户命名</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
port</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongo都被的端口号</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
####
####comments0 start 第一次运行此脚本时,自动检查创建备份路径 ####
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ ! -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb_back/mongodboplog_back/mongo$port</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">mkdir</span> -p /data/mongodb_back/mongodboplog_back/<span style="color: rgba(0, 0, 0, 1)">mongo$port
</span><span style="color: rgba(0, 0, 255, 1)">fi</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> [ ! -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb_back/mongodboplog_back/log/$port</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">mkdir</span> -p /data/mongodb_back/mongodboplog_back/log/<span style="color: rgba(0, 0, 0, 1)">$port
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">

bkdatapath</span>=/data/mongodb_back/mongodboplog_back/<span style="color: rgba(0, 0, 0, 1)">mongo$port
bklogpath</span>=/data/mongodb_back/mongodboplog_back/log/<span style="color: rgba(0, 0, 0, 1)">$port

####comments end ##

logfilename</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">===================================Message --=MongoDB 端口为</span><span style="color: rgba(128, 0, 0, 1)">"</span> $port <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">的差异备份开始,开始时间为</span><span style="color: rgba(128, 0, 0, 1)">"</span> $(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d%H%M%S</span><span style="color: rgba(128, 0, 0, 1)">"</span>) &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

ParamBakEndDate</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> +%<span style="color: rgba(0, 0, 0, 1)">s)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --本次备份时间参数中的结束时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $ParamBakEndDate &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

DiffTime</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> <span style="color: rgba(128, 0, 128, 1)">65</span> \* <span style="color: rgba(128, 0, 128, 1)">60</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --备份设置的间隔时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $DiffTime &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log


ParamBakStartDate</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> $ParamBakEndDate -<span style="color: rgba(0, 0, 0, 1)"> $DiffTime)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --本次备份时间参数中的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $ParamBakStartDate &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

bkfilename</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d%H%M%S</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

#### comments1 start 获取数据库中oplog记录的开始范围,防止导出的数据不完整 ####

command_line</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${command_linebin} localhost:$port/admin -u$username -p$password</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">

opmes</span>=$(/bin/<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">db.printReplicationInfo()</span><span style="color: rgba(128, 0, 0, 1)">"</span> | $command_line --<span style="color: rgba(0, 0, 0, 1)">quiet)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> $opmes &gt;<span style="color: rgba(0, 0, 0, 1)"> opdoctime$port.tmplog

opbktmplogfile</span>=<span style="color: rgba(0, 0, 0, 1)">opdoctime$port.tmplog

#opstartmes</span>=$(<span style="color: rgba(0, 0, 255, 1)">grep</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> $opmes)

opstartmes</span>=$(<span style="color: rgba(0, 0, 255, 1)">grep</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time</span><span style="color: rgba(128, 0, 0, 1)">"</span> $opbktmplogfile | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">CST</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span> | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $2}</span><span style="color: rgba(128, 0, 0, 1)">'</span> | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)"> GMT</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --oplog集合记录的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span>$opstartmes &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

oplogRecordFirst</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$opstartmes</span><span style="color: rgba(128, 0, 0, 1)">"</span>+%<span style="color: rgba(0, 0, 0, 1)">s)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --oplog集合记录的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $oplogRecordFirst &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

##begin 比较备份参数的开始时间是否在oplog记录的时间范围内
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ $oplogRecordFirst -<span style="color: rgba(0, 0, 0, 1)">le $ParamBakStartDate ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --检查设置备份时间合理。备份参数的开始时间在oplog记录的时间范围内。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Fatal Error --检查设置的备份时间不合理合理。备份参数的开始时间不在oplog记录的时间范围内。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">

##end##

#### comments1 end####

## 调整一下命令,将备份的过程打印到log文件中,我们可以从local.oplog.rs导出的文档数据量来评估,一个周期内的操作量,和预估如果恢复可能的耗时

##dumpmsg</span>=$(/data/mongodb/mongobin344/bin/mongodump -h localhost --port $port --authenticationDatabase admin -u$username -p$password -d local -c oplog.rs--query <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{ts:{$gte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakStartDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,1),$lte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakEndDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,9999)}}</span><span style="color: rgba(128, 0, 0, 1)">'</span> -o $bkdatapath/<span style="color: rgba(0, 0, 0, 1)">mongodboplog$bkfilename)
<br></span>/data/mongodb/mongobin344/bin/mongodump -h localhost --port $port --authenticationDatabase admin -u$username -p$password -d local -c oplog.rs--query <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{ts:{$gte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakStartDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,1),$lte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakEndDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,9999)}}</span><span style="color: rgba(128, 0, 0, 1)">'</span> -o $bkdatapath/mongodboplog$bkfilename &gt;&gt; $bklogpath/$logfilename.log <span style="color: rgba(128, 0, 128, 1)">2</span>&gt;&amp;<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">

#</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">本次导出的具体信息如下:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> $dumpmsg
#</span><span style="color: rgba(0, 0, 255, 1)">echo</span> $dumpmsg &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

## 调整结束

#### comments2 start再次检查,防止导出oplog数据过程耗时过长,比如,我们一小时导出一份,每一次循环涵盖65分钟,如果导出执行过程耗时5分钟以上就可能导致导出的数据不完整。####
## 下面的70 是有上面的65</span>+5而得,+<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)"> 是允许导出耗时5分钟。这个逻辑有点绕,大家可以测测,这段逻辑看几分钟可以理解通透了。
DiffTime</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> <span style="color: rgba(128, 0, 128, 1)">70</span> \* <span style="color: rgba(128, 0, 128, 1)">60</span><span style="color: rgba(0, 0, 0, 1)">)
AllowMaxDate</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> $(<span style="color: rgba(0, 0, 255, 1)">date</span> +%s) -<span style="color: rgba(0, 0, 0, 1)"> $DiffTime)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ $AllowMaxDate -<span style="color: rgba(0, 0, 0, 1)">le $ParamBakStartDate ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --oplog记录导出时间在规定的DiffTime范围内。数据有效</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Fatal Error --oplog记录导出时间 超出了 规定的DiffTime范围。数据完整性等不到保证。请增大DiffTime参数或调整备份频率。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">

#### comments2 end ####

#### comments3 检查备份文件是否已经删除start ####
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$bkdatapath/mongodboplog$bkfilename</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --检查此次备份文件已经产生.文件信息为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $bkdatapath/mongodboplog$bkfilename &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Fatal Error --备份过程已执行,但是未检测到备份产生的文件,请检查!</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
##### comments3 end ####

#### comments4 start 删除历史备份文件,保留3天,如需调整,请在持续设置
keepbaktime</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-3 days</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">+%Y%m%d%H</span><span style="color: rgba(128, 0, 0, 1)">"</span>)*
<span style="color: rgba(0, 0, 255, 1)">if</span> [ -d $bkdatapath/<span style="color: rgba(0, 0, 0, 1)">mongodboplog$keepbaktime ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">rm</span> -rf $bkdatapath/<span style="color: rgba(0, 0, 0, 1)">mongodboplog$keepbaktime
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message -- $bkdatapath/mongodboplog$keepbaktime 删除完毕</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
### comments4 end


</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">============================Message --MongoDB 端口为</span><span style="color: rgba(128, 0, 0, 1)">"</span> $port <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">的差异备份结束,结束时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d%H%M%S</span><span style="color: rgba(128, 0, 0, 1)">"</span>) &gt;&gt; $bklogpath/$logfilename.log</pre>
</div>
<p>&nbsp;</p>
<p>代码说明:</p>
<p>1.增量备份的脚本,也是通过crontab触发执行,以上参数未修改前,建议每小时执行一次。</p>
<p>2.备份完整后,会自动检查文件是否产生,并且会将三天前的备份文件删除。</p>
<p>3.脚本会自动检查备份路径,不存在将自动产生。</p>
<p>4.增量导出中开始时间和结束时间是最重要的参数,并且要对参数的合法性、有效性检查。例如,检查Oplog的记录是否完全涵盖输入的时间,防止出现希望导出08:00--09:00的数据,但是oplog集合中只有08:30--09:00的数据;防止导出过程耗时过长(例如超过定义的5分钟),导致数据不完整。代码中都会对这些异常进行判断和捕获。</p>
<p>&nbsp;</p>
<p><span style="background-color: rgba(204, 255, 255, 1); color: rgba(255, 0, 0, 1); font-size: 15px"><strong>&nbsp;2018-11-30 01:48 再次更新,将代码调整如下,主要针对 判断增量备份出的oplog数据能否涵盖60分钟。本代码为不小于61分钟,大家可根据需求调整。</strong></span></p>
<p>&nbsp;</p>
<p>前面的代码,是通过限制备份时间(要小于5分钟)来做判断的,仔细分析下,oplog是固定集合,大小由oplogsize设置,其覆盖情况有插入量的多少来决定,不是时间来决定。如果短时间有大量的插入就会很快覆盖掉前面的操作,即1分钟的大量操作完全可能会覆盖掉前面20分钟的操作,所以,有可能有这种情况发生,例如,08:00 执行增量备份,备份时间参数命令为06:55---08:00,执行到08:02 结束。但是在08:00 -08:01 期间有大量的写操作,此时oplog中 06:55 --07:10的集合很可能会被新进来的08:00 -08:01覆盖掉了,所以,备份导出的数据数据07:10 之前的数据很有可能是丢失的,不完整的。最保险的办法,还是通过db.printReplicationInfo()检查判断。</p>
<p>所以代码调整如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">#
# This </span><span style="color: rgba(0, 0, 255, 1)">file</span><span style="color: rgba(0, 0, 0, 1)"> is used by cron to Backup the data of oplog collection,the collection is part of local DB.
# The oplog (operations log) is a special capped collection that keeps a rolling record of all operations
# that modify the data stored </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> your databases.All replica set members contain a copy of the oplog,
# </span><span style="color: rgba(0, 0, 255, 1)">in</span> the local.oplog.rs collection, <span style="color: rgba(0, 0, 255, 1)">which</span><span style="color: rgba(0, 0, 0, 1)"> allows them to maintain the current state of the database.
# Each operation </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> the oplog is idempotent. That is, oplog operations produce the same results
# whether applied once or multiple times to the target dataset.
#
# We backup the collections by periodicity to restore the DB</span><span style="color: rgba(0, 0, 255, 1)">in</span> <span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> ofDB disaster
# The version is defined V.</span><span style="color: rgba(128, 0, 128, 1)">001</span><span style="color: rgba(0, 0, 0, 1)">
# Version   ModifyTime                ModifyBy            Desc
# Ver001    </span><span style="color: rgba(128, 0, 128, 1)">2018</span>-<span style="color: rgba(128, 0, 128, 1)">11</span>-<span style="color: rgba(128, 0, 128, 1)">06</span> <span style="color: rgba(128, 0, 128, 1)">17</span>:<span style="color: rgba(128, 0, 128, 1)">00</span><span style="color: rgba(0, 0, 0, 1)">         xuchangpei             Create the Scripts File
#
#
#</span>!/bin/<span style="color: rgba(0, 0, 0, 1)">bash

#### 请在此处输入关键参数,例如程序路径,账号,密码,实例端口###
command_linebin</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb/mongobin344/bin/mongo</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
username</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户名</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
password</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户命名</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
port</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongo都被的端口号</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
####
####comments0 start 第一次运行此脚本时,自动检查创建备份路径 ####
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ ! -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb_back/mongodboplog_back/mongo$port</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">mkdir</span> -p /data/mongodb_back/mongodboplog_back/<span style="color: rgba(0, 0, 0, 1)">mongo$port
</span><span style="color: rgba(0, 0, 255, 1)">fi</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> [ ! -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data/mongodb_back/mongodboplog_back/log/$port</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">mkdir</span> -p /data/mongodb_back/mongodboplog_back/log/<span style="color: rgba(0, 0, 0, 1)">$port
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">

bkdatapath</span>=/data/mongodb_back/mongodboplog_back/<span style="color: rgba(0, 0, 0, 1)">mongo$port
bklogpath</span>=/data/mongodb_back/mongodboplog_back/log/<span style="color: rgba(0, 0, 0, 1)">$port

####comments end ##

logfilename</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">===================================Message --=MongoDB 端口为</span><span style="color: rgba(128, 0, 0, 1)">"</span> $port <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">的差异备份开始,开始时间为</span><span style="color: rgba(128, 0, 0, 1)">"</span> $(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d%H%M%S</span><span style="color: rgba(128, 0, 0, 1)">"</span>) &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

ParamBakEndDate</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> +%<span style="color: rgba(0, 0, 0, 1)">s)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --本次备份时间参数中的结束时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $ParamBakEndDate &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

DiffTime</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> <span style="color: rgba(128, 0, 128, 1)">65</span> \* <span style="color: rgba(128, 0, 128, 1)">60</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --备份设置的间隔时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $DiffTime &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log


ParamBakStartDate</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> $ParamBakEndDate -<span style="color: rgba(0, 0, 0, 1)"> $DiffTime)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --本次备份时间参数中的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $ParamBakStartDate &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

####上文中的DiffTime用来备份前检查oplog 中的数据是否瞒住要求,即最早的一笔数据要满足在 65分钟前,那么备份后应该也要检查一下.防止在备份的过程中有大量的操作,将前面的尚未导出的oplog数据覆盖点. 例如,</span><span style="color: rgba(128, 0, 128, 1)">08</span>:00执行导出,备份前最早的一笔数据要在06:<span style="color: rgba(128, 0, 128, 1)">00</span><span style="color: rgba(0, 0, 0, 1)">
####执行完毕后,再次检查oplog中最早的一笔数据,知识要在07:</span><span style="color: rgba(128, 0, 128, 1)">00</span> 之前,在此我们要求在06:<span style="color: rgba(128, 0, 128, 1)">59</span><span style="color: rgba(0, 0, 0, 1)"> 即 61分钟前.再次增加一个时间参数 用来表示备份后,oplog 必须满足的时间要求.参数命名为

DiffTime</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> <span style="color: rgba(128, 0, 128, 1)">61</span> \* <span style="color: rgba(128, 0, 128, 1)">60</span><span style="color: rgba(0, 0, 0, 1)">)
ParamAfterBakRequestStartDate</span>=$(<span style="color: rgba(0, 0, 255, 1)">expr</span> $ParamBakEndDate -<span style="color: rgba(0, 0, 0, 1)"> $DiffTime)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --为保证备份的连续性,本次备份后,oplog中的开始时间需小于:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $ParamAfterBakRequestStartDate &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
##### end

bkfilename</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d%H%M%S</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

#### comments1 start 获取数据库中oplog记录的开始范围,防止导出的数据不完整 ####

command_line</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${command_linebin} localhost:$port/admin -u$username -p$password</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">

opmes</span>=$(/bin/<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">db.printReplicationInfo()</span><span style="color: rgba(128, 0, 0, 1)">"</span> | $command_line --<span style="color: rgba(0, 0, 0, 1)">quiet)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> $opmes &gt;<span style="color: rgba(0, 0, 0, 1)"> opdoctime$port.tmplog

opbktmplogfile</span>=<span style="color: rgba(0, 0, 0, 1)">opdoctime$port.tmplog

#opstartmes</span>=$(<span style="color: rgba(0, 0, 255, 1)">grep</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> $opmes)

opstartmes</span>=$(<span style="color: rgba(0, 0, 255, 1)">grep</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time</span><span style="color: rgba(128, 0, 0, 1)">"</span> $opbktmplogfile | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">CST</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span> | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $2}</span><span style="color: rgba(128, 0, 0, 1)">'</span> | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)"> GMT</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --oplog集合记录的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span>$opstartmes &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

oplogRecordFirst</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$opstartmes</span><span style="color: rgba(128, 0, 0, 1)">"</span>+%<span style="color: rgba(0, 0, 0, 1)">s)

</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --oplog集合记录的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $oplogRecordFirst &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

##begin 比较备份参数的开始时间是否在oplog记录的时间范围内
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ $oplogRecordFirst -<span style="color: rgba(0, 0, 0, 1)">le $ParamBakStartDate ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --检查设置备份时间合理。备份参数的开始时间在oplog记录的时间范围内。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Fatal Error --检查设置的备份时间不合理合理。备份参数的开始时间不在oplog记录的时间范围内。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">

##end##

#### comments1 end####

## 调整一下命令,将备份的过程打印到log文件中,我们可以从local.oplog.rs导出的文档数据量来评估,一个周期内的操作量,和预估如果恢复可能的耗时

##dumpmsg</span>=$(/data/mongodb/mongobin344/bin/mongodump -h localhost --port $port --authenticationDatabase admin -u$username -p$password -d local -c oplog.rs--query <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{ts:{$gte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakStartDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,1),$lte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakEndDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,9999)}}</span><span style="color: rgba(128, 0, 0, 1)">'</span> -o $bkdatapath/<span style="color: rgba(0, 0, 0, 1)">mongodboplog$bkfilename)

</span>/data/mongodb/mongobin344/bin/mongodump -h localhost --port $port --authenticationDatabase admin -u$username -p$password -d local -c oplog.rs--query <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{ts:{$gte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakStartDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,1),$lte:Timestamp(</span><span style="color: rgba(128, 0, 0, 1)">'</span>$ParamBakEndDate<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,9999)}}</span><span style="color: rgba(128, 0, 0, 1)">'</span> -o $bkdatapath/mongodboplog$bkfilename &gt;&gt; $bklogpath/$logfilename.log <span style="color: rgba(128, 0, 128, 1)">2</span>&gt;&amp;<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">

#</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">本次导出的具体信息如下:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> $dumpmsg
#</span><span style="color: rgba(0, 0, 255, 1)">echo</span> $dumpmsg &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log

## 调整结束

#### comments2 start再次检查,防止导出oplog数据过程耗时过长,因oplog是固定集合,如果操作期间有大量的操作,则oplog中新的数据会覆盖掉旧的数据,就可能导致导出的数据不完整,无法保证增量文件间的时间连续性。因此备份后再次检查####
opmes</span>=$(/bin/<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">db.printReplicationInfo()</span><span style="color: rgba(128, 0, 0, 1)">"</span> | $command_line --<span style="color: rgba(0, 0, 0, 1)">quiet)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> $opmes &gt;<span style="color: rgba(0, 0, 0, 1)"> opdoctime$port.tmplog
opbktmplogfile</span>=<span style="color: rgba(0, 0, 0, 1)">opdoctime$port.tmplog
opstartmes</span>=$(<span style="color: rgba(0, 0, 255, 1)">grep</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time</span><span style="color: rgba(128, 0, 0, 1)">"</span> $opbktmplogfile | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">CST</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span> | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">oplog first event time: </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $2}</span><span style="color: rgba(128, 0, 0, 1)">'</span> | <span style="color: rgba(0, 0, 255, 1)">awk</span> -F <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)"> GMT</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --执行备份后,oplog集合记录的开始时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span>$opstartmes &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
oplogRecordFirst</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$opstartmes</span><span style="color: rgba(128, 0, 0, 1)">"</span>+%<span style="color: rgba(0, 0, 0, 1)">s)
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --执行备份后,oplog集合记录的开始时间为[时间格式化]:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $oplogRecordFirst &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
##begin 比较备份参数的开始时间是否在oplog记录的时间范围内
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ $oplogRecordFirst -<span style="color: rgba(0, 0, 0, 1)">le $ParamAfterBakRequestStartDate ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --备份后,检查oplog集合中数据的开始时间,即集合中最早的一笔数据,时间不小于61分钟的时间(即参数 ParamAfterBakRequestStartDate)。这样可以保证每个增量备份含有最近一个小时的全部op操作,满足文件的持续完整性,逐个还原无丢失数据风险。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Fatal Error --备份后,检查oplog集合的涵盖的时间范围过小(小于61min)。设置的备份时间不合理合理,备份后的文件不能完全涵盖最近60分钟的数据。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
#### comments2 end ####


#### comments3 检查备份文件是否已经删除start ####
</span><span style="color: rgba(0, 0, 255, 1)">if</span> [ -d <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$bkdatapath/mongodboplog$bkfilename</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message --检查此次备份文件已经产生.文件信息为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $bkdatapath/mongodboplog$bkfilename &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Fatal Error --备份过程已执行,但是未检测到备份产生的文件,请检查!</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
##### comments3 end ####

#### comments4 start 删除历史备份文件,保留3天,如需调整,请在持续设置
keepbaktime</span>=$(<span style="color: rgba(0, 0, 255, 1)">date</span> -d <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-3 days</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">+%Y%m%d%H</span><span style="color: rgba(128, 0, 0, 1)">"</span>)*
<span style="color: rgba(0, 0, 255, 1)">if</span> [ -d $bkdatapath/<span style="color: rgba(0, 0, 0, 1)">mongodboplog$keepbaktime ]
</span><span style="color: rgba(0, 0, 255, 1)">then</span>
<span style="color: rgba(0, 0, 255, 1)">rm</span> -rf $bkdatapath/<span style="color: rgba(0, 0, 0, 1)">mongodboplog$keepbaktime
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Message -- $bkdatapath/mongodboplog$keepbaktime 删除完毕</span><span style="color: rgba(128, 0, 0, 1)">"</span> &gt;&gt; $bklogpath/<span style="color: rgba(0, 0, 0, 1)">$logfilename.log
</span><span style="color: rgba(0, 0, 255, 1)">fi</span><span style="color: rgba(0, 0, 0, 1)">
### comments4 end


</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">============================Message --MongoDB 端口为</span><span style="color: rgba(128, 0, 0, 1)">"</span> $port <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">的差异备份结束,结束时间为:</span><span style="color: rgba(128, 0, 0, 1)">"</span> $(<span style="color: rgba(0, 0, 255, 1)">date</span> -d today +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%Y%m%d%H%M%S</span><span style="color: rgba(128, 0, 0, 1)">"</span>) &gt;&gt; $bklogpath/$logfilename.log</pre>
</div>
<p>(第二份代码 尚未大量验证,因为我们的oplogsize设置的较大,oplog数据范围没有小于60分钟的风险。部署的多是前面的第一份代码。但从准确性上来讲,后者要强于前者,待大量验证完善,将逐渐推广。)</p>
<h2>四 功能测试验证</h2>
<h3><strong>1. 测试环境</strong></h3>
<p>&nbsp;</p>
<table style="border: 0 solid rgba(0, 0, 0, 1)" border="0">
<tbody>
<tr>
<td style="text-align: center"><span style="font-size: 14px"><strong>Item</strong></span></td>
<td style="text-align: center"><span style="font-size: 14px"><strong>ServerIP</strong></span></td>
<td style="text-align: center"><span style="font-size: 14px"><strong>Port</strong></span></td>
<td style="text-align: center"><span style="font-size: 14px"><strong>User DB</strong></span></td>
</tr>
<tr>
<td style="text-align: center"><span style="font-size: 14px"><strong>源库</strong></span></td>
<td><span style="font-size: 14px">172.XXX.XXX.124(Primary)</span></td>
<td><span style="font-size: 14px">2XXX30</span></td>
<td><span style="font-size: 14px">testoplog</span></td>
</tr>
<tr>
<td style="text-align: center"><span style="font-size: 14px"><strong>备份还原库</strong></span></td>
<td><span style="font-size: 14px">172.XXX.XXX.124(Primary)</span></td>
<td><span style="font-size: 14px">2XXX20</span></td>
<td><span style="font-size: 14px">无</span></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h3><strong>2. 完整备份与还原</strong></h3>
<p>step 1 在备份前,先向数据库testoplog插入部分数据</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107140223217-1786957581.png"></p>
<p>step 2 完整备份所有的数据库,执行的代码为上面的完整备份代码(保存到执行文件bkoplogtest_2XXX30),打印出执行过程如下截图</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181108004109405-136041771.png"></p>
<p>step 3 还原完整备份,执行的代码和打印执行过程如下:</p>
<p>执行的命令:</p>
<p><em>/data/mongodb/mongobin344/bin/mongorestore -h 172.XXX.XXX.124 --port 2XXX20&nbsp; --oplogReplay --authenticationDatabase 认证数据库-u 用户名-p '密码' --gzip /data/mongodb_back/testoplogbackfile/20181107</em></p>
<p>打印出的执行过程:</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107163702966-14690828.png"></p>
<p>step 4 检查还原库的情况,检查库(testoplog)、表(testfullbefore01、testfullbefore02、testfullbefore03)是否还原。</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107164132339-490464559.png"></p>
<p><strong>结论:完整还原后与原库完整备份时数据一致,符合测试预期。</strong></p>
<p>&nbsp;</p>
<h3><strong>&nbsp;3. 增量备份与还原</strong></h3>
<p>&nbsp;</p>
<p>增量备份与还原的测试案例描述</p>
<p>&nbsp;</p>
<table border="0">
<tbody>
<tr>
<td style="text-align: center"><strong><span style="font-size: 14px">测试案例</span></strong></td>
<td style="text-align: center"><strong><span style="font-size: 14px">第一次增量备份</span></strong></td>
<td style="text-align: center"><strong><span style="font-size: 14px">第一次增量还原</span></strong></td>
<td style="text-align: center"><strong><span style="font-size: 14px">第二次增量备份</span></strong></td>
<td style="text-align: center"><strong><span style="font-size: 14px">第二次增量还原</span></strong></td>
</tr>
<tr>
<td style="text-align: center"><strong><span style="font-size: 14px">源库</span></strong></td>
<td>
<p><span style="font-size: 13px">备份前,新建集合testdiffbk01</span></p>
<p><span style="font-size: 13px">并插入10000笔数据</span></p>
</td>
<td><span style="font-size: 13px">&nbsp;无操作</span></td>
<td>
<p><span style="font-size: 13px">备份前,新建集合testdiffbk02</span></p>
<p><span style="font-size: 13px">并插入10000笔数据</span></p>
</td>
<td><span style="font-size: 13px">&nbsp;无操作</span></td>
</tr>
<tr>
<td style="text-align: center"><strong><span style="font-size: 14px">还原库</span></strong></td>
<td><span style="font-size: 13px">无操作</span></td>
<td>
<p><span style="font-size: 13px">还原后,检查testdiffbk01是否存在</span></p>
<p><span style="font-size: 13px">以及数据量</span></p>
</td>
<td><span style="font-size: 13px">&nbsp;无操作</span></td>
<td>
<p><span style="font-size: 13px">还原后,检查testdiffbk02是否存在</span></p>
<p><span style="font-size: 13px">以及数据量</span></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>step 1 第一次增量备份前,向源库中插入测试数据</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107195340945-1479518009.png"></p>
<p>step 2 第一次执行增量备份(执行增量备份的脚本,代码放置在执行文件mongodb_oplogbacktestoplog2XXXX.sh中)</p>
<h2>&nbsp;<img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107195640657-69634870.png"></h2>
<p>step 3 向源库中第二次插入测试数据</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107195735494-1363116325.png"></p>
<p>step 4 第二次执行增量备份</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107195842532-1892852197.png"></p>
<p>两次增量备份产生的文件在 文件夹 /data/mongodb_back/mongodboplog_back/mongo27230 中,如下图所示:</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107201351690-1838141352.png"></p>
<p>step 5 将完整备份所在路径下的文件清空,将第一次备份的产生的oplog.rs.bson 文件,copy至此路径下,并重命名为oplog.bson。【<em><strong>即还原第一份增量备份</strong></em>】</p>
<p>清空指令:</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107201746480-276412176.png"></p>
<p>Copy+ 重命名指令</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107201906095-1701568728.png"></p>
<p>还原指令:</p>
<p><em>/data/mongodb/mongobin344/bin/mongorestore -h 172.XXX.XXX.124 --port 2XXX20 --oplogReplay --authenticationDatabase 验证数据库-u 用户名-p '密码' /data/mongodb_back/testoplogbackfile/20181107</em></p>
<p>&nbsp;<img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107202428767-1159408883.png"></p>
<p>step 7 验证第一次增量还原的数据,验证测试所用的集合testdiffbk01及数据,与原库第一次增量备份时一致,<strong>即已正常还原增量。</strong></p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107202604236-848123840.png"></p>
<p>step 8 将完整备份所在路径下的文件清空,将第二次增量备份的产生的oplog.rs.bson 文件,copy至此路径下,并重命名为oplog.bson。【<em><strong>即还原第二份增量备份</strong></em>】</p>
<p>删除指令</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107202954600-1378468488.png"></p>
<p>copy + 重命名指令</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107203222465-371929014.png"></p>
<p>还原增量备份的指令【与第一次执行的还原命令完全一样】</p>
<p><em>/data/mongodb/mongobin344/bin/mongorestore -h 172.XXX.XXX.124 --port 2XXX20&nbsp; --oplogReplay --authenticationDatabase 验证数据库-u 用户名-p '密码' /data/mongodb_back/testoplogbackfile/20181107</em></p>
<p>&nbsp;<img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107203518140-506665164.png"></p>
<p>step 9&nbsp;&nbsp;验证第二次增量还原的数据,验证测试所用的集合testdiffbk02及数据。结论:与原库第二次增量备份时一致,<strong>即已正常还原增量。</strong></p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181107203709921-1016083591.png"></p>
<p><strong>&nbsp;此轮测试有完整备份与完整还原,还有两次增量备份月增量,详细演示增量还原方案的可行性和相关代码的可执行性,部署后满足生产所需。</strong></p>
<h2>五 注意事项</h2>
<p><strong>一定要在还原完整备份的路径下,还原已备份oplog的增量文件。即先将已还原的完整备份文件删除,再将增量备份产生oplog.rs.bson文件copy至路径下,并且重命名为oplog.bson。</strong></p>
<p>如果是在其他路径下,则报错,主要的错误信息为:</p>
<p>2018-11-06T10:24:51.848+0800<strong> checking for collection data in</strong> /data/mongodb_back/bkrcs_test/oplog.bson<br>2018-11-06T10:24:51.848+0800        <strong>Failed: no oplog file to replay; make sure you run mongodump with --oplog</strong></p>
<p>验证测试,完整备份(全库备份)的文件在 路径&nbsp; <strong>/XXX/XXXX_back/bkrcs_2XXXX/20181105&nbsp;</strong>下 。</p>
<p>如果我们将oplog的增量文件(oplog.rs集合导出的数据)/local/oplog.rs.bson 复制至&nbsp;/XXX/XXXX_back/bkrcs_test/路径下,并重命名为oplog.bson</p>
<p>执行restore命令报错:</p>
<p><img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181106110407701-792560039.png"></p>
<p>如果我们将/local/oplog.rs.bson复制至还原完整备份所在的路径下(&nbsp;<strong>/XXX/XXXX_back/bkrcs_27XXX/20181105</strong>),执行restore,测试不再报错。</p>
<p>&nbsp;<img src="https://img2018.cnblogs.com/blog/780228/201811/780228-20181106111838785-773571071.png"></p>
<p>检查新增数据也已同步过去。</p>
<p>所以,还原时增量备份(oplog)一定要放置完整备份所在的文件夹下(copy前,先将完整备份完结删除)进行还原。</p>
<p>&nbsp;</p>
<p><span style="background-color: rgba(255, 0, 0, 1)"><strong>本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!</strong></span></p>
<p><span style="color: rgba(255, 0, 0, 1)">&nbsp;<strong>本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!</strong></span></p>
<p><strong><strong>本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!</strong></strong></p><br><br>
来源:https://www.cnblogs.com/xuliuzai/p/9917137.html
頁: [1]
查看完整版本: 瞧一瞧!这儿实现了MongoDB的增量备份与还原(含部署代码)