MongoDB 主從復制及 自動故障轉移


1、MongoDB 主從復制

MongoDB復制是將數據同步在多個服務器的過程。

復制提供了數據的冗余備份,並在多個服務器上存儲數據副本,提高了數據的可用性, 並可以保證數據的安全性。

復制還允許您從硬件故障和服務中斷中恢復數據。

官方文檔 https://docs.mongodb.com/manual/replication/

1.1 什么是復制?

保障數據的安全性 數據高可用性 (24*7) 災難恢復 無需停機維護(如備份,重建索引,壓縮) 分布式讀取數據

1.2 MongoDB復制原理

mongodb的復制至少需要兩個節點。其中一個是主節點,負責處理客戶端請求,其余的都是從節點,負責復制主節點上的數據。

mongodb各個節點常見的搭配方式為:一主一從、一主多從。

主節點記錄在其上的所有操作oplog,從節點定期輪詢主節點獲取這些操作,然后對自己的數據副本執行這些操作,從而保證從節點的數據與主節點一致。

MongoDB復制結構圖如下所示:

以上結構圖中,客戶端從主節點讀取數據,在客戶端寫入數據到主節點時, 主節點與從節點進行數據交互保障數據的一致性。

1.3 副本集特征

N 個節點的集群 任何節點可作為主節點 所有寫入操作都在主節點上 自動故障轉移 自動恢復

1.4 MongoDB副本集設置

1、關閉正在運行的MongoDB服務器。

service mongod stop 

2.節點建點

首先需要去你選擇的mongodb數據文件存放的文件夾新建三個數據庫,用來模擬三台不通的機器,博主的路徑如下

mkdir -p /data/db/node1 mkdir -p /data/db/node2 mkdir -p /data/db/node3 

3.啟動三個數據庫(dbpath),並且端口(--port 1000x),集群名稱(--replSet gabriel),關閉日志選項(--nojournal),守護進程方式啟動,會自動拉起(--fork),日志目錄(--logpath)

mongod --dbpath /data/db/node1 --port 10001 --replSet gabriel --nojournal --fork --logpath /data/db/node1.log mongod --dbpath /data/db/node2 --port 10002 --replSet gabriel --nojournal --fork --logpath /data/db/node2.log mongod --dbpath /data/db/node3 --port 10003 --replSet gabriel --nojournal --fork --logpath /data/db/node3.log 

4.順便連接一個服務器,做初始化操作,這里博主連入10001端口

終端下進入

mongo localhost:10001 

進入后輸入初始化方法

MongoDB Enterprise gabriel:OTHER> rs.initiate({_id:"gabriel",members:[ {_id:1,host:"localhost:10001"}, {_id:2,host:"localhost:10002"}, {_id:3,host:"localhost:10003"}, ]}) 

收到如下信息就成功了。

{
	"ok" : 1, "operationTime" : Timestamp(1517221411, 1), "$clusterTime" : { "clusterTime" : Timestamp(1517221411, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } MongoDB Enterprise gabriel:OTHER> 

此時會發現終端上的輸出已經有了變化。

//從單個一個 > //變成了 gabriel:OTHER> 

5.查詢狀態

MongoDB Enterprise gabriel:OTHER> rs.status() { "set" : "gabriel", "date" : ISODate("2018-01-29T10:33:21.227Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1517221984, 1), "t" : NumberLong(1) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1517221984, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1517221994, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1517221994, 1), "t" : NumberLong(1) } }, "members" : [ { "_id" : 1, "name" : "localhost:10001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 659, "optime" : { "ts" : Timestamp(1517221994, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-01-29T10:33:14Z"), "electionTime" : Timestamp(1517221422, 1), "electionDate" : ISODate("2018-01-29T10:23:42Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "localhost:10002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 589, "optime" : { "ts" : Timestamp(1517221994, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1517221984, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-01-29T10:33:14Z"), "optimeDurableDate" : ISODate("2018-01-29T10:33:04Z"), "lastHeartbeat" : ISODate("2018-01-29T10:33:20.972Z"), "lastHeartbeatRecv" : ISODate("2018-01-29T10:33:19.923Z"), "pingMs" : NumberLong(0), "syncingTo" : "localhost:10001", "configVersion" : 1 }, { "_id" : 3, "name" : "localhost:10003", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 589, "optime" : { "ts" : Timestamp(1517221994, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1517221984, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-01-29T10:33:14Z"), "optimeDurableDate" : ISODate("2018-01-29T10:33:04Z"), "lastHeartbeat" : ISODate("2018-01-29T10:33:20.972Z"), "lastHeartbeatRecv" : ISODate("2018-01-29T10:33:19.921Z"), "pingMs" : NumberLong(0), "syncingTo" : "localhost:10001", "configVersion" : 1 } ], "ok" : 1, "operationTime" : Timestamp(1517221994, 1), "$clusterTime" : { "clusterTime" : Timestamp(1517221994, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } 

在返回中,參數set后面為集群名稱,每個members下面可以看到他們各自的情況,其中stateStr是角色,主節點為(PRIMARY)。

6.進入主節點插入數據,進入從節點查看數據

博主主節點在10001接口

mongo localhost:10001 

插入數據

MongoDB Enterprise gabriel:PRIMARY> use test switched to db test db.col.insert({title: 'MongoDB 教程', description: 'MongoDB 是一個 Nosql 數據庫', by: '小羅技術筆記-專注於開發技術的研究與知識分享', url: 'http://www.yuwowugua.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 }) MongoDB Enterprise gabriel:PRIMARY> db.col.find() { "_id" : ObjectId("5a6ef998525d903d07a00cdf"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 數據庫", "by" : "小羅技術筆記-專注於開發技術的研究與知識分享", "url" : "http://www.yuwowugua.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 } MongoDB Enterprise gabriel:PRIMARY> 

博主切換從節點10002

mongo localhost:10002 

切換到從節點,你會發現使用show dbs 會報錯,是因為還沒有開啟權限,輸入rs.slaveOk();就可以順利訪問了。

MongoDB Enterprise gabriel:SECONDARY> show dbs
2018-01-29T10:40:37.362+0000 E QUERY [thread1] Error: listDatabases failed:{ "operationTime" : Timestamp(1517222434, 1), "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk", "$clusterTime" : { "clusterTime" : Timestamp(1517222434, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:65:1 shellHelper.show@src/mongo/shell/utils.js:813:19 shellHelper@src/mongo/shell/utils.js:703:15 @(shellhelp2):1:1 MongoDB Enterprise gabriel:SECONDARY> MongoDB Enterprise gabriel:SECONDARY> rs.slaveOk() 

再次查看

MongoDB Enterprise gabriel:SECONDARY> show dbs admin 0.000GB config 0.000GB local 0.000GB test 0.000GB MongoDB Enterprise gabriel:SECONDARY> 

切到test 庫,查看數據已經同步過來了

MongoDB Enterprise gabriel:SECONDARY> use test switched to db test MongoDB Enterprise gabriel:SECONDARY> db.col.find() { "_id" : ObjectId("5a6ef998525d903d07a00cdf"), "title" : "MongoDB 教程", "description" : "MongoDB 是一個 Nosql 數據庫", "by" : "小羅技術筆記-專注於開發技術的研究與知識分享", "url" : "http://www.yowowugua.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 } MongoDB Enterprise gabriel:SECONDARY> 

以上就是簡單的主從復制建立過程,現在已經可以在從服務器看到主服務器插入的數據了。

切換從節點10003 一樣的問題

刪除從節點

rs.remove('ip:port') 

關閉主服務器后,再重新啟動,會發現原來的從服務器變為了從服務器,新啟動的服務器(原來的從服務器)變為了從服務器

2、 MongoDB 自動故障轉移

首先通過 rs.status() 查看,可以看到主節點是10001,主節點"name" :

"localhost:10001", "stateStr" : "PRIMARY" 接下來停止 10001 主節點,測試故障切換

MongoDB Enterprise gabriel:PRIMARY>  rs.status() { "set" : "gabriel", "date" : ISODate("2018-01-30T02:39:58.468Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1517279986, 1), "t" : NumberLong(1) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1517279986, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1517279996, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1517279996, 1), "t" : NumberLong(1) } }, "members" : [ { "_id" : 1, "name" : "localhost:10001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 58656, "optime" : { "ts" : Timestamp(1517279996, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-01-30T02:39:56Z"), "electionTime" : Timestamp(1517221422, 1), "electionDate" : ISODate("2018-01-29T10:23:42Z"), "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "localhost:10002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 58586, "optime" : { "ts" : Timestamp(1517279996, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1517279986, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-01-30T02:39:56Z"), "optimeDurableDate" : ISODate("2018-01-30T02:39:46Z"), "lastHeartbeat" : ISODate("2018-01-30T02:39:58.289Z"), "lastHeartbeatRecv" : ISODate("2018-01-30T02:39:57.220Z"), "pingMs" : NumberLong(0), "syncingTo" : "localhost:10001", "configVersion" : 1 }, { "_id" : 3, "name" : "localhost:10003", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDurable" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2018-01-30T02:39:58.304Z"), "lastHeartbeatRecv" : ISODate("2018-01-30T02:39:21.208Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Connection refused", "configVersion" : -1 } ], "ok" : 1, "operationTime" : Timestamp(1517279996, 1), "$clusterTime" : { "clusterTime" : Timestamp(1517279996, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } MongoDB Enterprise gabriel:PRIMARY> 

連接到主節點

mongo localhost:10001 

顯示所有數據庫

MongoDB Enterprise gabriel:PRIMARY> show dbs admin 0.000GB config 0.000GB local 0.000GB test 0.000GB 

切換到admin

MongoDB Enterprise gabriel:PRIMARY> use admin switched to db admin 

停止數據庫,必須進入 admin 庫

MongoDB Enterprise gabriel:PRIMARY> db.shutdownServer() 

響應

2018-01-30T02:51:34.503+0000 I NETWORK [thread1] trying reconnect to localhost:10001 (127.0.0.1) failed 2018-01-30T02:51:35.398+0000 I NETWORK [thread1] Socket recv() Connection reset by peer 127.0.0.1:10001 2018-01-30T02:51:35.398+0000 I NETWORK [thread1] SocketException: remote: (NONE):0 error: SocketException socket exception [RECV_ERROR] server [127.0.0.1:10001] 2018-01-30T02:51:35.399+0000 I NETWORK [thread1] reconnect localhost:10001 (127.0.0.1) failed failed 2018-01-30T02:51:35.404+0000 I NETWORK [thread1] trying reconnect to localhost:10001 (127.0.0.1) failed 2018-01-30T02:51:35.404+0000 W NETWORK [thread1] Failed to connect to 127.0.0.1:10001, in(checking socket for error after poll), reason: Connection refused 2018-01-30T02:51:35.404+0000 I NETWORK [thread1] reconnect localhost:10001 (127.0.0.1) failed failed MongoDB Enterprise > 

查看是否真的停止了,發現已經沒有10001 節點進程了

root@admin-2:# ps -ef | grep mongo root 5554 1 0 Jan29 ? 00:03:34 mongod --dbpath /data/db/node2 --port 10002 --replSet gabriel --nojournal --fork --logpath /data/db/node2.log root 12284 1 0 02:43 ? 00:00:02 mongod --dbpath /data/db/node3 --port 10003 --replSet gabriel --nojournal --fork --logpath /data/db/node3.log root 12436 5132 0 02:53 pts/1 00:00:00 grep --color=auto mongo root@admin-2:# netstat -nltp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:10002 0.0.0.0:* LISTEN 5554/mongod tcp 0 0 127.0.0.1:10003 0.0.0.0:* LISTEN 12284/mongod root@admin-2:/data/db# 

查看是否故障專業

root@admin-2:# mongo localhost:10001 

查看主從狀態

MongoDB Enterprise gabriel:SECONDARY> rs.status() { "set" : "gabriel", "date" : ISODate("2018-01-30T02:56:48.074Z"), "myState" : 2, "term" : NumberLong(2), "syncingTo" : "localhost:10003", "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1517280995, 1), "t" : NumberLong(2) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1517280995, 1), "t" : NumberLong(2) }, "appliedOpTime" : { "ts" : Timestamp(1517281005, 1), "t" : NumberLong(2) }, "durableOpTime" : { "ts" : Timestamp(1517280995, 1), "t" : NumberLong(2) } }, "members" : [ { "_id" : 1, "name" : "localhost:10001", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDurable" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2018-01-30T02:56:47.605Z"), "lastHeartbeatRecv" : ISODate("2018-01-30T02:51:34.519Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Connection refused", "configVersion" : -1 }, { "_id" : 2, "name" : "localhost:10002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 59660, "optime" : { "ts" : Timestamp(1517281005, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-01-30T02:56:45Z"), "syncingTo" : "localhost:10003", "configVersion" : 1, "self" : true }, { "_id" : 3, "name" : "localhost:10003", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 784, "optime" : { "ts" : Timestamp(1517281005, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1517281005, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-01-30T02:56:45Z"), "optimeDurableDate" : ISODate("2018-01-30T02:56:45Z"), "lastHeartbeat" : ISODate("2018-01-30T02:56:46.486Z"), "lastHeartbeatRecv" : ISODate("2018-01-30T02:56:47.147Z"), "pingMs" : NumberLong(0), "electionTime" : Timestamp(1517280703, 1), "electionDate" : ISODate("2018-01-30T02:51:43Z"), "configVersion" : 1 } ], "ok" : 1, "operationTime" : Timestamp(1517281005, 1), "$clusterTime" : { "clusterTime" : Timestamp(1517281005, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } MongoDB Enterprise gabriel:SECONDARY> 

發現 “name” : “localhost:10001”,”stateStr” : “(not reachable/healthy)”, 健康狀態已經是“無法訪問狀態了”

主節點已經切換成 10003 節點了

"_id" : 3, "name" : "localhost:10003", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", 

重啟節點10001

mongod --dbpath /data/db/node1 --port 10001 --replSet gabriel --nojournal --fork --logpath /data/db/node1.log
來源:黑帽seo技術可能會殺死SEO活動


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM