MongoDB复制集及配置
1 复制集
1.1 复制集结构
有PSS(一主两从)、PSA(一主一从一投票(Arbiter))
复制集建议为单数节点,最少三节点,有利发生故障时投票选举,双数节点投票时容易发生脑裂
Arbiter节点在整个集群中只做投票,各节点通过内置的RAFT协议进行互相有心跳检测,
投票节点不参数任何的数据复制和选主,只参与投票!那么投票节点是不是就可以使用最低配的服务器。
1.2 数据如何复制
主库写操作,无论是插入、更新或删除,到达主节点时,它对数据的操作将被记录下来(经过一些必要的转换),这些记录称为 oplog,从节点通过在主节点上打开一个 tailable 游标不断获取新进入主节点的oplog,并在自己的数据上回放,以此保持跟主节点的数据一致。
1.3 复制集故障恢复
通过选举完成故障恢复,具有投票权的节点之间两两互相发送心跳:
- 5次心跳检测,判断是否失联,如果失联,此时从节点会发起选举,然后发起投票
- 选举成功后,重新构建复制环境,当失联的节点恢复后,会自动加入到复制集中作为从节点
- 选举基于 RAFT 一致性算法实现,选举成功的必要条件是大多数投票节点存活
- oplog类似MySQL的binlog,但不同的是,binlog是存在磁盘文件中的,oplog是存在表中,追加式的日志
1.3.1 选举影响因素
整个集群必须有大多数节点存活;被选举为主节点的节点必须:
- 能够与多数节点建立连接
- 具有较新的 oplog
- 具有较高的优先级(如果有配置)
1.4 常见选项
复制集节点有以下常见的选配项:
- 是否具有投票权(v 参数):有则参与投票;
- 优先级(priority 参数):优先级越高的节点越优先成为主节点。优先级为0的节点无法成为主节点
- 隐藏(hidden 参数):复制数据,但对应用不可见。隐藏节点可以具有投票仅,但优先级必须为0
- 延迟(slaveDelay 参数):复制 n 秒之前的数据,保持与主节点的时间差
1.5 复制集的作用
通过内部的日志oplog来实现一致性的复制,类似MySQL的MGR的功能。
在主节点发生故障时,会自动选出一个替代节点,进行自动的故障转移。
复制集的主要意义在于实现服务高可用,它的现实依赖于两个方面的
功能:
- 数据写入时将数据迅速复制到另一个独立节点上
- 在接受写入的节点发生故障时从节点会自动选举出一个新的替代节点
在实现高可用的同时,复制集实现了其他几个附加作用:
- 数据分发:将数据从一个区域复制到另一个区域,减少另一个区域的读延迟
- 读写分离:不同类型的压力分别在不同的节点上执行
- 异地容灾:在数据中心故障时候快速切换到异地
1.6 复制集注意事项
1.关于硬件
- 因为正常的复制集节点都有可能成为主节点,它们的地位是一样的,因此硬件配置上必须一致
- 为了保证节点不会同时宕机,各节点使用的硬件必须具有独立性
2.关于软件: - 复制集各节点软件版本必须一致,以避免出现不可预知的问题。
- 增加节点不会增加系统写性能
2 复制集(Replcation Set)配置
2.1 准备工作(所有节点都执行)
2.1.1 主机规划
- 操作系统版本:Red Hat Enterprise Linux Server release 7.9 (Maipo)
主机名 | 用户 | 角色 | ip | 版本 |
---|---|---|---|---|
mongodb01 | mongod | 主节点(P) | 172.22.14.84 | v4.2.8 |
mongodb02 | mongod | 从节点(S) | 172.22.14.85 | v4.2.8 |
mongodb03 | mongod | 从节点(S) | 172.22.14.86 | v4.2.8 |
mongodb04 | mongod | 特殊从节点(S) | 172.22.14.56 | v4.2.8 |
2.1.2 目录规划
mkdir -p /mongodb/{app,conf,data,log}/
app: 程序目录
conf:配置文件
data:数据目录
log:日志文件
2.1.3 创建用户
useradd mongod
passwd mongod
2.1.4 关闭THP(所有节点都执行)
root用户 vi /etc/rc.local最后添加如下代码
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
[root@mongodb01 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
[root@mongodb01 ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
[always] madvise never
[root@mongodb01 ~]#
其他系统关闭参照官方文档:https://docs.mongodb.com/manual/tutorial/transparent-huge-pages/
2.1.5 部署mongodb
tar -xf mongodb-linux-x86_64-rhel70-4.2.8.tgz -C /mongodb/app/
cd /mongodb/app
ln -s /mongodb/app/mongodb-linux-x86_64-rhel70-4.2.8/ mongodb
2.1.6 修改权限
chown -R mongod:mongod /mongodb
2.1.7 设置环境变量
切换用户并设置环境变量
su - mongod
vi .bash_profile
export PATH=/mongodb/app/mongodb/bin:$PATH
source .bash_profile
2.2 配置文件内容准备
mongodb01:
cat > /mongodb/conf/mongod.conf <<EOF
systemLog:
destination: file
path: /mongodb/log/mongodb.log # 日志位置
logAppend: true # 日志以追加模式记录
storage:
journal:
enabled: true
dbPath: /mongodb/data # 数据路径的位置
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
processManagement:
fork: true # 后台守护进程
net:
port: 27017
bindIp: 172.22.14.84,127.0.0.1
replication:
oplogSizeMB: 2048
replSetName: my_repl
EOF
mongodb02
cat > /mongodb/conf/mongod.conf <<EOF
systemLog:
destination: file
path: /mongodb/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/data
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
processManagement:
fork: true
net:
port: 27017
bindIp: 172.22.14.85,127.0.0.1
replication:
oplogSizeMB: 2048
replSetName: my_repl
EOF
mongodb03
cat > /mongodb/conf/mongod.conf <<EOF
systemLog:
destination: file
path: /mongodb/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/data
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
processManagement:
fork: true
net:
port: 27017
bindIp: 172.22.14.86,127.0.0.1
replication:
oplogSizeMB: 2048
replSetName: my_repl
EOF
mongodb04
cat > /mongodb/conf/mongod.conf <<EOF
systemLog:
destination: file
path: /mongodb/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/data
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
processManagement:
fork: true
net:
port: 27017
bindIp: 172.22.14.56,127.0.0.1
replication:
oplogSizeMB: 2048
replSetName: my_repl
EOF
2.3 启动(所有节点都执行)
mongod -f /mongodb/conf/mongod.conf
停止命令:mongod -f /mongodb/conf/mongod.conf
2.3.1 检查
以mongodb01为例,端口:
[mongod@mongodb01 ~]$ netstat -lntup|grep 27017
tcp 0 0 172.22.14.84:27017 0.0.0.0:* LISTEN 25557/mongod
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 25557/mongod
登录:
[mongod@mongodb01 ~]$ mongo
MongoDB shell version v4.2.8
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("359d7530-11cb-4104-81f5-b26ee7f729a0") }
MongoDB server version: 4.2.8
>
2.4 配置复制集:(随便登录一个节点执行)
登录到mongodb,然后执行,1主2从,从库普通从库(PSS),命令如下:
config = {_id: 'my_repl', members: [
{_id: 0, host: '172.22.14.84:27017'},
{_id: 1, host: '172.22.14.85:27017'},
{_id: 2, host: '172.22.14.86:27017'}]} # 成员的id可以自动生成,为了方便管理,也可以手动设置
rs.initiate(config) # 初始化配置
结果如下:
> config = {_id: 'my_repl', members: [
... {_id: 0, host: '172.22.14.84:27017'},
... {_id: 1, host: '172.22.14.85:27017'},
... {_id: 2, host: '172.22.14.86:27017'}]}
{
"_id" : "my_repl",
"members" : [
{
"_id" : 0,
"host" : "172.22.14.84:27017"
},
{
"_id" : 1,
"host" : "172.22.14.85:27017"
},
{
"_id" : 2,
"host" : "172.22.14.86:27017"
}
]
}
>
> rs.initiate(config)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1644930994, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1644930994, 1)
}
my_repl:PRIMARY> # rs.initiate(config)执行完成后,mongodb会自动选一个节点为主节点
2.4.1 从库开启读功能
执行命令:rs.slaveOk()
2.4.2 测试复制集
添加数据测试
db.movies.insert([ { "title" : "肖生客的救赎", "year" : 1994,"imdb_rating" : 9.7 },{ "title" : "辛德勒的名单", "year" : 1993,"imdb_rating" : 9.5 }])
my_repl:PRIMARY> db.movies.insert([ { "title" : "肖生客的救赎", "year" : 1994,"imdb_rating" : 9.7 },{ "title" : "辛德勒的名单", "year" : 1993,"imdb_rating" : 9.5 }])
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
my_repl:PRIMARY> db.movies.find().pretty()
{
"_id" : ObjectId("620baaad29e26c569e1921cd"),
"title" : "肖生客的救赎",
"year" : 1994,
"imdb_rating" : 9.7
}
{
"_id" : ObjectId("620baaad29e26c569e1921ce"),
"title" : "辛德勒的名单",
"year" : 1993,
"imdb_rating" : 9.5
}
my_repl:PRIMARY>
注:在mongodb复制集当中,默认从库不允许读写,需要执行命令:rs.slaveOk() ,然后就可以读了,如:
my_repl:SECONDARY> db.movies.find()
Error: error: {
"operationTime" : Timestamp(1645018054, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1645018054, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
my_repl:SECONDARY> rs.slaveOk()
my_repl:SECONDARY> db.movies.find()
{ "_id" : ObjectId("620cfbb90200a96020ca8480"), "title" : "辛德勒的名单", "year" : 1993, "imdb_rating" : 9.5 }
{ "_id" : ObjectId("620cfbb90200a96020ca847f"), "title" : "肖生客的救赎", "year" : 1994, "imdb_rating" : 9.7 }
my_repl:SECONDARY>
2.4.3 停止从库测试
停止一个从库,主库上添加一条数据,例如:
db.movies.insert({ "title" : "楚门的世界", "year" : 1998,"imdb_rating" : 9.3 })
结果:
my_repl:PRIMARY> db.movies.insert({ "title" : "楚门的世界2", "year" : 1998,"imdb_rating" : 9.5 })
WriteResult({ "nInserted" : 1 })
my_repl:PRIMARY> db.movies.find().pretty()
{
"_id" : ObjectId("620baaad29e26c569e1921cd"),
"title" : "肖生客的救赎",
"year" : 1994,
"imdb_rating" : 9.7
}
{
"_id" : ObjectId("620baaad29e26c569e1921ce"),
"title" : "辛德勒的名单",
"year" : 1993,
"imdb_rating" : 9.5
}
{
"_id" : ObjectId("620bac2929e26c569e1921cf"),
"title" : "楚门的世界",
"year" : 1998,
"imdb_rating" : 9.3
}
从库恢复后,执行rs.slaveOk()加入复制集后,会自动将新添加的数据复制过来,例如:
my_repl:SECONDARY> rs.slaveOk()
my_repl:SECONDARY> db.movies.find().pretty()
{
"_id" : ObjectId("620baaad29e26c569e1921cd"),
"title" : "肖生客的救赎",
"year" : 1994,
"imdb_rating" : 9.7
}
{
"_id" : ObjectId("620baaad29e26c569e1921ce"),
"title" : "辛德勒的名单",
"year" : 1993,
"imdb_rating" : 9.5
}
{
"_id" : ObjectId("620bac2929e26c569e1921cf"),
"title" : "楚门的世界",
"year" : 1998,
"imdb_rating" : 9.3 # 新添加的数据自动复制
}
2.5 复制集管理
2.5.1 查看复制集状态
rs.status(); # 查看整体复制集状态
rs.isMaster(); # 查看当前是否是主节点
主库执行:
my_repl:PRIMARY> rs.isMaster()
{
"hosts" : [
"172.22.14.84:27017",
"172.22.14.85:27017",
"172.22.14.86:27017"
],
"setName" : "my_repl",
"setVersion" : 1,
"ismaster" : true,
"secondary" : false,
"primary" : "172.22.14.84:27017",
"me" : "172.22.14.84:27017",
"electionId" : ObjectId("7fffffff0000000000000001"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1645018844, 1),
"t" : NumberLong(1)
},
"lastWriteDate" : ISODate("2022-02-16T13:40:44Z"),
"majorityOpTime" : {
"ts" : Timestamp(1645018844, 1),
"t" : NumberLong(1)
},
"majorityWriteDate" : ISODate("2022-02-16T13:40:44Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2022-02-16T13:40:46.236Z"),
"logicalSessionTimeoutMinutes" : 30,
"connectionId" : 1,
"minWireVersion" : 0,
"maxWireVersion" : 8,
"readOnly" : false,
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645018844, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645018844, 1)
}
my_repl:PRIMARY>
rs.isMaster()从节点执行,例如:
my_repl:SECONDARY> rs.isMaster()
{
"hosts" : [
"172.22.14.84:27017",
"172.22.14.85:27017",
"172.22.14.86:27017"
],
"setName" : "my_repl",
"setVersion" : 1,
"ismaster" : false,
"secondary" : true,
"primary" : "172.22.14.84:27017",
"me" : "172.22.14.85:27017",
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1645018874, 1),
"t" : NumberLong(1)
},
"lastWriteDate" : ISODate("2022-02-16T13:41:14Z"),
"majorityOpTime" : {
"ts" : Timestamp(1645018874, 1),
"t" : NumberLong(1)
},
"majorityWriteDate" : ISODate("2022-02-16T13:41:14Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2022-02-16T13:41:21.917Z"),
"logicalSessionTimeoutMinutes" : 30,
"connectionId" : 1,
"minWireVersion" : 0,
"maxWireVersion" : 8,
"readOnly" : false,
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645018874, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645018874, 1)
}
my_repl:SECONDARY>
2.5.2 添加节点(主节点上执行)
添加节点,命令:rs.add("ip:port");
,例如:
my_repl:PRIMARY> rs.add("172.22.14.56:27017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645018929, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645018929, 1)
}
my_repl:PRIMARY>
查看:
my_repl:PRIMARY> rs.status()
{
"set" : "my_repl",
"date" : ISODate("2022-02-16T13:42:49.877Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 3,
"writeMajorityCount" : 3,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2022-02-16T13:42:44.905Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"readConcernMajorityWallTime" : ISODate("2022-02-16T13:42:44.905Z"),
"appliedOpTime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2022-02-16T13:42:44.905Z"),
"lastDurableWallTime" : ISODate("2022-02-16T13:42:44.905Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1645018929, 1),
"lastStableCheckpointTimestamp" : Timestamp(1645018929, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2022-02-16T13:26:14.795Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1645017963, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2022-02-16T13:26:14.840Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2022-02-16T13:26:16.242Z")
},
"members" : [
{
"_id" : 0,
"name" : "172.22.14.84:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1044,
"optime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:42:44Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1645017974, 1),
"electionDate" : ISODate("2022-02-16T13:26:14Z"),
"configVersion" : 2,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "172.22.14.85:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1006,
"optime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:42:44Z"),
"optimeDurableDate" : ISODate("2022-02-16T13:42:44Z"),
"lastHeartbeat" : ISODate("2022-02-16T13:42:49.224Z"),
"lastHeartbeatRecv" : ISODate("2022-02-16T13:42:49.225Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "172.22.14.84:27017",
"syncSourceHost" : "172.22.14.84:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 2
},
{
"_id" : 2,
"name" : "172.22.14.86:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1006,
"optime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:42:44Z"),
"optimeDurableDate" : ISODate("2022-02-16T13:42:44Z"),
"lastHeartbeat" : ISODate("2022-02-16T13:42:49.225Z"),
"lastHeartbeatRecv" : ISODate("2022-02-16T13:42:48.250Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "172.22.14.56:27017",
"syncSourceHost" : "172.22.14.56:27017",
"syncSourceId" : 3,
"infoMessage" : "",
"configVersion" : 2
},
{
"_id" : 3,
"name" : "172.22.14.56:27017", # 新添加的节点
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 40,
"optime" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1645018964, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:42:44Z"),
"optimeDurableDate" : ISODate("2022-02-16T13:42:44Z"),
"lastHeartbeat" : ISODate("2022-02-16T13:42:49.235Z"),
"lastHeartbeatRecv" : ISODate("2022-02-16T13:42:49.637Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "172.22.14.85:27017",
"syncSourceHost" : "172.22.14.85:27017",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 2
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645018964, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645018964, 1)
}
my_repl:PRIMARY>
2.5.3 删除节点
命令:rs.remove("ip:port")
,例如:
my_repl:PRIMARY> rs.remove("172.22.14.56:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645019046, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645019046, 1)
}
my_repl:PRIMARY>
2.5.4 添加一个仲裁节点
命令:rs.addArb("ip:port")
,例如:
my_repl:PRIMARY> rs.addArb("172.22.14.56:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645019096, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645019096, 1)
}
my_repl:PRIMARY> rs.status()
{
"set" : "my_repl",
"date" : ISODate("2022-02-16T13:59:58.013Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 3,
"writeMajorityCount" : 3,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2022-02-16T13:59:54.940Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"readConcernMajorityWallTime" : ISODate("2022-02-16T13:59:54.940Z"),
"appliedOpTime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2022-02-16T13:59:54.940Z"),
"lastDurableWallTime" : ISODate("2022-02-16T13:59:54.940Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1645019954, 1),
"lastStableCheckpointTimestamp" : Timestamp(1645019954, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2022-02-16T13:26:14.795Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1645017963, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2022-02-16T13:26:14.840Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2022-02-16T13:26:16.242Z")
},
"members" : [
{
"_id" : 0,
"name" : "172.22.14.84:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 2073,
"optime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:59:54Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1645017974, 1),
"electionDate" : ISODate("2022-02-16T13:26:14Z"),
"configVersion" : 4,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "172.22.14.85:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 2034,
"optime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:59:54Z"),
"optimeDurableDate" : ISODate("2022-02-16T13:59:54Z"),
"lastHeartbeat" : ISODate("2022-02-16T13:59:56.676Z"),
"lastHeartbeatRecv" : ISODate("2022-02-16T13:59:57.550Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "172.22.14.84:27017",
"syncSourceHost" : "172.22.14.84:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 4
},
{
"_id" : 2,
"name" : "172.22.14.86:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 2034,
"optime" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1645019994, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-02-16T13:59:54Z"),
"optimeDurableDate" : ISODate("2022-02-16T13:59:54Z"),
"lastHeartbeat" : ISODate("2022-02-16T13:59:56.676Z"),
"lastHeartbeatRecv" : ISODate("2022-02-16T13:59:57.550Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "172.22.14.84:27017",
"syncSourceHost" : "172.22.14.84:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 4
},
{
"_id" : 3,
"name" : "172.22.14.56:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER", # 仲裁节点
"uptime" : 16,
"lastHeartbeat" : ISODate("2022-02-16T13:59:57.331Z"),
"lastHeartbeatRecv" : ISODate("2022-02-16T13:59:57.669Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 4
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645019994, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645019994, 1)
}
my_repl:PRIMARY>
2.5.5 特殊从节点的配置
优先级(priority 参数:0-1000):优先级越高的节点越优先成为主节点;优先级为0的节点无法成为主节点;
隐藏(hidden 参数):复制数据,但对应用不可见。隐藏节点可以具有投票仅,但优先级必须为0;
延迟(slaveDelay 参数):复制 n 秒之前的数据,保持与主节点的时间
新添加一个从节点,并设置为隐藏节点,且延时复制不参与投票,例如:
my_repl:PRIMARY> rs.add("172.22.14.56:27017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1645022230, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1645022230, 1)
}
my_repl:PRIMARY> rs.config()
{
……省略……
{
"_id" : 3,
"host" : "172.22.14.56:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
……省略……
}
my_repl:PRIMARY>
设置新添加的节点为隐藏节点,且不参与投票,延时复制(一般延时节点也配置成hidden),例如:
cfg=rs.conf() # 将配置导入到变量中
# members[数字]表示节点号,在rs.conf() 0表示第一个节点,3表示第4个节点
cfg.members[3].priority=0 # 是否会被选为新主,设置0,不会被选为新主
cfg.members[3].slaveDelay=120 # 延时120s
cfg.members[3].hidden=true # 修改节点为隐藏节点
cfg.members[3].votes=0 # 设置不投票
rs.reconfig(cfg) #重新加载
修改后:
my_repl:PRIMARY> rs.config()
{
……省略……
{
"_id" : 3,
"host" : "172.22.14.56:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : true, # 隐藏
"priority" : 0, # 不参与选主
"tags" : {
},
"slaveDelay" : NumberLong(120), # 延时120s复制
"votes" : 0 # 不投票
}
……省略……
}
my_repl:PRIMARY>
注意:重新修改回来命令:
cfg=rs.conf()
cfg.members[3].priority=1
cfg.members[3].slaveDelay=0
cfg.members[3].hidden=0
cfg.members[3].votes=1
rs.reconfig(cfg)
rs.conf() # 查看复制集配置
2.5.6 复制集其他操作命令
- 查看复制集配置信息:
rs.config()
- 查看复制集各成员状态:
rs.status()
- 复制集角色切换(不要人为顺便操作,有风险)
rs.stepDown()
- 锁定从库,使其不成为主库(freeze()和stepDown()单位都是秒。)
rs.freeze(300)
- 设置副本节点可读:在副本节点执行:
rs.slaveOk()
- 查看副本节点
rs.printSlaveReplicationInfo()
例如:
my_repl:PRIMARY> rs.printSlaveReplicationInfo() # 命令看不到仲裁节点
source: 172.22.14.86:27017
syncedTo: Tue Feb 15 2022 22:48:56 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
source: 172.22.14.85:27017
syncedTo: Tue Feb 15 2022 22:46:56 GMT+0800 (CST)
120 secs (0.03 hrs) behind the primary
my_repl:PRIMARY>
2.5.7 环境清理
如果复制集部署过程中遇到了其他问题,以使用下面的命令来进行重置完后,重新配置即可
su - mongod
mongod -f /mongodb/conf/mongod.conf --shutdown
rm -rf /mongodb/conf/*
rm -rf /mongodb/log/*
rm -rf /mongodb/data/*
2.5.8 小结
- PSS结构的复制集刚搭建完默认情况下只能在主节点上进行读写,从库是不具备任何读写能力
- 不支持级联复制
- 隐藏节点,只参与复制,不参与选举和投票(mongodb也支持延时复制),可以做一些内部的大查询库用
- 延时库也只参与复制,不参与选举和投票,不对外提供服务
- mongodb的配置文件支持等值配置也支持YAML方式配置,yaml方式配置时,一定要注意格式