挖一挖MongoDB的備份與還原(實現指定時間點還原和增量備份還原)


一  研究背景需求

目前作者所在公司的MongoDB數據庫是每天凌晨做一次全庫完整備份,但數據庫出現故障時,只能保證恢復到全備時間點,比如,00:30 做的完整備份,而出現故障是下午18:00,那么現有的備份機制只可以恢復到00:30,即丟失00:30 – 18:00 的操作數據。

此外,我們現在的副本集沒有delay節點,當出現誤操作或需要恢復到指定時間點操作時,目前災備機制也不支持此操作。上線這種備份方案,心里總是惶惶的。

並且細究mongodump機制原理,此命令在運行過程中並不會把數據庫鎖死(或建立快照,以保證整個庫凍結在一個固定的時間點),實現數據庫完整性,而是細化到集合級別,如此,會導致數據完整性問題。 例如,集合A中存放了訂單概要信息,集合B中存放了訂單的所有明細,那么只有一個訂單有完整的明細時才是正確的狀態。那么備份時,如果備份集合A處於時間點x,而備份集合B處於x之后的一個時間點y時,可以想象A和B中的數據極有可能不對應而失去意義(部分訂單有訂單明細而沒有訂單概要信息)。

二  原理分析

關系型數據庫,例如MySQL ,SQL Server 都有事務日志(或bin log),會將數據庫的DML  DDL、DCL等操作記錄在事務文件中,可以通過日志備份搭建還原體系。MongoDB沒有此類機制和數據文件,難以實現。

但MongoDB 副本集 有通過 oplog(主要記錄在local數據庫oplog.rs集合中) 實現節點間的同步,此集合記錄了數據庫的OP操作,記錄的是整個mongod實例一段時間內的所有變更(插入/更新/刪除)操作。

是否可以考慮通過oplog.rs集合的備份還原來解決以上問題(數據完整性;不能還原到指定時間點;時效性差。)。

值得注意的是,oplog為replica set或者master/slave模式專用,standalone模式運行mongodb並不推薦。

查看mongodb備份命令Mongodump,其中有一個相關參數oplog。

Mongodump --oplog參數

參數

參數說明

--oplog

Use oplog for taking a point-in-time snapshot

 

該參數的主要作用是我們在導出庫集合數據的同時生成一個oplog.bson文件,里面存放了開始進行dump到dump結束之間所有的op log 操作。

 

注意:--oplog選項只對全庫導出有效。

相應的 Mongorestore 中與 Oplog 相關的參數

參數

參數說明

oplogReplay

replay oplog for point-in-time restore

oplogLimit

only include oplog entries before the provided Timestamp

oplogFile

oplog file to use for replay of oplog

三 驗證測試

3.1 場景1  備份還原后,如何保證數據一致性、完整性

在Insert數據過程中,備份數據庫,為說明問題,數據插入跨越整個備份過程。

3.1.1 在不使用--oplog 參數下備份還原

Step 1 向數據庫ygtest041602插入數據,源庫沒有集合order0531、orderdetial

插入語句:

for(var i = 0; i < 10000; i++)

{ db.order0531.insert({a: i});};

 

 

for(i=0;i<300000;i++)

{ db.orderdetial.insert({"id":i,"name":"shenzheng","addr":"龍崗","date":new Date()}); };

 

step 2  在上述命令執行期間 執行mongodump 備份

./mongodump -h 172.177.XXX.XXX --port 端口 --authenticationDatabase admin -u 用戶名 -p 密碼 --gzip -o /data/mongodb_back/mongotestdump

Step 3 還原上述備份文件 

./mongorestore -h 172.177.XXX.XXX --port 端口  --authenticationDatabase admin -u 用戶名 -p 密碼  --gzip /data/mongodb_back/mongotestdump

Step 4 檢查源庫Insert 語句, 執行完畢(一定是mongodump完畢,再insert結束;但不強調,mongorestoreinsert的時間關系)

Step 5 待語句執行完畢后,比較 源庫和 還原庫 的數據。

源庫

還原庫

我們看到集合orderdetial在兩個數據庫不一致,有差異。即這種備份還原 無法保證數據一致性。

3.1.2 增加 參數--oplog 參數下備份還原

Step 1 刪除 上次測試中遺留的集合 和 備份文件

Step 2 啟動insert命令

for(var i = 0; i < 10000; i++)

{ db.order0531.insert({a: i});};

 

for(i=0;i<150000;i++)

{ db.orderdetial.insert({"id":i,"name":"shenzheng","addr":"龍崗","date":new Date()}); };

 

Step 3 執行備份命令

./mongodump -h 172.177.XXX.XXX --port 端口  --oplog --authenticationDatabase admin -u 用戶名 -p密碼  --gzip -o /data/mongodb_back/mongotestdump

從打印結果來看,有對oplog命令的輸出,查看備份文件 多了一個 oplog.bson 文件

Step 4 執行還原命令,增加參數  --oplogReplay

./mongorestore -h 172.177.XXX.XXX --port 端口  --oplogReplay --authenticationDatabase admin -u 用戶名 -p 密碼  --gzip /data/mongodb_back/mongotestdump

從執行情況來看,此類還原命令有還原oplog

Step 5 比對數據

源庫

還原庫

 

本場景測試結論:

雖然結果數據仍不一致,但從后者的備份還原過程可以看出,有對oplog做單獨的處理。

數據可以保證以oplog結尾為准,實現了多集合(表)的時間一致性(MongoDB本身特性,不保證體現數據庫的事務一致性)。

 

3.2 場景二  還原到指定時間點

 

 

使用場景3.1.2 的備份文件,測試還原到備份過程中的某個時刻。從上次備份過程可知,開始時間為2018-05-31T11:13:46.501+0800,結束時間為 2018-05-31T11:14:12.961+0800

此輪測試還原點選擇在此時間段內。時間還原點的選擇,假如我們還原到orderdetial 集合"_id" : ObjectId("5b0f6876c52291864d3485b9")的插入時的時間點。

查看此時間點對應的時間和操作序列,在源庫local中的oplog.rs 集合查詢。

(oplog.rs集合的數據意義,我們在其他章節介紹,在此不做贅述)

"ts" : Timestamp(1527736438, 858)

此文檔對應的 "id" : 9719.0,插入時間為2018-05-31T11:13:58.721+0800 【正好,在mongodump的過程中】

 

Step 1 刪除還原服務器中的還原庫(上面測試遺留的數據庫)

Step 2 執行還原命令,通過--oplogLimit 參數指定時間點,時間點為上一步查到的Timestamp(1527736438, 858)

./mongorestore -h 172.177.XXX.XXX --port 端口  --oplogReplay --oplogLimit "1527736438:858" --authenticationDatabase admin -u 用戶名 -p 密碼  /data/mongodb_back/mongotestdump

Step 3 結果驗證

從print 出來的執行過程來看,相同的備份文件,相同的還原環境,添加--oplogLimit "1527736438:858" 參數的 replay Oplog,要小於上次不帶--oplogLimit參數的全還原。

本次還原,添加 --oplogLimit,只還原了 824 KB 的oplog

2018-05-31T16:55:21.975+0800     replaying oplog

2018-05-31T16:55:22.724+0800     oplog  85.9KB

2018-05-31T16:55:25.720+0800     oplog  575KB

2018-05-31T16:55:27.231+0800     oplog  842KB

2018-05-31T16:55:27.231+0800     done

 上次,沒有添加 --oplogLimit,默認全還原,所以還原了3.22MB oplog。

2018-05-31T11:23:33.770+0800     replaying oplog

2018-05-31T11:23:34.682+0800     oplog  146KB

2018-05-31T11:23:40.686+0800     oplog  1.10MB

2018-05-31T11:23:49.688+0800     oplog  2.61MB

2018-05-31T11:23:52.680+0800     oplog  3.11MB

2018-05-31T11:23:53.246+0800     oplog  3.22MB

2018-05-31T11:23:53.246+0800     done

這也容易理解。全還原一定大於指定時間的部分還原。

數據檢驗 :

(1)此時最大ID為"id" : 9718.0,和參數值對應的ID值連續

(2)此過程共還原數據9719,低於全還原的63862

 

本場景測試結論:

使用參數--oplogReplay –oplogLimit 可以將數據庫還原到指定時刻。

 

3.3 場景三 oplog.rs 集合中導出數據進行還原

在場景2 中的 oplog.bson 是我們在mongodump 全庫時,添加參數--oplog參數后自動生成的 全庫備份,受限於性能損耗和資源限制,不能高頻率執行和長時間存儲。考慮到副本集的oplog保存在oplog.rs集合中,此輪測試驗證是否只從oplog.rs導出,就可以保證數據連續性。即從oplog.rs導出的數據是否可以替代mongodump過程中產生的oplog.bson.

類似於我們從oplog.rs集合中導出MySQL的binlog文件,也類似於SQL Server Log日志,可以實現增量備份與增量還原。

Step 1 在上述場景中繼續測試,我們已經執行全庫還原,只是時間點還原到"id" : 9718.0 對應的數據。

Step 2 刪除 上次全備過程中產生的備份文件

Step 3 為增加試驗效果,再次在源庫插入部分數據

for(var i = 0; i < 10000; i++)

{ db.order0531.insert({a: i});};

 

for(i=0;i<200000;i++)

{ db.orderdetial.insert({"id":i,"name":"shenzheng","addr":"龍崗","date":new Date()}); };

step 4 將數據庫local中集合oplog.rs 導出(建議導出時,增加時間參數,例如一小時內的或大於某時間時刻。注意,此處的測試場景中,我們選擇的Timestamp(1527552239,1),在我們場景2中的Timestamp(1527736438, 858)的前面,故意時間重疊)

./mongodump -h 172.177.XXX.XXX --port 端口 --authenticationDatabase admin -u 用戶名 -p 密碼 -d local -c oplog.rs  --query '{ts:{$gte:Timestamp(1527552239,1)}}' -o /data/mongodb_back/mongotestoplog

step 5 將備份產生的文件local/oplog.rs.bson,copy至還原路徑下,並將其命名為oplog.bson

cp ./mongotestoplog/local/oplog.rs.bson ./mongotestdump/oplog.bson

step 6 執行還原命令

./mongorestore -h 172.177.XXX.XXX --port 端口  --oplogReplay --authenticationDatabase admin -u 用戶名 –p 密碼  /data/mongodb_back/mongotestdump

step 7 數據驗證

還原庫

源庫

兩者數據一致

 

本場景測試結論:

(1)dumprestor 命令,可以接受從別處而來,除了--oplog之外,可人為獲取的從oplog.rs中導出;還原時需重命名(step 5)。

(2)可以實現數據庫的增量備份與增量還原。我們可以設置Job,每小時從集合oplog.rs中導出一份操作日志。然后再利用這些文件中進行還原。注意此處的增量,是針對數據變化的,不是針對上次的全庫備份。此概念與關系型數據庫中的增量備份還原不同,其實更像關系型數據庫中的日志備份和還原。

(3)oplog有一個非常重要的特性——冪等性(idempotent)。即對一個數據集合,使用oplog中記錄的操作重放時,無論被重放多少次,其結果會是一樣的。舉例來說,如果oplog中記錄的是一個插入操作,並不會因為你重放了兩次,數據庫中就得到兩條相同的記錄。

四 總結 

1. MongoDB 不支持事務,無法保證備份還原命令中的事務完整性、業務一致性(無關系數型據庫中基於事務日志的重做還原機制)。但結合命令參數--oplog,可以實現數據、業務的時間一致性。

2. 數據庫還原時,結合參數--oplogReplay  --oplogLimit實現指定時間點的還原。

3. 搭建副本集的MongoDB,定期導出oplog.rs,可以實現增量備份與增量還原。

 

 

本文版權歸作者所有,未經作者同意不得轉載,謝謝配合!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM