一開始我就以為 oplog 應該就類似于 mysql bin-log 而事實上,確實差不多,oplog 也是用于復制集間由 Primary 記錄,Secondary 用來同步,從而保持資料一致,
最近遇到了誤刪db(刪庫不能跑路)的事情,所以,實驗了N多次的 oplog 恢復資料,
特地記錄一下,以備后查,
# ------------------------------ oplog ---------------------------------
## 1. 在復制集中使用 oplog ,可以使用以下命令查看oplog情況:
rpset1:PRIMARY> rs.printReplicationInfo()
configured oplog size: 10240MB
log length start to end: 149092secs (41.41hrs)
oplog first event time: Sun Apr 26 2020 20:25:46 GMT+0800 (CST)
oplog last event time: Tue Apr 28 2020 13:50:38 GMT+0800 (CST)
now: Tue Apr 28 2020 13:50:38 GMT+0800 (CST)
rpset1:SECONDARY> rs.printReplicationInfo()
configured oplog size: 10240MB
log length start to end: 149937secs (41.65hrs)
oplog first event time: Sun Apr 26 2020 20:10:59 GMT+0800 (CST)
oplog last event time: Tue Apr 28 2020 13:49:56 GMT+0800 (CST)
now: Tue Apr 28 2020 13:49:56 GMT+0800 (CST)
rpset1:SECONDARY> rs.printReplicationInfo()
configured oplog size: 10240MB
log length start to end: 148635secs (41.29hrs)
oplog first event time: Sun Apr 26 2020 20:32:00 GMT+0800 (CST)
oplog last event time: Tue Apr 28 2020 13:49:15 GMT+0800 (CST)
now: Tue Apr 28 2020 13:49:16 GMT+0800 (CST)
# 組態檔 conf/slave.conf 中的oplogSize
replication:
oplogSizeMB: 10240
replSetName: rpset1
從以上的命令中可以看出,這個復制集的 oplog 有41小時的容量,而這個 mongodb 每天都有定時備份,所以,這個容量肯定是夠用了,
使用 oplogReplay 恢復資料,官文說必須要有一個特殊的權限,
## 2. 創建專門的角色使用 oplogReplay 此角色必須有 anyResource 和 anyAction # 備份時不需要此權限,但恢復時必須要有此權限,否則恢復失敗且沒有報錯資訊, use admin db.createRole( { "role" : "sysadmin", "privileges" : [{ "resource" : {"anyResource" : true}, "actions" : ["anyAction"] }], "roles" : [] } ) # 創建專門的用戶使用此角色 db.createUser({user:"admin", pwd:"admin", roles:[{role:"sysadmin", db:"admin"}]}) # 或者授權某個用戶 db.grantRolesToUser( "root" , [ { role: "sysadmin", db: "admin" } ])
檢查一下定時備份db的命令,找到如下:
## 3. 日常全量備份 ./mongodump -h 10.170.6.116:27017 -u admin -p admin --authenticationDatabase admin --gzip -o /data/tmp/rs0 # 備份時如果有 --oplog 選項,輸出目錄下就會有 oplog.bson 檔案 # ./mongodump -h 10.170.6.116:27000 -u rsroot -p abcd1234 --authenticationDatabase admin --oplog -o /data/tmp/rs0
因為備份時沒有帶 --oplog 引數,所以進行恢復時,使用先恢復備份,再 oplogReplay的方式完成,也就是參考下面的第9點,
而4到8點,用來在恢復備份的同時帶上 oplogReplay 的方式,
## 4. 假設上次日常備份之后的某個時間點出現了誤洗掉操作,就需要利用 oplogReplay 來恢復這段時間的新資料 # 先檢查上次日常備份的時間點(如果 dump 時使用了 --oplog 引數,就會有oplog.bson檔案,如果沒有,可參考第9條): ./bsondump /data/tmp/rs0/oplog.bson > /data/tmp/0 cat /data/tmp/0 # 找到第一行 {"ts":{"$timestamp":{"t":1588138496,"i":1}}, ...
# 欄位的意思:
ts: 操作發生的時間,t: unix時間戳, i: 可以認為是同一時間內的第幾個. h: 記錄的唯一ID v: 版本資訊 op: 寫操作的型別 n: no-op c: db cmd i: insert u: update d: delete ns: 操作的namespace, 即: 資料庫.集合 o: 操作所對應的檔案 o2: 更新時所對應的where條件,更新時才有
# 起始時間戳可自由指定,不必oplog中找記錄,稍微早于需要的時間點即可,
./mongodump -h 192.168.6.116:27017 -u admin -p admin --authenticationDatabase admin -d local -c oplog.rs -q '{"ts":{"$gt": {"$timestamp":{"t":1588138300,"i":1}}}}' -o /data/tmp/rs1
## 5. 匯出當前的 local/oplog.rs 注意 -q 選項的 JSON格式 # 因為備份整個 local/oplog.rs 容量太大,恢復也會耗時過長,所以采用起始時間的方式: ./mongodump -h 192.168.6.116:27017 -u admin -p admin --authenticationDatabase admin -d local -c oplog.rs -q '{"ts":{"$gt": {"$timestamp":{"t":1588138393,"i":1}}}}' -o /data/tmp/rs1 # 也可以同時指定結束時間,如下: ./mongodump -h 192.168.6.116:27017 -u rsroot -p abcd1234 --authenticationDatabase admin -d local -c oplog.rs -q '{"ts":{"$lte": {"$timestamp":{"t":1588142111,"i":1}}, "$gte": {"$timestamp":{"t":1588138393,"i":1}}}}' -o /data/tmp/rs2 # 也可以使用 --queryFile=./n.json 的方式,指定查詢檔案(可能4.0.7以下版本會有錯誤提示)
{"ts":{"$gte": {"$timestamp":{"t":1589042338,"i":1}}}, "ns":{"$not": {"$regex": "test.names"}}}
# -q 引數示例:
-q '{"ts":{"$gte": {"$timestamp":{"t":1589342458,"i":1}}}, "ns":{"$nin":["test.tlog","config.system.sessions"]}}' -q '{"ts":{"$gte": {"$timestamp":{"t":1589342458,"i":1}}}, "lsid":{"$exists": false }}'
## 6. 檢查 oplog.rs.bson 手工找出誤洗掉的時間戳: ./bsondump /data/tmp/rs1/local/oplog.rs.bson > /data/tmp/1 # 打開 /data/tmp/1 手工查找,如果有洗掉表或庫,則有 drop 資訊, 如果有洗掉資料,則有 "op":"d" 資訊 ## 7. 替換日常全備份中的 oplog.bson rm -rf /data/tmp/rs0/oplog.bson mv /data/tmp/rs1/local/oplog.rs.bson /data/tmp/rs0/oplog.bson ## 8. 執行恢復命令(注意用戶權限) ./mongorestore -h 192.168.6.116:27017 -u admin -p admin --authenticationDatabase admin --oplogReplay --oplogLimit "1588232764:1" --dir /data/tmp/rs0/ # 其中 1588232764 即是 $timestamp 中的"t",1 即是 $timestamp 中的 "i" 這樣配置后oplog將會 # 重放到這個時間點以前,即正好避開了第一條洗掉陳述句及其后面的操作,資料庫停留在災難前狀態 ## 9. 如果日常備份沒有 --oplog 并且使用了 --gzip,可以先恢復此備份, # 然后再使用oplogReplay 指定單獨的 oplog.rs.bson 檔案進行恢復. ./mongorestore -h 192.168.6.116:27017 -u admin -p admin --authenticationDatabase admin /data/tmp/rs0/ --gzip ./mongorestore -h 192.168.6.116:27017 -u admin -p admin --authenticationDatabase admin --oplogReplay --oplogLimit "1588232764:1" /data/tmp/rs1/local/oplog.rs.bson
# 有可能恢復時不成功,提示 “ applyOps field: no such field ” ,此時,只能使用上面的第8步的方式試試了,
不必擔心資料混亂,因為 oplog 的冪等性,即使多次Replay 也不會產生重復資料, 已存在相同的 _id,即使其它欄位不同,也不會恢復,不存在的 _id 則會恢復,
當然,也可以將備份和oplog恢復到某臺單機上,再使用匯出匯入的方法將資料移到生產環境,
試驗往單機恢復的時候,同一個命令執行多次,有時出錯有時成功,就不知道為什么了,操作時只能是多試幾次了,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/4598.html
標籤:NoSQL
上一篇:Redis 字典實作
