MongoDB复制集概述
什么是复制集
复制集(Replica Sets)是额外的数据副本, 是跨多个服务器同步数据的过程, 复制集提供了冗余并增加了数据可用性, 通过复制集可以对硬件故障和中断的服务进行恢复.
复制集的优势如下:
1.让数据更安全
2.高数据可用性(24*7)
3.灾难恢复
4.无停机维护(如备份、索引重建、故障转移)
5.读缩放(额外的副本读取)
6.副本集对应用程序是透明的
复制集工作原理
MongoDB的复制集至少需要两个节点. 其中一个是主节点(Primary), 负责处理客户端的请求, 其余的都是从节点(Secondary), 负责复制主节点上的数据.
复制集特点:
1.N个节点的群集
2.任何节点可作为主节点
3.所有写入操作都在主节点上
4.自动故障转移
5.自动恢复
复制集的选举原理
MongoDB复制集的节点是通过选举产生主节点
复制原理
复制是基于操作日志oplog, 相当于MySQL中的二进制日志, 只记录发生改变的记录. 复制是将主节点的oplog日志同步并应用到其他从节点的过程.
选举原理
节点类型分为标准(host)节点、被动(passive)节点和仲裁(arbiter)节点.
(1)只有标准节点可能被选举为活跃(primary)节点, 有选举权. 被动节点有完整副本, 不可能成为活跃节点, 有选举权. 仲裁节点不复制数据, 不可能成为活跃跃点只有选举权.
(2)标准节点与被动节点的区别: priority值高者是标准节点, 低者则为被动节点.
(3)选举规则是票数高者获胜, priority是优先权为0~1000的值, 相当于额外增加0~1000的票数.
选举结果:票数高者获胜; 若票数相同, 数据新者获胜.
MongoDB复制集部属
配置复制集
安装MongoDB后配置多实例
(1).将mongoDB原本的数据清空
1 | rm -rf /var/lib/mongo/* |
(2).创建数据文件和日志文件存储路径
1 | mkdir -p /var/lib/mongo{2,3,4} |
注: 日志文件可以自动生成
(4).编译4个MongoDB实例的配置文件
1 | # -------27017------- |
注: bindIp更改为本机上的网卡IP地址
(5).启动mongoDB服务
1 | mongod -f /etc/mongod.conf |
(6).初始化配置复制集
1 | mongo --host 192.168.100.10:27017 |
当前未配置复制集时的错误提示: 2020-08-28T15:29:12.858+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:814:19 shellHelper@src/mongo/shell/utils.js:704:15 @(shellhelp2):1:1 复制集状态: { "info" : "run rs.initiate(...) if not yet done for the set", "ok" : 0, "errmsg" : "no replset config has been received", "code" : 94, "codeName" : "NotYetInitialized" }
初始化后的复制集状态
{
“set” : “test_rs”,
“date” : ISODate(“2020-08-28T07:44:08.660Z”),
“myState” : 1,
“term” : NumberLong(1),
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“heartbeatIntervalMillis” : NumberLong(2000),
“optimes” : {
“lastCommittedOpTime” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“appliedOpTime” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“durableOpTime” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
}
},
“members” : [
{
“_id” : 0,
“name” : “192.168.100.10:27017”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”, # 主节点
“uptime” : 1047,
“optime” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2020-08-28T07:44:05Z”),
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“infoMessage” : “”,
“electionTime” : Timestamp(1598600384, 1),
“electionDate” : ISODate(“2020-08-28T07:39:44Z”),
“configVersion” : 1,
“self” : true,
“lastHeartbeatMessage” : “”
},
{
“_id” : 1,
“name” : “192.168.100.10:27018”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”, # 从节点
“uptime” : 275,
“optime” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“optimeDurable” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2020-08-28T07:44:05Z”),
“optimeDurableDate” : ISODate(“2020-08-28T07:44:05Z”),
“lastHeartbeat” : ISODate(“2020-08-28T07:44:08.245Z”),
“lastHeartbeatRecv” : ISODate(“2020-08-28T07:44:08.471Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “”,
“syncingTo” : “192.168.100.10:27019”,
“syncSourceHost” : “192.168.100.10:27019”,
“syncSourceId” : 2,
“infoMessage” : “”,
“configVersion” : 1
},
{
“_id” : 2,
“name” : “192.168.100.10:27019”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”, # 从节点
“uptime” : 275,
“optime” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“optimeDurable” : {
“ts” : Timestamp(1598600645, 1),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2020-08-28T07:44:05Z”),
“optimeDurableDate” : ISODate(“2020-08-28T07:44:05Z”),
“lastHeartbeat” : ISODate(“2020-08-28T07:44:08.245Z”),
“lastHeartbeatRecv” : ISODate(“2020-08-28T07:44:08.450Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “”,
“syncingTo” : “192.168.100.10:27017”,
“syncSourceHost” : “192.168.100.10:27017”,
“syncSourceId” : 0,
“infoMessage” : “”,
“configVersion” : 1
},
{
“_id” : 3,
“name” : “192.168.100.10:27020”,
“health” : 1,
“state” : 7,
“stateStr” : “ARBITER”, # 仲裁节点
“uptime” : 275,
“lastHeartbeat” : ISODate(“2020-08-28T07:44:08.245Z”),
“lastHeartbeatRecv” : ISODate(“2020-08-28T07:44:05.120Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “”,
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“infoMessage” : “”,
“configVersion” : 1
}
],
“ok” : 1
}
增加和删除节点
1 | rs.add("ip地址:端口号") |
MongoDB复制集切换
模拟故障自动转移
1 | # 关闭第一个实例 |
切换后的复制集状态
{
“set” : “test_rs”,
“date” : ISODate(“2020-08-28T08:32:33.539Z”),
“myState” : 1,
“term” : NumberLong(2),
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“heartbeatIntervalMillis” : NumberLong(2000),
“optimes” : {
“lastCommittedOpTime” : {
“ts” : Timestamp(1598603535, 1),
“t” : NumberLong(1)
},
“appliedOpTime” : {
“ts” : Timestamp(1598603548, 1),
“t” : NumberLong(2)
},
“durableOpTime” : {
“ts” : Timestamp(1598603548, 1),
“t” : NumberLong(2)
}
},
“members” : [
{
“_id” : 0,
“name” : “192.168.100.10:27017”,
“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(“2020-08-28T08:32:32.982Z”),
“lastHeartbeatRecv” : ISODate(“2020-08-28T08:32:14.597Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “Connection refused”,
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“infoMessage” : “”,
“configVersion” : -1
},
{
“_id” : 1,
“name” : “192.168.100.10:27018”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 3952,
“optime” : {
“ts” : Timestamp(1598603548, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2020-08-28T08:32:28Z”),
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“infoMessage” : “could not find member to sync from”,
“electionTime” : Timestamp(1598603546, 1),
“electionDate” : ISODate(“2020-08-28T08:32:26Z”),
“configVersion” : 1,
“self” : true,
“lastHeartbeatMessage” : “”
},
……
],
“ok” : 1
}
手动进行主从切换
1 | # 开启第一个实例 |
切换前的复制集状态
{
“_id” : 0,
“name” : “192.168.100.10:27017”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 663,
“optime” : {
“ts” : Timestamp(1598865163, 1),
“t” : NumberLong(2)
},
“optimeDurable” : {
“ts” : Timestamp(1598865163, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2020-08-31T09:12:43Z”),
“optimeDurableDate” : ISODate(“2020-08-31T09:12:43Z”),
“lastHeartbeat” : ISODate(“2020-08-31T09:12:45.437Z”),
“lastHeartbeatRecv” : ISODate(“2020-08-31T09:12:47.729Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “”,
“syncingTo” : “192.168.100.10:27019”,
“syncSourceHost” : “192.168.100.10:27019”,
“syncSourceId” : 2,
“infoMessage” : “”,
“configVersion” : 1
},
{
“_id” : 1,
“name” : “192.168.100.10:27018”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 1318,
“optime” : {
“ts” : Timestamp(1598865163, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2020-08-31T09:12:43Z”),
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“infoMessage” : “could not find member to sync from”,
“configVersion” : 1,
“self” : true,
“lastHeartbeatMessage” : “”
},
……
切换后的复制集状态
{
“_id” : 0,
“name” : “192.168.100.10:27017”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 710,
“optime” : {
“ts” : Timestamp(1598865205, 1),
“t” : NumberLong(3)
},
“optimeDurable” : {
“ts” : Timestamp(1598865205, 1),
“t” : NumberLong(3)
},
“optimeDate” : ISODate(“2020-08-31T09:13:25Z”),
“optimeDurableDate” : ISODate(“2020-08-31T09:13:25Z”),
“lastHeartbeat” : ISODate(“2020-08-31T09:13:34.476Z”),
“lastHeartbeatRecv” : ISODate(“2020-08-31T09:13:34.450Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “”,
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“infoMessage” : “”,
“electionTime” : Timestamp(1598865174, 1),
“electionDate” : ISODate(“2020-08-31T09:12:54Z”),
“configVersion” : 1
},
{
“_id” : 1,
“name” : “192.168.100.10:27018”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 1366,
“optime” : {
“ts” : Timestamp(1598865205, 1),
“t” : NumberLong(3)
},
“optimeDate” : ISODate(“2020-08-31T09:13:25Z”),
“syncingTo” : “192.168.100.10:27017”,
“syncSourceHost” : “192.168.100.10:27017”,
“syncSourceId” : 0,
“infoMessage” : “”,
“configVersion” : 1,
“self” : true,
“lastHeartbeatMessage” : “”
},
……
验证复制集的选举原理
1.查看oplog日志
1 | # 登录主节点 |
2.配置复制集的优先级
1 | // 查看所有节点的状态 |
config={"_id":"test_rs","members":[ {"_id":0,"host":"192.168.100.10:27017","priority":100}, {"_id":1,"host":"192.168.100.10:27018","priority":100}, {"_id":2,"host":"192.168.100.10:27019","priority":0}, {"_id":3,"host":"192.168.100.10:27020","arbiterOnly":true}]}
所有节点的状态
{
“hosts” : [
“192.168.100.10:27017”,
“192.168.100.10:27018”
],
“passives” : [
“192.168.100.10:27019”
],
“arbiters” : [
“192.168.100.10:27020”
],
“setName” : “test_rs”,
“setVersion” : 1,
“ismaster” : true,
“secondary” : false,
“primary” : “192.168.100.10:27017”,
“me” : “192.168.100.10:27017”,
“electionId” : ObjectId(“7fffffff0000000000000003”),
“lastWrite” : {
“opTime” : {
“ts” : Timestamp(1598877986, 1),
“t” : NumberLong(3)
},
“lastWriteDate” : ISODate(“2020-08-31T12:46:26Z”)
},
“maxBsonObjectSize” : 16777216,
“maxMessageSizeBytes” : 48000000,
“maxWriteBatchSize” : 1000,
“localTime” : ISODate(“2020-08-31T12:46:26.933Z”),
“maxWireVersion” : 5,
“minWireVersion” : 0,
“readOnly” : false,
“ok” : 1
}
MongoDB复制集管理
配置允许在从节点读取数据
默认MongoDB复制集的从节点不能读取数据, 可以使用rs.slaveOk()命令允许能够在从节点读取数据. 连接到复制集的其中一个从节点, 配置其允许读取数据.
1 | # 登录从节点 |
# 允许在从节点读取数据前 2020-08-31T21:41:36.272+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:814:19 shellHelper@src/mongo/shell/utils.js:704:15 @(shellhelp2):1:1 test_rs:SECONDARY> quit; function quit() { [native code] } # 允许在从节点读取数据后 admin 0.000GB local 0.000GB mytest 0.000GB
查看复制状态信息
1 | rs.printReplicationInfo() |
rs.printReplicationInfo()
configured oplog size: 2048MB # 配置的oplog文件大小
log length start to end: 18118secs (5.03hrs) # oplog日志的启用时间段
oplog first event time: Mon Aug 31 2020 16:50:59 GMT+0800 (CST) # 第一个事务日志的产生时间
oplog last event time: Mon Aug 31 2020 21:52:57 GMT+0800 (CST) # 最后一个事务日志的产生时间
now: Mon Aug 31 2020 21:53:03 GMT+0800 (CST) # 现在的时间
rs.printSlaveReplicationInfo()
source: 192.168.100.10:27018 # 从库的IP及端口
syncedTo: Mon Aug 31 2020 22:01:07 GMT+0800 (CST) # 目前的同步情况, 以及最后一次同步时间等信息.
0 secs (0 hrs) behind the primary
source: 192.168.100.10:27019
syncedTo: Mon Aug 31 2020 22:01:07 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
更改oplog大小
oplog即operations log的简写, 存储在local数据库中. oplog中新操作会自动替换旧的操作, 以保证oplog不会超过预设的大小. 默认情况下, oplog大小会占用64位的实例5%的可用磁盘空间.
1 | use local |
{ "ns" : "local.oplog.rs", "size" : 185610, "count" : 1930, "avgObjSize" : 96, "storageSize" : 4096, "capped" : true, "max" : -1, "maxSize" : 102400000, "sleepCount" : 0, "sleepMS" : 0, "wiredTiger" : { "metadata" : { "formatVersion" : 1 }, ...... } } configured oplog size: 97.65625MB log length start to end: 19178secs (5.33hrs) oplog first event time: Mon Aug 31 2020 16:50:59 GMT+0800 (CST) oplog last event time: Mon Aug 31 2020 22:10:37 GMT+0800 (CST) now: Mon Aug 31 2020 22:10:41 GMT+0800 (CST)
部署认证的复制
1.为每个实例生成密钥文件, 并修改权限.
1 | touch /var/lib/testKeyFile.file |
2.登录主节点添加权限用户
1 | mongo --host 192.168.100.10:27017 |
3.关闭各实例服务, 为各实例配置文件添加上用户认证和密钥文件位置后并重新启动.
1 | mongod -f /etc/mongod.conf --shutdown |
4.登录主节点服务器, 验证群集.
1 | mongo --host 192.168.100.10:27017 |
认证前
2020-09-01T09:34:48.476+0800 E QUERY [thread1] Error: listDatabases failed:{
“ok” : 0,
“errmsg” : “not authorized on admin to execute command { listDatabases: 1.0 }”,
“code” : 13,
“codeName” : “Unauthorized”
} :{
“ok” : 0,
“errmsg” : “not authorized on admin to execute command { replSetGetStatus: 1.0 }”,
“code” : 13,
“codeName” : “Unauthorized”
}
认证后
admin 0.000GB
local 0.000GB
mytest 0.000GB{
“set” : “test_rs”,
“date” : ISODate(“2020-09-01T01:34:49.819Z”),
“myState” : 1,
“term” : NumberLong(5),
“syncingTo” : “”,
“syncSourceHost” : “”,
“syncSourceId” : -1,
“heartbeatIntervalMillis” : NumberLong(2000),
“optimes” : {
“lastCommittedOpTime” : {
“ts” : Timestamp(1598924082, 1),
“t” : NumberLong(5)
},
“appliedOpTime” : {
“ts” : Timestamp(1598924082, 1),
“t” : NumberLong(5)
},
“durableOpTime” : {
“ts” : Timestamp(1598924082, 1),
“t” : NumberLong(5)
}
},
……
}
5.登录从节点服务器, 验证群集.
1 | mongo --host 192.168.100.10:27018 |