一開始我就以為 oplog 應該就類似於 mysql bin-log 而事實上,確實差不多。oplog 也是用於複製集間由 Primary 記錄,Secondary 用來同步。從而保持數據一致。 最近遇到了誤刪db(刪庫不能跑路)的事情,所以,實驗了N多次的 oplog 恢複數據。 特地記錄一下,以 ...
一開始我就以為 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 ## 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恢復到某台單機上,再使用導出導入的方法將數據移到生產環境。
試驗往單機恢復的時候,同一個命令執行多次,有時出錯有時成功,就不知道為什麼了。操作時只能是多試幾次了。