1. 程式人生 > 資料庫 >MongoDB複製集環境基於時間點的恢復

MongoDB複製集環境基於時間點的恢復

背景

對於任何型別的資料庫,如果要將資料庫恢復到過去的任意時間點,需要有過去某個時間點的全備+全備之後的重做日誌,MongoDB也不例外。使用全備將資料庫恢復到固定時刻,然後使用重做日誌追加全備之後的操作。

案例3: 誤操作某個集合,對單個集合進行恢復

案例2: 誤刪除某個DB,對單個DB進行恢復

案例1:將整個例項恢復到某個時間點

寫在前面

摘錄自https://www.cnblogs.com/lijiaman/p/13526238.html(推薦閱讀)

1.概述

在這裡插入圖片描述

重做日誌備份:MongoDB只有開啟主從複製或者副本集時才會開啟重做日誌,主從複製存放在local資料庫下的oplog.$main集合中,複製集的日誌存放在local資料庫下的oplog.rs集合中,該集合是一個上限集合,當達到固定大小時,最老的記錄會被自動覆蓋。

因此需要注意,MongoDB的重做日誌並不會一直儲存著,能否恢復到故障點,完全取決於日誌是否完整。

環境

MongoDB 4.2.8版本副本集環境(一主一從一仲裁)

確認日誌儲存情況

oplog是一個上限集合,當資料量達到一定大小後,MongoDB會自動清理oplog日誌資訊,為了保證恢復能夠正常進行,需要確認日誌的時間是否符合還原需求。

簡單來說,oplog應該儲存著自上一次備份以來的所有日誌。可以使用下面方法來確認最早的oplog。

方法:檢視主從複製資訊 在主節點檢視日誌資訊,可以看到oplog日誌大小,因為oplog是一個固定大小的集合,所以還可以看到日誌的開始、結束時間、oplog的時間差等。

rs0:PRIMARY>rs.printReplicationInfo()

configured oplog size:   990MB
log length start to end: 14775296secs (4104.25hrs)
oplog first event time:  Fri Jul 03 2020 07:23:41 GMT+0000 (UTC)
oplog last event time:   Mon Dec 21 2020 07:38:37 GMT+0000 (UTC)
now:                     Mon Dec 21 2020 07:38:44 GMT+0000 (UTC)

案例1:將整個例項恢復到某個時間點

場景描述

業務人員發現多個MongoDB資料庫均存在資料錯誤的情況,需要將全部資料恢復到過去的某個時刻。

資料恢復方法描述
只要確定了恢復時間點,就可以使用完全備份+oplog備份,將資料恢復到過去的某個時刻。

大致流程,(恢復過程中需停庫,並且是整個例項(所有庫都受影響)) 1.基於全備(資料恢復到故障之前), 2.基於local庫的oplog日誌(通過資料的_id找到需要恢復的時間點)其中需要更改日誌備份的檔名,並且保證日誌沒有被覆蓋

恢復過程

1.模擬業務正常執行,資料正常進入MongoDB資料庫

db.test1.insert({id:1,name:'a'})
db.test1.insert({id:2,name:'b'})

db.test1.find()
{ "_id" : ObjectId("5fe05220bfb5260f460a6eec"), "id" : 1, "name" : "a" }
{ "_id" : ObjectId("5fe05222bfb5260f460a6eed"), "id" : 2, "name" : "b" }

2.執行完整備份

mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary  -o /dfile/mongobak

以上為Replica Set(副本集備份)
預設情況下,mongodump讀取Primary節點的資料,如果想讀取Secondary節點的資料,則需要使用選項readPreference。

rs0為副本集的名稱 

-o /dfile/mongobak  備份目錄(目錄按照資料庫名顯示)
[root@0e9aebbbddf3 mongobak]# ls
11  admin  test  tt
[root@0e9aebbbddf3 mongobak]# ls test
test.bson           test1.metadata.json  user00.bson           user111.metadata.json
test.metadata.json  user.bson            user00.metadata.json  users.bson
test1.bson          user.metadata.json   user111.bson          users.metadata.json

在這裡插入圖片描述

3.再次模擬業務正常執行,資料正常進入MongoDB資料庫

模擬全備之後的資料寫入,也就是需要通過日誌恢復的內容

db.test1.insert({id:3,name:'c'})

最終資料如下:

db.test1.find()
{ "_id" : ObjectId("5fe05220bfb5260f460a6eec"), "id" : 1, "name" : "a" }
{ "_id" : ObjectId("5fe05222bfb5260f460a6eed"), "id" : 2, "name" : "b" }
{ "_id" : ObjectId("5fe0565fbfb5260f460a6eee"), "id" : 3, "name" : "c" }

4.模擬資料誤操作

test1集合id增加100
use test
db.test1.update({},{$inc:{"id":100}},{multi:true})

誤操作之後的資料:

db.test1.find()
{ "_id" : ObjectId("5fe05220bfb5260f460a6eec"), "id" : 101, "name" : "a" }
{ "_id" : ObjectId("5fe05222bfb5260f460a6eed"), "id" : 102, "name" : "b" }
{ "_id" : ObjectId("5fe0565fbfb5260f460a6eee"), "id" : 103, "name" : "c" }

要求把所有資料庫的資料恢復到STEP4之前的狀態。

5.停止業務,不再往資料庫寫資料

6.備份日誌。可以備份部分日誌,也可以備份全部日誌

mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary  -d local -c oplog.rs -o /dfile/mongobak/oplog
mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary  -d local -c oplog.rs -o /dfile/mongobak/oplog

2020-12-21T08:09:00.256+0000    WARNING: ignoring unsupported URI parameter 'replicaset'
2020-12-21T08:09:00.266+0000    writing local.oplog.rs to /dfile/mongobak/oplog/local/oplog.rs.bson
2020-12-21T08:09:00.271+0000    done dumping local.oplog.rs (1495 documents)

[mongobak]# ls oplog/
local
[mongobak]# ls oplog/local/
oplog.rs.bson  oplog.rs.metadata.json

7.確認資料異常時間點,對oplog集合進行分析

db.oplog.rs.find({$and:[{"ns":/test/},{"op":"u"}]}).sort({ts:1})db.oplog.rs.find({$and:[{"ns":/test/},{"op":"u"}]}).sort({ts:1})

查詢結果如下,可以確認,開始對test.test1集合更新的時間為Timestamp(1608537904, 1)
#根據資料的_id和下面的_id對應

{ "ts" : Timestamp(1608537904, 1), "t" : NumberLong(11), "h" : NumberLong(0), "v" : 2, "op" : "u", "ns" : "test.test1", "ui" : UUID("02287b04-f11b-4069-8816-d87199bc9f5b"), "o2" : { "_id" : ObjectId("5fe05220bfb5260f460a6eec") }, "wall" : ISODate("2020-12-21T08:05:04.795Z"), "o" : { "$v" : 1, "$set" : { "id" : 101 } } }
{ "ts" : Timestamp(1608537904, 2), "t" : NumberLong(11), "h" : NumberLong(0), "v" : 2, "op" : "u", "ns" : "test.test1", "ui" : UUID("02287b04-f11b-4069-8816-d87199bc9f5b"), "o2" : { "_id" : ObjectId("5fe05222bfb5260f460a6eed") }, "wall" : ISODate("2020-12-21T08:05:04.796Z"), "o" : { "$v" : 1, "$set" : { "id" : 102 } } }
{ "ts" : Timestamp(1608537904, 3), "t" : NumberLong(11), "h" : NumberLong(0), "v" : 2, "op" : "u", "ns" : "test.test1", "ui" : UUID("02287b04-f11b-4069-8816-d87199bc9f5b"), "o2" : { "_id" : ObjectId("5fe0565fbfb5260f460a6eee") }, "wall" : ISODate("2020-12-21T08:05:04.796Z"), "o" : { "$v" : 1, "$set" : { "id" : 103 } } }

8.執行完全備份的恢復

``
需要注意,考慮是否需要使用"–drop"選項,如果不用該選項,會保留集合中當前的資料,如果使用了drop選項,在匯入集合時會先刪除集合。這裡使用該選項(因為我們要修改,所以需要新增–drop)

如果還原匯入已存在的例項中的資料庫或集合有已存在相同_id的文件,mongorestore並不會覆蓋。

``

mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017"  --drop  /dfile/mongobak

注意執行之後的資訊:
22 document(s) restored successfully. 0 document(s) failed to restore.

確認全量恢復的資料,已經恢復回來

#恢復之前
rs0:PRIMARY> use testdb.test1.find()db.test1.find()
{ "_id" : ObjectId("5fe05220bfb5260f460a6eec"), "id" : 101, "name" : "a" }
{ "_id" : ObjectId("5fe05222bfb5260f460a6eed"), "id" : 102, "name" : "b" }
{ "_id" : ObjectId("5fe0565fbfb5260f460a6eee"), "id" : 103, "name" : "c" }
#恢復之後
rs0:PRIMARY> db.test1.find()db.test1.find()
{ "_id" : ObjectId("5fe05220bfb5260f460a6eec"), "id" : 1, "name" : "a" }
{ "_id" : ObjectId("5fe05222bfb5260f460a6eed"), "id" : 2, "name" : "b" }

在這裡插入圖片描述

9.使用oplog執行增量恢復

在恢復oplog之前,需要對其格式進行處理,否則會報錯

#報錯資訊
mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --oplogReplay --oplogLimit "1608537904:1"  /dfile/mongobak/oplog/local


2020-12-21T08:32:17.219+0000    WARNING: ignoring unsupported URI parameter 'replicaset'
2020-12-21T08:32:17.226+0000    preparing collections to restore from
2020-12-21T08:32:17.226+0000    don't know what to do with file "/dfile/mongobak/oplog/local/oplog.rs.bson", skipping...
2020-12-21T08:32:17.227+0000    don't know what to do with file "/dfile/mongobak/oplog/local/oplog.rs.metadata.json", skipping...
2020-12-21T08:32:17.227+0000    Failed: no oplog file to replay; make sure you run mongodump with --oplog
2020-12-21T08:32:17.227+0000    0 document(s) restored successfully. 0 document(s) failed to restore.

需要把oplog.rs.metadata.json 檔案刪除,把oplog.rs.bson名字改為oplog.bson

[root@0e9aebbbddf3 mongobak]# cd oplog/
[root@0e9aebbbddf3 oplog]# ls
local
[root@0e9aebbbddf3 oplog]# cd local/
[root@0e9aebbbddf3 local]# ls
oplog.rs.bson  oplog.rs.metadata.json
[root@0e9aebbbddf3 local]# pwd
/dfile/mongobak/oplog/local
[root@0e9aebbbddf3 local]# rm -rf oplog.rs.metadata.json 
[root@0e9aebbbddf3 local]# mv oplog.rs.bson oplog.bson    
[root@0e9aebbbddf3 local]# ls
oplog.bson

最後執行oplog增量恢復即可

#成功執行的資訊
mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --oplogReplay --oplogLimit "1608537904:1"  /dfile/mongobak/oplog/local

2020-12-21T08:35:26.823+0000    WARNING: ignoring unsupported URI parameter 'replicaset'
2020-12-21T08:35:26.829+0000    preparing collections to restore from
2020-12-21T08:35:26.829+0000    replaying oplog
2020-12-21T08:35:26.961+0000    applied 101 oplog entries
2020-12-21T08:35:26.961+0000    0 document(s) restored successfully. 0 document(s) failed to restore

許可權問題:原文提到恢復使用者不能具有root的角色

10.確認資料恢復情況,發現數據以及恢復到了STEP4之前的狀態

rs0:PRIMARY> db.test1.find()db.test1.find()
{ "_id" : ObjectId("5fe05220bfb5260f460a6eec"), "id" : 1, "name" : "a" }
{ "_id" : ObjectId("5fe05222bfb5260f460a6eed"), "id" : 2, "name" : "b" }
{ "_id" : ObjectId("5fe0565fbfb5260f460a6eee"), "id" : 3, "name" : "c" }

在這裡插入圖片描述
至此恢復結束。

案例2: 誤刪除某個DB,對單個DB進行恢復

通常,每個DB承載不同的業務,相互之間沒有關係,如果出現故障,往往會表現在某個DB上,因此,如果出現故障,只對相應的DB進行恢復,那將減小對業務的影響。

場景:假設業務執行過程中,資料庫db3被人誤刪除了,我們需要對db3進行恢復,並且不能影響到其它的DB業務。

推薦做法:

可以在當前例項上進行恢復,也可以新啟動一個mongod例項,用於資料恢復,我們採用新的mongod例項來恢復資料。

恢復到測試庫,確定資料沒有問題,最後通過備份恢復的方式恢復到生成環境


1.首先新啟動一個mongod例項;
2.將已有的完全備份恢復到新的例項上;
3.備份oplog,只備份db3的oplog,其它資料庫的不備份;
4.使用oplog將資料庫恢復到刪除之前;
5.檢查db3資料庫的資料,確認是否恢復回來;
6.如果第5步沒有問題,mongodump匯出db3資料庫,然後倒入到生產環境中。


1.模擬業務正常執行,資料正常進入MongoDB資料庫

use db3
db.db3test.insert({id:111,name:'aaa'})
db.db3test.insert({id:222,name:'bbb'})
db.db3test.insert({id:333,name:'ccc'})

rs0:PRIMARY> db.db3test.find()db.db3test.find()
{ "_id" : ObjectId("5fe06487bfb5260f460a6eef"), "id" : 111, "name" : "aaa" }
{ "_id" : ObjectId("5fe06487bfb5260f460a6ef0"), "id" : 222, "name" : "bbb" }
{ "_id" : ObjectId("5fe06488bfb5260f460a6ef1"), "id" : 333, "name" : "ccc" }

2.執行完整備份

mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary  -o /dfile/mongobak

3.再次模擬業務正常執行,資料正常進入MongoDB資料庫

db.db3test.insert({id:444,name:'ddd'})
db.db3test.insert({id:555,name:'eee'})
db.db3test.insert({id:666,name:'fff'})

最終資料如下:

db.db3test.find()
{ "_id" : ObjectId("5fe06487bfb5260f460a6eef"), "id" : 111, "name" : "aaa" }
{ "_id" : ObjectId("5fe06487bfb5260f460a6ef0"), "id" : 222, "name" : "bbb" }
{ "_id" : ObjectId("5fe06488bfb5260f460a6ef1"), "id" : 333, "name" : "ccc" }
{ "_id" : ObjectId("5fe06563bfb5260f460a6ef2"), "id" : 444, "name" : "ddd" }
{ "_id" : ObjectId("5fe06563bfb5260f460a6ef3"), "id" : 555, "name" : "eee" }
{ "_id" : ObjectId("5fe06564bfb5260f460a6ef4"), "id" : 666, "name" : "fff" }

4.模擬資料誤操作

rs0:PRIMARY> dbdb
db3
rs0:PRIMARY> db.dropDatabase()
        "dropped" : "db3",
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1608541699, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1608541699, 2)
}

show tables;

接下來執行恢復操作。

5.在發現誤操作之後,首先應該備份oplog,這裡只涉及到db3資料庫,只要備份db3的oplog即可,這樣可以加快備份恢復速度

mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary  -d local -c oplog.rs -q '{"ns":{"$regex":"db3"}}'  -o /dfile/mongobak/oplog

6.先執行完全恢復(只恢復db3庫)

#使用的是全備目錄中的db3目錄(推薦先恢復到測試庫)
mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" -d db3  /dfile/mongobak/db3

執行恢復後,db3資料已經恢復到了全備時的狀態

rs0:PRIMARY> show tables;
db3test
rs0:PRIMARY> show collections
db3test
rs0:PRIMARY> db.db3test.find()
{ "_id" : ObjectId("5fe06487bfb5260f460a6eef"), "id" : 111, "name" : "aaa" }
{ "_id" : ObjectId("5fe06487bfb5260f460a6ef0"), "id" : 222, "name" : "bbb" }
{ "_id" : ObjectId("5fe06488bfb5260f460a6ef1"), "id" : 333, "name" : "ccc" }

7.使用oplog恢復到drop操作之前

先確認drop db3資料庫的時間點:Timestamp(1608541699, 2)

use local
db.oplog.rs.find(
 {
     $and : [
      {"ns" : {"$regex":"db3"}},
      {"op" : "c"},
      {"o"  : {"dropDatabase":1}}
     ]
  }
).sort({ts:1})
#結果如下
{ "ts" : Timestamp(1608541699, 2), "t" : NumberLong(11), "h" : NumberLong(0), "v" : 2, "op" : "c", "ns" : "db3.$cmd", "wall" : ISODate("2020-12-21T09:08:19.243Z"), "o" : { "dropDatabase" : 1 } }
#Timestamp(1608541699, 2)的值和刪除時顯示的一致

執行增量恢復:

先處理oplog,刪除檔案oplog.rs.metadata.json,修改oplog.rs.bson為oplog.bson

[root@0e9aebbbddf3 oplog]# cd local/
[root@0e9aebbbddf3 local]# ls
oplog.bson  oplog.rs.bson  oplog.rs.metadata.json
[root@0e9aebbbddf3 local]# rm -rf oplog.rs.metadata.json 
[root@0e9aebbbddf3 local]# mv oplog. 
oplog.bson     oplog.rs.bson  
[root@0e9aebbbddf3 local]# mv oplog.rs.bson oplog.bson 
mv: overwrite 'oplog.bson'? y  #上次遺留的(可覆蓋,可以移動到其他目錄)
[root@0e9aebbbddf3 local]# ls
oplog.bson

執行恢復
--oplogLimit "1608541699:1" 是在use local db.oplog.rs.find()中查到的前一個時間點(因為--oplogLimit "1608541699:2",是查到的但是包含了drop database操作)。需要手動減1

mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --oplogReplay --oplogLimit "1608541699:1"  /dfile/mongobak/oplog/local 
2020-12-21T09:29:53.276+0000    WARNING: ignoring unsupported URI parameter 'replicaset'
2020-12-21T09:29:53.285+0000    preparing collections to restore from
2020-12-21T09:29:53.285+0000    replaying oplog
2020-12-21T09:29:53.298+0000    applied 7 oplog entries
2020-12-21T09:29:53.298+0000    0 document(s) restored successfully. 0 document(s) failed to restore.

原文提示: 特別注意:這裡發現,oplogLimit引數,在MongoDB 2.7版本中不包含後面的時間點,在4.2裡面包含後面的時間點。如果我使用時間Timestamp(1597374734, 2)來作為恢復點,則發現數據庫恢復完成又被刪除了。
檢查資料是否已經恢復,可以確認,資料已經恢復回來

db.db3test.find()
{ "_id" : ObjectId("5fe06487bfb5260f460a6eef"), "id" : 111, "name" : "aaa" }
{ "_id" : ObjectId("5fe06487bfb5260f460a6ef0"), "id" : 222, "name" : "bbb" }
{ "_id" : ObjectId("5fe06488bfb5260f460a6ef1"), "id" : 333, "name" : "ccc" }
{ "_id" : ObjectId("5fe06563bfb5260f460a6ef2"), "id" : 444, "name" : "ddd" }
{ "_id" : ObjectId("5fe06563bfb5260f460a6ef3"), "id" : 555, "name" : "eee" }
{ "_id" : ObjectId("5fe06564bfb5260f460a6ef4"), "id" : 666, "name" : "fff" }

至此恢復結束。

案例3: 誤操作某個集合,對單個集合進行恢復

場景

業務人員執行誤刪某個文件(集合)

T1~T2:業務正常執行,資料正常進入資料庫
T2:使用mongodump執行資料庫完全備份
T2~T4:業務正常執行,資料正常進入資料庫
T4:使用者誤刪除資料
T4~T6:業務還在執行,但是已經出現問題,如此時還能正常插入資料,但是查詢、更新、刪除資料存在找不到資料的錯誤
T6:DBA需資料恢復

推薦做法:在測試上恢復,確認資料正確之後,通過備份恢復的方式恢復到生產中

可以在當前例項上進行恢復,也可以新啟動一個mongod例項,用於資料恢復,我們在上一個例子中已經使用新建mongod例項的方式來恢復資料,本次實驗我們直接在生產例項上進行恢復。


1.執行完全恢復,使用完全備份,將資料庫恢復到T2時刻;
2.找到T4時刻故障之前的時間,從而確定T2~T4之間的oplog日誌。結合T2時刻的全備+ T2~T4之間的oplog日誌,實現資料恢復;(備註:這裡不需要去確認T2之後的日誌開始時間,在使用oplog恢復資料時,是通過唯一編號“_id”來操作資料的,oplog可能從全備份之前的任意時間開始,但是並不影響資料的正確性)。
3.找到T4時刻故障之後的時間,備份oplog。
4.使用oplog,實現T4~T6時間段的恢復。


恢復過程

1.模擬業務正常執行,資料正常進入MongoDB資料庫

use db4
db.db4test.insert({id:1111,name:'aaaa'})
db.db4test.insert({id:2222,name:'bbbb'})
db.db4test.insert({id:3333,name:'cccc'})

2.執行完整備份

mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary  -o /dfile/mongobak

3.再次模擬業務正常執行,資料正常進入MongoDB資料庫

use db4
db.db4test.insert({id:4444,name:'dddd'})
db.db4test.insert({id:5555,name:'eeee'})
db.db4test.insert({id:6666,name:'ffff'})

最終資料如下:

db.db4test.find()
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef5"), "id" : 1111, "name" : "aaaa" }
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef6"), "id" : 2222, "name" : "bbbb" }
{ "_id" : ObjectId("5fe070ffbfb5260f460a6ef7"), "id" : 3333, "name" : "cccc" }
{ "_id" : ObjectId("5fe07227bfb5260f460a6ef8"), "id" : 4444, "name" : "dddd" }
{ "_id" : ObjectId("5fe07227bfb5260f460a6ef9"), "id" : 5555, "name" : "eeee" }
{ "_id" : ObjectId("5fe07228bfb5260f460a6efa"), "id" : 6666, "name" : "ffff" }

4.模擬資料誤操作,刪除2條資料

db.db4test.remove({id:{$gt:4444}})
WriteResult({ "nRemoved" : 2 })
rs0:PRIMARY> db.db4test.find()db.db4test.find()
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef5"), "id" : 1111, "name" : "aaaa" }
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef6"), "id" : 2222, "name" : "bbbb" }
{ "_id" : ObjectId("5fe070ffbfb5260f460a6ef7"), "id" : 3333, "name" : "cccc" }
{ "_id" : ObjectId("5fe07227bfb5260f460a6ef8"), "id" : 4444, "name" : "dddd" }

5.再次模擬業務正常執行,資料正常進入MongoDB資料庫

use db4
db.db4test.insert({id:7777,name:'gggg'})
db.db4test.insert({id:8888,name:'hhhh'})
db.db4test.insert({id:9999,name:'kkkk'})

最終資料如下:

db.db4test.find()
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef5"), "id" : 1111, "name" : "aaaa" }
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef6"), "id" : 2222, "name" : "bbbb" }
{ "_id" : ObjectId("5fe070ffbfb5260f460a6ef7"), "id" : 3333, "name" : "cccc" }
{ "_id" : ObjectId("5fe07227bfb5260f460a6ef8"), "id" : 4444, "name" : "dddd" }
{ "_id" : ObjectId("5fe072c5bfb5260f460a6efb"), "id" : 7777, "name" : "gggg" }
{ "_id" : ObjectId("5fe072c6bfb5260f460a6efc"), "id" : 8888, "name" : "hhhh" }
{ "_id" : ObjectId("5fe072c7bfb5260f460a6efd"), "id" : 9999, "name" : "kkkk" }

此時,我們發現id為5555和6666的資料是被誤刪除的,需要恢復回來,並且要保留執行刪除命令之後的資料。

6.在發現誤操作之後,首先應該備份oplog,這裡只涉及到db4.db4test集合,只要備份該集合的oplog即可,這樣可以加快備份恢復速度

mongodump --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --readPreference=secondary -d local -c 'oplog.rs' -q '{"ns":"db4.db4test"}'  -o /dfile/mongobak/oplog

7.對該集合執行完全恢復操作

mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" -d db4 -c db4test  /dfile/mongobak/db4/db4test.bson

2020-12-21T10:08:23.286+0000    WARNING: ignoring unsupported URI parameter 'replicaset'
2020-12-21T10:08:23.293+0000    checking for collection data in /dfile/mongobak/db4/db4test.bson
2020-12-21T10:08:23.294+0000    restoring to existing collection db4.db4test without dropping
2020-12-21T10:08:23.294+0000    reading metadata for db4.db4test from /dfile/mongobak/db4/db4test.metadata.json
2020-12-21T10:08:23.294+0000    restoring db4.db4test from /dfile/mongobak/db4/db4test.bson
2020-12-21T10:08:23.299+0000    continuing through error: E11000 duplicate key error collection: db4.db4test index: _id_ dup key: { _id: ObjectId('5fe070fdbfb5260f460a6ef6') }
2020-12-21T10:08:23.299+0000    continuing through error: E11000 duplicate key error collection: db4.db4test index: _id_ dup key: { _id: ObjectId('5fe070ffbfb5260f460a6ef7') }
2020-12-21T10:08:23.300+0000    continuing through error: E11000 duplicate key error collection: db4.db4test index: _id_ dup key: { _id: ObjectId('5fe070fdbfb5260f460a6ef5') }
2020-12-21T10:08:23.359+0000    no indexes to restore
2020-12-21T10:08:23.359+0000    finished restoring db4.db4test (0 documents, 3 failures)
2020-12-21T10:08:23.359+0000    0 document(s) restored successfully. 3 document(s) failed to restore.

8.使用oplog,對該集合執行增量恢復操作

先檢視對db4.db4test集合執行刪除的開始時間Timestamp(1608544902, 1)

use local
db.oplog.rs.find(
 {
     $and : [
      {"ns" : /db4.db4test/},
      {"op" : "d" }
     ]
  }
).sort({ts:1})

{ "ts" : Timestamp(1608544902, 1), "t" : NumberLong(11), "h" : NumberLong(0), "v" : 2, "op" : "d", "ns" : "db4.db4test", "ui" : UUID("16ea0367-1ae2-4929-aad4-1dc16474d419"), "wall" : ISODate("2020-12-21T10:01:42.057Z"), "o" : { "_id" : ObjectId("5fe07227bfb5260f460a6ef9") } }
{ "ts" : Timestamp(1608544902, 2), "t" : NumberLong(11), "h" : NumberLong(0), "v" : 2, "op" : "d", "ns" : "db4.db4test", "ui" : UUID("16ea0367-1ae2-4929-aad4-1dc16474d419"), "wall" : ISODate("2020-12-21T10:01:42.058Z"), "o" : { "_id" : ObjectId("5fe07228bfb5260f460a6efa") } }

執行增量恢復:

先處理oplog,刪除檔案oplog.rs.metadata.json,修改oplog.rs.bson為oplog.bson

[root@0e9aebbbddf3 local]# ls
oplog.bson  oplog.rs.bson  oplog.rs.metadata.json
[root@0e9aebbbddf3 local]# rm -rf oplog.rs.metadata.json 
[root@0e9aebbbddf3 local]# mv oplog.rs.bson oplog.bson 
mv: overwrite 'oplog.bson'? y
[root@0e9aebbbddf3 local]# ls
oplog.bson

執行恢復
--oplogLimit "1608544902:1就是看到的第一個remove操作值

mongorestore --host="rs0/192.168.68.60:27017,192.168.68.61:27017,192.168.68.62:27017" --oplogReplay --oplogLimit "1608544902:1"  /dfile/mongobak/oplog/local


2020-12-21T10:18:08.274+0000    WARNING: ignoring unsupported URI parameter 'replicaset'
2020-12-21T10:18:08.283+0000    preparing collections to restore from
2020-12-21T10:18:08.283+0000    replaying oplog
2020-12-21T10:18:08.290+0000    applied 6 oplog entries
2020-12-21T10:18:08.290+0000    0 document(s) restored successfully. 0 document(s) failed to restore.

9.檢視資料是否恢復,確認已經完全恢復回來

最後兩行就是

db.db4test.find()
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef5"), "id" : 1111, "name" : "aaaa" }
{ "_id" : ObjectId("5fe070fdbfb5260f460a6ef6"), "id" : 2222, "name" : "bbbb" }
{ "_id" : ObjectId("5fe070ffbfb5260f460a6ef7"), "id" : 3333, "name" : "cccc" }
{ "_id" : ObjectId("5fe07227bfb5260f460a6ef8"), "id" : 4444, "name" : "dddd" }
{ "_id" : ObjectId("5fe072c5bfb5260f460a6efb"), "id" : 7777, "name" : "gggg" }
{ "_id" : ObjectId("5fe072c6bfb5260f460a6efc"), "id" : 8888, "name" : "hhhh" }
{ "_id" : ObjectId("5fe072c7bfb5260f460a6efd"), "id" : 9999, "name" : "kkkk" }
{ "_id" : ObjectId("5fe07227bfb5260f460a6ef9"), "id" : 5555, "name" : "eeee" }
{ "_id" : ObjectId("5fe07228bfb5260f460a6efa"), "id" : 6666, "name" : "ffff" }

至此恢復結束。

再次感謝原文
https://www.cnblogs.com/lijiaman/p/13526238.html

本文說明,主要技術內容來自網際網路技術大佬的分享,還有一些自我的加工(僅僅起到註釋說明的作用)。如有相關疑問,請留言,將確認之後,執行侵權必刪