|
MongoDB復(fù)制原理就是主節(jié)點記錄在其上的所有操作oplog,從節(jié)點定期輪詢主節(jié)點獲取這些操作,然后對自己的數(shù)據(jù)副本執(zhí)行這些操作,從而保證從節(jié)點的數(shù)據(jù)與主節(jié)點一致。 那什么是副本集呢?主從模式一主一從就是一個副本。MongoDB復(fù)制提供了數(shù)據(jù)的冗余備份,并在多個服務(wù)器上存儲數(shù)據(jù)副本,提高了數(shù)據(jù)的可用性, 并可以保證數(shù)據(jù)的安全性;復(fù)制還允許您從硬件故障和服務(wù)中斷中恢復(fù)數(shù)據(jù)。副本集具有多個副本保證了容錯性,就算一個副本掛掉了還有很多副本存在,并且解決了之前的問題“主節(jié)點掛掉了,整個集群內(nèi)會自動切換”。 副本集特征: · N 個節(jié)點的集群 · 任何節(jié)點可作為主節(jié)點 · 所有寫入操作都在主節(jié)點上 · 自動故障轉(zhuǎn)移 · 自動恢復(fù) 副本集還有以下幾個需要注意的地方: 1. 最小構(gòu)成是:primary,secondary,arbiter,一般部署是:primary,2 secondary。 2. 成員數(shù)應(yīng)該為奇數(shù),如果為偶數(shù)的情況下添加arbiter,arbiter不保存數(shù)據(jù),只投票。 3. 最大50 members,但是只能有 7 voting members,其他是non-voting members。 借用網(wǎng)上找的兩張架構(gòu)圖說明一下:

由圖可以看到客戶端連接到整個副本集,不關(guān)心具體哪一臺機器是否掛掉。主服務(wù)器負責(zé)整個副本集的讀寫,副本集定期同步數(shù)據(jù)備份,一但主節(jié)點掛掉,副本節(jié)點就會選舉一個新的主服務(wù)器,這一切對于應(yīng)用服務(wù)器不需要關(guān)心。我們看一下主服務(wù)器掛掉后的架構(gòu):
 副本集中的副本節(jié)點在主節(jié)點掛掉后通過心跳機制檢測到后,就會在集群內(nèi)發(fā)起主節(jié)點的選舉機制,自動選舉一位新的主服務(wù)器。更加詳細的副本機制請參考搭建高可用mongodb集群(三)—— 深入副本集內(nèi)部機制 官方推薦的副本集機器數(shù)量至少為3個,我這里就以三個節(jié)點為例介紹。 1. 環(huán)境準(zhǔn)備 192.168.221.161:27017作為主節(jié)點,192.168.221.161:27018,192.168.221.161:27019作為兩個副本節(jié)點 2. 分別創(chuàng)建三個節(jié)點所需要的文件夾 mkdir /data/db{1..3} #存放三個節(jié)點數(shù)據(jù)文件 touch /usr/local/mongodb/mongodb{1..3}.log #存放三個節(jié)點的日志
3. 創(chuàng)建三個節(jié)點的配置文件 [root@MidApp mongodb]# cat mongodb1.conf dbpath=/data/db1 logpath=/usr/local/mongodb/logs/mongodb1.log logappend=true port=27017 fork=true auth=false nohttpinterface=false bind_ip=192.168.221.161 journal=true quiet=true replSet=repset
[root@MidApp mongodb]# cat mongodb2.conf dbpath=/data/db2 logpath=/usr/local/mongodb/logs/mongodb2.log logappend=true port=27018 fork=true auth=false nohttpinterface=false bind_ip=192.168.221.161 journal=true quiet=true replSet=repset
[root@MidApp mongodb]# cat mongodb3.conf dbpath=/data/db3 logpath=/usr/local/mongodb/logs/mongodb3.log logappend=true port=27019 fork=true auth=false nohttpinterface=false bind_ip=192.168.221.161 journal=true quiet=true replSet=repset
4. 分別啟動三個節(jié)點 mongod -f mongodb1.conf mongod -f mongodb2.conf mongod -f mongodb3.conf
查看日志輸出,沒有找到replica的配置信息 2017-11-13T16:34:46.212-0800 I CONTROL [initandlisten] options: { config: "mongodb1.conf", net: { bindIp: "192.168.221.160", http: { enabled: true }, port: 27017 }, processManagement: { fork: true }, replication: { replSet: "repset" }, security: { authorization: "disabled" }, storage: { dbPath: "/data/db1", journal: { enabled: true } }, systemLog: { destination: "file", logAppend: true, path: "/usr/local/mongodb/logs/mongodb1.log", quiet: true } } 2017-11-13T16:34:46.214-0800 I INDEX [initandlisten] allocating new ns file /data/db1/local.ns, filling with zeroes... 2017-11-13T16:34:46.216-0800 I JOURNAL [journal writer] Journal writer thread started 2017-11-13T16:34:46.492-0800 I STORAGE [FileAllocator] allocating new datafile /data/db1/local.0, filling with zeroes... 2017-11-13T16:34:46.492-0800 I STORAGE [FileAllocator] creating directory /data/db1/_tmp 2017-11-13T16:34:46.501-0800 I STORAGE [FileAllocator] done allocating datafile /data/db1/local.0, size: 64MB, took 0.001 secs 2017-11-13T16:34:46.520-0800 I REPL [initandlisten] Did not find local replica set configuration document at startup; NoMatchingDocument Did not find replica set configuration document in local.system.replset
5. 初始化副本集 任選一個節(jié)點登錄進去,可以看到show dbs是不可用,因為還沒初始化副本集 [root@MidApp mongodb]# mongo 192.168.221.161 MongoDB shell version: 3.0.6 connecting to: 192.168.221.161/test Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs./ Questions? Try the support group http://groups.google.com/group/mongodb-user > show dbs 2017-11-13T16:39:33.235-0800 E QUERY Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" } at Error (<anonymous>) at Mongo.getDBs (src/mongo/shell/mongo.js:47:15) at shellHelper.show (src/mongo/shell/utils.js:630:33) at shellHelper (src/mongo/shell/utils.js:524:36) at (shellhelp2):1:1 at src/mongo/shell/mongo.js:47 > use admin switched to db admin
定義副本集配置變量,這里的 _id:”repset” 和上面配置文件的參數(shù)“ –replSet repset” 要保持一樣 >config= {_id:"repset",members:[ {_id:0,host:"192.168.221.161:27017"}, {_id:1,host:"192.168.221.161:27018"}, {_id:2,host:"192.168.221.161:27019"}] }
查看輸出信息: { "_id" : "repset", "members" : [ { "_id" : 0, "host" : "192.168.221.161:27017" }, { "_id" : 1, "host" : "192.168.221.161:27018" }, { "_id" : 2, "host" : "192.168.221.161:27019" } ] }
初始化副本集配置 12 > rs.initiate(config); { "ok" : 1 }
查看集群節(jié)點狀態(tài): repset:OTHER> rs.status() { "set" : "repset", "date" : ISODate("2017-11-14T00:49:25.782Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "192.168.221.161:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 695, "optime" : Timestamp(1510620540, 1), "optimeDate" : ISODate("2017-11-14T00:49:00Z"), "electionTime" : Timestamp(1510620544, 1), "electionDate" : ISODate("2017-11-14T00:49:04Z"), "configVersion" : 1, "self" : true }, { "_id" : 1, "name" : "192.168.221.161:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 25, "optime" : Timestamp(1510620540, 1), "optimeDate" : ISODate("2017-11-14T00:49:00Z"), "lastHeartbeat" : ISODate("2017-11-14T00:49:24.739Z"), "lastHeartbeatRecv" : ISODate("2017-11-14T00:49:24.762Z"), "pingMs" : 0, "configVersion" : 1 }, { "_id" : 2, "name" : "192.168.221.161:27019", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 25, "optime" : Timestamp(1510620540, 1), "optimeDate" : ISODate("2017-11-14T00:49:00Z"), "lastHeartbeat" : ISODate("2017-11-14T00:49:24.739Z"), "lastHeartbeatRecv" : ISODate("2017-11-14T00:49:24.762Z"), "pingMs" : 0, "configVersion" : 1 } ], "ok" : 1 }
整個副本及已經(jīng)搭建成功了! 6. 測試副本集數(shù)據(jù)復(fù)制功能 在主節(jié)點登錄mongodb [root@MidApp mongodb]# mongo 192.168.221.161:27017 MongoDB shell version: 3.0.6 connecting to: 192.168.221.161:27017/test repset:PRIMARY> use test; switched to db test repset:PRIMARY> db.testdb.insert({"test1":"item1"}) WriteResult({ "nInserted" : 1 }) repset:PRIMARY> exit bye
在副本節(jié)點登錄查看數(shù)據(jù): [root@MidApp logs]# mongo 192.168.221.161:27018 MongoDB shell version: 3.0.6 connecting to: 192.168.221.161:27018/test repset:SECONDARY> use test switched to db test repset:SECONDARY> db.getMongo().setSlaveOk();#mongodb默認是從主節(jié)點讀寫數(shù)據(jù)的,副本節(jié)點上不允許讀,需要設(shè)置副本節(jié)點可以讀 repset:SECONDARY> db.testdb.find() { "_id" : ObjectId("5a0a3e8d40637405ab003b39"), "test1" : "item1" }
7. 測試副本集failover功能 手動把現(xiàn)在的主節(jié)點停掉,查看集群狀態(tài): repset:SECONDARY> rs.status() { "set" : "repset", "date" : ISODate("2017-11-14T00:57:14.753Z"), "myState" : 2, "members" : [ { "_id" : 0, "name" : "192.168.221.161:27017", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : Timestamp(0, 0), "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2017-11-14T00:57:13.304Z"), "lastHeartbeatRecv" : ISODate("2017-11-14T00:57:09.285Z"), "pingMs" : 0, "lastHeartbeatMessage" : "Failed attempt to connect to 192.168.221.161:27017; couldn't connect to server 192.168.221.161:27017 (192.168.221.161), connection attempt failed", "configVersion" : -1 }, { "_id" : 1, "name" : "192.168.221.161:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 1167, "optime" : Timestamp(1510620813, 2), "optimeDate" : ISODate("2017-11-14T00:53:33Z"), "infoMessage" : "could not find member to sync from", "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "192.168.221.161:27019", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 17, "optime" : Timestamp(1510620813, 2), "optimeDate" : ISODate("2017-11-14T00:53:33Z"), "lastHeartbeat" : ISODate("2017-11-14T00:57:13.317Z"), "lastHeartbeatRecv" : ISODate("2017-11-14T00:57:13.330Z"), "pingMs" : 0, "electionTime" : Timestamp(1510621032, 1), "electionDate" : ISODate("2017-11-14T00:57:12Z"), "configVersion" : 1 } ], "ok" : 1 }
可以看到原來的主節(jié)點狀態(tài)現(xiàn)在已經(jīng)變成了不可達,192.168.221.161:27019已經(jīng)變成新的主節(jié)點 8. 再次啟動原來的主節(jié)點,發(fā)現(xiàn)192.168.221.161:27017還是SECONDARY repset:SECONDARY> rs.status() { "set" : "repset", "date" : ISODate("2017-11-14T17:02:13.837Z"), "myState" : 2, "members" : [ { "_id" : 0, "name" : "192.168.221.161:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 5, "optime" : Timestamp(1510620813, 2), "optimeDate" : ISODate("2017-11-14T00:53:33Z"), "lastHeartbeat" : ISODate("2017-11-14T17:02:12.642Z"), "lastHeartbeatRecv" : ISODate("2017-11-14T17:02:11.902Z"), "pingMs" : 0, "configVersion" : 1 }, { "_id" : 1, "name" : "192.168.221.161:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 59066, "optime" : Timestamp(1510620813, 2), "optimeDate" : ISODate("2017-11-14T00:53:33Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "192.168.221.161:27019", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 57916, "optime" : Timestamp(1510620813, 2), "optimeDate" : ISODate("2017-11-14T00:53:33Z"), "lastHeartbeat" : ISODate("2017-11-14T17:02:12.308Z"), "lastHeartbeatRecv" : ISODate("2017-11-14T17:02:12.080Z"), "pingMs" : 0, "electionTime" : Timestamp(1510621032, 1), "electionDate" : ISODate("2017-11-14T00:57:12Z"), "configVersion" : 1 } ], "ok" : 1 }
現(xiàn)在,mongodb的副本集群已經(jīng)完成了。 接下來是關(guān)于mongodb的讀寫分離和分片的內(nèi)容
|