mongodb中的復制可以在多台服務器中同步數據。
復制提供了冗余和增加了數據的高可用性,防止單個節點易丟失數據的可能性,也可以用來進行讀寫分離提高客戶端操作性能。
復制集中各節點的mongodb實例有相同的數據集副本。主節點可以接收客戶端所有寫操作記錄到日志中,從庫復制主庫的操作日志記錄應用到其數據庫中。
一個客戶端只能有一個主節點,如果主節點不可用(10秒內無法連接),復制集中將選一個成員節點作為主節點。
mongodb復制的基本結構如下:
前期 — 配置服務器名稱和IP綁定:
1. 設置服務器名稱,3台服務器各自設置自己的主機名(當前終端需重新打開才變化)
[root@mongodb11 ~]# vi/etc/sysconfig/network
HOSTNAME= mongodb11.kk.net
2. 不重啟計算機則執行以下方法:
[root@mongodb11 ~]# hostname mongodb11.kk.net
#另兩台也更改服務器名稱:
HOSTNAME= mongodb12.kk.net
HOSTNAME= mongodb13.kk.net
[root@mongodb12 ~]#hostname mongodb12.kk.net
[root@mongodb13 ~]#hostname mongodb13.kk.net
3. 在3台服務器文件hosts 中都添加以下3行:
# vi /etc/hosts
192.168.1.11 mongodb11.kk.net 192.168.1.12 mongodb12.kk.net 192.168.1.13 mongodb13.kk.net
實驗 — 復制的部署測試:
給3台服務器配置mongodb啟動參數(參數如下表格):
[root@mongodb ~]# vi/etc/mongod.conf
192.168.1.11(mongodb11.kk.net)#將作為主庫
pidfilepath=/var/run/mongodb/mongod.pid
logpath=/var/log/mongodb/mongod.log
dbpath=/var/lib/mongo
logappend=true
bind_ip=192.168.1.11
port=27017
fork=true
replSet=rs0
192.168.1.12(mongodb12.kk.net)
pidfilepath=/var/run/mongodb/mongod.pid
logpath=/var/log/mongodb/mongod.log
dbpath=/var/lib/mongo
logappend=true
bind_ip=192.168.1.12
port=27018
fork=true
replSet=rs0
192.168.1.13(mongodb13.kk.net)
pidfilepath=/var/run/mongodb/mongod.pid
logpath=/var/log/mongodb/mongod.log
dbpath=/var/lib/mongo
logappend=true
bind_ip=192.168.1.13
port=27019
fork=true
replSet=rs0
配置完成後重啟服務:(replSet=rs0 #復制集名稱:rs0)
[root@mongodb ~]#service mongod restart
【在192.168.1.11(mongodb11.kk.net)中部署】
1. 登錄到mongodb中:
[root@mongodb11 ~]# mongo192.168.1.11:27017
2. 初始化復制集:(集合為:"rs0" ;第一個成員為:"mongodb11.kk.net:27017" )
>rs.initiate({_id: "rs0",members: [{ _id: 0 , host: "mongodb11.kk.net:27017" }]})
rs.add("mongodb12.kk.net:27018") rs.add("mongodb13.kk.net:27019")
rs0:PRIMARY> rs.status() { "set" : "rs0", "date" : ISODate("2015-05-13T13:56:35.020Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "mongodb11.kk.net:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 990, "optime" : Timestamp(1431525353, 1), "optimeDate" : ISODate("2015-05-13T13:55:53Z"), "electionTime" : Timestamp(1431524773, 2), "electionDate" : ISODate("2015-05-13T13:46:13Z"), "configVersion" : 3, "self" : true }, { "_id" : 1, "name" : "mongodb12.kk.net:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 47, "optime" : Timestamp(1431525353, 1), "optimeDate" : ISODate("2015-05-13T13:55:53Z"), "lastHeartbeat" : ISODate("2015-05-13T13:56:33.382Z"), "lastHeartbeatRecv" : ISODate("2015-05-13T13:56:34.022Z"), "pingMs" : 0, "syncingTo" : "mongodb11.kk.net:27017", "configVersion" : 3 }, { "_id" : 2, "name" : "mongodb13.kk.net:27019", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 41, "optime" : Timestamp(1431525353, 1), "optimeDate" : ISODate("2015-05-13T13:55:53Z"), "lastHeartbeat" : ISODate("2015-05-13T13:56:33.412Z"), "lastHeartbeatRecv" : ISODate("2015-05-13T13:56:33.467Z"), "pingMs" : 1, "configVersion" : 3 } ], "ok" : 1 }
use admin db.runCommand( { replSetGetStatus : 1 } )
詳細說明如下:( 參考: replSetGetStatus ) (state 參考 Replica Set Member States)
"_id" : #集群中節點編號 "name" : #成員服務器名稱及端口 "health" : #表示成員中的健康狀態(0:down;1:up) "state" : #為0~10,表示成員的當前狀態 "stateStr" : #描述該成員是主庫(PRIMARY)還是備庫(SECONDARY) "uptime" : #該成員在線時間(秒) "optime" : #成員最後一次應用日志(oplog)的信息 "optimeDate" : #成員最後一次應用日志(oplog)的時間 "electionTime" : #當前primary從操作日志中選舉信息 "electionDate" : #當前primary被選定為primary的日期 "configVersion" : #mongodb版本 "self" : #為true 表示當前節點
5. 測試操作。在主庫中,可以任意操作:
rs0:PRIMARY> show dbs admin 0.078GB local 4.076GB mydb 0.078GB test 0.078GB rs0:PRIMARY> use mydb switched to db mydb rs0:PRIMARY> rs0:PRIMARY> db.coll.insert({"id":1}) WriteResult({ "nInserted" : 1 }) rs0:PRIMARY> rs0:PRIMARY> db.coll.find() { "_id" : ObjectId("5553670b60be2bf611868985"), "id" : 1 } rs0:PRIMARY> rs0:PRIMARY> db.coll.remove({"id":1}) WriteResult({ "nRemoved" : 1 }) rs0:PRIMARY>
【現在到分庫中】
192.168.1.12(mongodb12.kk.net)
192.168.1.13(mongodb13.kk.net)
查看分庫數據庫目錄,發現多了幾個數據庫,數據庫與主庫(192.168.1.11)一致!是主庫同步過來的。
[root@mongodb12 ~]# ll /var/lib/mongo/
[root@mongodb13 ~]# ll /var/lib/mongo/ total 2423844 -rw-------. 1 mongod mongod 67108864 May 13 21:55 admin.0 -rw-------. 1 mongod mongod 16777216 May 13 21:55 admin.ns drwxr-xr-x. 2 mongod mongod 4096 May 13 21:55 journal -rw-------. 1 mongod mongod 67108864 May 13 21:55 local.0 -rw-------. 1 mongod mongod 2146435072 May 13 23:00 local.1 -rw-------. 1 mongod mongod 16777216 May 13 23:00 local.ns -rwxr-xr-x. 1 mongod mongod 6 May 13 21:40 mongod.lock -rw-------. 1 mongod mongod 67108864 May 13 23:00 mydb.0 -rw-------. 1 mongod mongod 16777216 May 13 23:00 mydb.ns -rw-r--r--. 1 mongod mongod 69 May 12 22:05 storage.bson -rw-------. 1 mongod mongod 67108864 May 13 21:55 test.0 -rw-------. 1 mongod mongod 16777216 May 13 21:55 test.ns drwxr-xr-x. 2 mongod mongod 4096 May 13 21:55 _tmp
[root@mongodb12 ~]# mongo 192.168.1.12:27018 MongoDB shell version: 3.0.2 connecting to: 192.168.1.12:27018/test rs0:SECONDARY>
rs0:SECONDARY> rs.slaveOk();
現在模擬主庫不可用,將主節點服務停止:
[root@mongodb11 ~]# service mongod stop
到節點192.168.1.12 中登錄mongodb,查看復制集狀態:
rs0:SECONDARY> rs.status() { "set" : "rs0", "date" : ISODate("2015-05-13T15:44:00.883Z"), "myState" : 2, "members" : [ { "_id" : 0, "name" : "mongodb11.kk.net:27017", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : Timestamp(0, 0), "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2015-05-13T15:43:58.977Z"), "lastHeartbeatRecv" : ISODate("2015-05-13T15:42:16.467Z"), "pingMs" : 0, "lastHeartbeatMessage" : "Failed attempt to connect to mongodb11.kk.net:27017; couldn't connect to server mongodb11.kk.net:27017 (192.168.1.11), connection attempt failed", "configVersion" : -1 }, { "_id" : 1, "name" : "mongodb12.kk.net:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 7431, "optime" : Timestamp(1431529249, 1), "optimeDate" : ISODate("2015-05-13T15:00:49Z"), "configVersion" : 3, "self" : true }, { "_id" : 2, "name" : "mongodb13.kk.net:27019", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 6486, "optime" : Timestamp(1431529249, 1), "optimeDate" : ISODate("2015-05-13T15:00:49Z"), "lastHeartbeat" : ISODate("2015-05-13T15:44:00.530Z"), "lastHeartbeatRecv" : ISODate("2015-05-13T15:44:00.091Z"), "pingMs" : 0, "electionTime" : Timestamp(1431531738, 1), "electionDate" : ISODate("2015-05-13T15:42:18Z"), "configVersion" : 3 } ], "ok" : 1 }
以上信息看到:
原來的主實例(mongodb11.kk.net:27017 )已經無法連接了;
而其中一個節點(mongodb13.kk.net:27019 )變成了主實例,此時該節點是可以讀寫數據的;
啟動服務器 mongodb11.kk.net 的mongodb服務,其變為了副本 (SECONDARY)。
如果想切換回原來的主庫,參考:Force a Member to Become Primary
1. 使用命令rs.status() 確認數據集成員運行正常 2. 到次節點192.168.1.12(mongodb12.kk.net)中登錄mongodb,運行freeze使其120內不會變為主節點。 rs.freeze(120) 3. 到主節點192.168.1.13(mongodb13.kk.net)中強制切換主節點,stepDown將阻止長事務和寫入操作 rs.stepDown(120) 此時節點192.168.1.11(mongodb11.kk.net)變成主節點
若要使某個節點永遠不會變為主節點,設置優先級為0。(參考 Prevent Secondary from Becoming Primary)
cfg = rs.conf() cfg.members[0].priority = 0.5 cfg.members[1].priority = 0.5 cfg.members[2].priority = 0 rs.reconfig(cfg) 說明:其中成員編號 0/1/2 為 rs.status()中的 "_id"值 members[2]為192.168.1.13(mongodb13.kk.net),則它將用於不會變成主節點
移除一個復制成員(兩種方法):
登錄到主庫: mongodb11.kk.net ,移除成員 rs.remove("mongodb13.kk.net:27019") 或者: cfg = rs.conf() cfg.members.splice(2,1) rs.reconfig(cfg)
#replSet=rs0 #注釋
再重啟服務,完成移除(數據庫文件仍保留在當前服務器)。