1. 程式人生 > >MongoDB復制集架構

MongoDB復制集架構

mongodb復制集架構配置

MongoDB復制集架構

由數據結點,投票結點組成,需要配置集群信息,可自動檢測集群中的結點健康狀態,當有結點出故障時,自動下線和切換主從結點。適用於數據量較大,高可用服務

通常,為了防止單點故障應用程序需要做集群。然而在數據庫中除了防止單點故障,還需要做到數據庫備份,讀寫分離,故障轉移等。而 MongoDB 的 Replica Set 恰恰都能滿足這些要求。


Replica Set角色

Replica Set 的成員是一堆有著同樣的數據內容 mongod 的實例集合,包含以下三類角色:

  1. 主節點(Primary)
    是 Replica Set 中唯一的接收寫請求的節點,並將寫入指令記錄到 oplog 上。副本節點通過復制 oplog 的寫入指令同步主節點的數據。Secondary。一個 Replica Set 有且只有Primary 節點,當Primar掛掉後,其他 Secondary 或者 Arbiter 節點會重新選舉出來一個主節點。應用程序的默認讀取請求也是發到 Primary節點處理的。

  2. 副本節點(Secondary)
    通過復制主節點 oplog 中的指令與主節點保持同樣的數據集,當主節點掛掉的時候,參與主節點選舉。

  3. 仲裁者(Arbiter)
    不存儲實際應用數據,只投票參與選取主節點,但不會被選舉成為主節點。


技術分享圖片


復制集架構配置

架構:

Arbite:127.0.0.1:27017

primary:127.0.0.1:27018

secondary: 127.0.0.1:27019


配置文件內容如下,只要修改logpath、dbpath、pidfilepath和端口即可

arbiter.conf

# syslog配置
logpath=/var/log/mongo/logs/mongod1.log
logappend=true
timeStampFormat=iso8601-utc
# storage 存儲配置
dbpath=/data/mongo/repldb1
directoryperdb=true
# processManagement 進程管理配置
fork=true
# 進程 PID 文件保存目錄
pidfilepath=/var/run/mongod1.pid
# net 網絡配置
bind_ip=127.0.0.1
port=27017 
# security 配置
#auth=true
# 復制集
replSet=test-set


primary.conf

# syslog配置
logpath=/var/log/mongo/logs/mongod2.log
logappend=true
timeStampFormat=iso8601-utc
# storage 存儲配置
dbpath=/data/mongo/repldb2
directoryperdb=true
# processManagement 進程管理配置
fork=true
# 進程 PID 文件保存目錄
pidfilepath=/var/run/mongod2.pid
# net 網絡配置
bind_ip=127.0.0.1
port=27018
# security 配置
#auth=true
# 復制集
replSet=test-set


secondary.conf

# syslog配置
logpath=/var/log/mongo/logs/mongod3.log
logappend=true
timeStampFormat=iso8601-utc
# storage 存儲配置
dbpath=/data/mongo/repldb3
directoryperdb=true
# processManagement 進程管理配置
fork=true
# 進程 PID 文件保存目錄
pidfilepath=/var/run/mongod3.pid
# net 網絡配置
bind_ip=127.0.0.1
port=27019
# security 配置
#auth=true
# 復制集
replSet=test-set


分別啟動這三個實例

mongod --config arbiter.conf 
mongod --config primary.conf 
mongod --config secondary.conf


初始化:

使用mongodb客戶端登陸兩個常規節點(primary和secondary)中的任何一個,執行如下命令

mongod 127.0.0.1:27018

登陸後執行初始化命令

> rs.initiate(
... {"_id":"test-set",
... "members":[
... {"_id":1,"host":"127.0.0.1:27018"},
... {"_id":2,"host":"127.0.0.1:27019"}
... ]
... });
{ "ok" : 1 }
test-set:SECONDARY> rs.addArb("127.0.0.1:27017")
{ "ok" : 1 }


查看集群狀態:

test-set:PRIMARY> rs.status()
{
        "set" : "test-set",
        "date" : ISODate("2018-04-19T07:22:22.813Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1524122535, 1),
                        "t" : NumberLong(1)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1524122535, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1524122535, 1),
                        "t" : NumberLong(1)
                }
        },
        "members" : [
                {
                        "_id" : 1,
                        "name" : "127.0.0.1:27018",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 1303,
                        "optime" : {
                                "ts" : Timestamp(1524122535, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2018-04-19T07:22:15Z"),
                        "electionTime" : Timestamp(1524121903, 1),
                        "electionDate" : ISODate("2018-04-19T07:11:43Z"),
                        "configVersion" : 2,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "127.0.0.1:27019",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 649,
                        "optime" : {
                                "ts" : Timestamp(1524122535, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1524122535, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2018-04-19T07:22:15Z"),
                        "optimeDurableDate" : ISODate("2018-04-19T07:22:15Z"),
                        "lastHeartbeat" : ISODate("2018-04-19T07:22:21.472Z"),
                        "lastHeartbeatRecv" : ISODate("2018-04-19T07:22:21.472Z"),
                        "pingMs" : NumberLong(0),
                        "syncingTo" : "127.0.0.1:27018",
                        "configVersion" : 2
                },
                {
                        "_id" : 3,
                        "name" : "127.0.0.1:27017",
                        "health" : 1,
                        "state" : 7,
                        "stateStr" : "ARBITER",
                        "uptime" : 69,
                        "lastHeartbeat" : ISODate("2018-04-19T07:22:21.471Z"),
                        "lastHeartbeatRecv" : ISODate("2018-04-19T07:22:18.484Z"),
                        "pingMs" : NumberLong(0),
                        "configVersion" : 2
                }
        ],
        "ok" : 1
}


登錄127.0.0.1:27019 角色顯示為Secondary

mongo 127.0.0.1:27019
2018-04-19T07:00:44.075Z I CONTROL  [initandlisten] 
test-set:SECONDARY> 
test-set:SECONDARY> 
test-set:SECONDARY>


在primary上創建數據,測試secondary上是否會同步

test-set:PRIMARY> show dbs
admin  0.000GB
local  0.000GB
test-set:PRIMARY> use testdb
switched to db testdb
test-set:PRIMARY> show collections
test-set:PRIMARY> db.test.insert({"name":"user1"});
WriteResult({ "nInserted" : 1 })


登錄secondary,查看

test-set:SECONDARY> rs.slaveOk()
test-set:SECONDARY> show dbs
admin   0.000GB
local   0.000GB
testdb  0.000GB
test-set:SECONDARY> use testdb
switched to db testdb
test-set:SECONDARY> show collections
test
test-set:SECONDARY> db.test.find()
{ "_id" : ObjectId("5ad844efa46a748c5a90fe41"), "name" : "user1" }


secondary上插入數據報錯,說明secondary上沒有寫的權限

test-set:SECONDARY>  db.test.insert({"name":"user2"});
WriteResult({ "writeError" : { "code" : 10107, "errmsg" : "not master" } })


驗證復制集架構容災功能

kill掉primary的進程,登錄127.0.0.1:27019

test-set:PRIMARY> show dbs
admin   0.000GB
local   0.000GB
testdb  0.000GB
test-set:PRIMARY> rs.status()
{
        "set" : "test-set",
        "date" : ISODate("2018-04-19T07:44:28.912Z"),
        "myState" : 1,
        "term" : NumberLong(2),
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1524123775, 1),
                        "t" : NumberLong(1)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1524123862, 1),
                        "t" : NumberLong(2)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1524123862, 1),
                        "t" : NumberLong(2)
                }
        },
        "members" : [
                {
                        "_id" : 1,
                        "name" : "127.0.0.1:27018",
                        "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-04-19T07:44:27.023Z"),
                        "lastHeartbeatRecv" : ISODate("2018-04-19T07:42:59.830Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "Connection refused",
                        "configVersion" : -1
                },
                {
                        "_id" : 2,
                        "name" : "127.0.0.1:27019",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 2625,
                        "optime" : {
                                "ts" : Timestamp(1524123862, 1),
                                "t" : NumberLong(2)
                        },
                        "optimeDate" : ISODate("2018-04-19T07:44:22Z"),
                        "infoMessage" : "could not find member to sync from",
                        "electionTime" : Timestamp(1524123790, 1),
                        "electionDate" : ISODate("2018-04-19T07:43:10Z"),
                        "configVersion" : 2,
                        "self" : true
                },
                {
                        "_id" : 3,
                        "name" : "127.0.0.1:27017",
                        "health" : 1,
                        "state" : 7,
                        "stateStr" : "ARBITER",
                        "uptime" : 1395,
                        "lastHeartbeat" : ISODate("2018-04-19T07:44:27.009Z"),
                        "lastHeartbeatRecv" : ISODate("2018-04-19T07:44:28.662Z"),
                        "pingMs" : NumberLong(0),
                        "configVersion" : 2
                }
        ],
        "ok" : 1
}


可以看到127.0.0.1:27018 有一個 "stateStr" : "(not reachable/healthy)"的報錯,而127.0.0.1:27019已經變成了primary角色

技術分享圖片


啟動原來的primary.conf配置的實例,角色由原來的primary變成了secondary

test-set:SECONDARY> show dbs
2018-04-19T15:50:04.113+0800 E QUERY    [thread1] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not master and slaveOk=false",
        "code" : 13435,
        "codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:782:19
shellHelper@src/mongo/shell/utils.js:672:15
@(shellhelp2):1:1
test-set:SECONDARY>


其他命令:

rs.slaveOk():secondary默認不允許讀寫,執行此命令後,從節點有可讀權限


rs.conf():查看配置情況

test-set:SECONDARY> rs.conf()
{
        "_id" : "test-set",
        "version" : 2,
        "protocolVersion" : NumberLong(1),
        "members" : [
                {
                        "_id" : 1,
                        "host" : "127.0.0.1:27018",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "127.0.0.1:27019",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 3,
                        "host" : "127.0.0.1:27017",
                        "arbiterOnly" : true,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {
                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
        ],
        "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : 60000,
                "getLastErrorModes" : {
                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("5ad841247ffb05dbb6b4a13b")
        }
}





MongoDB復制集架構