备注:
MongoDB 4.2 版本
一.复制简介
我们使用的是单台服务器 ,一个 mongod 服务器进程 。如果只 是用作学习和开发,这是可以的,但是如果用到生产环境中,风险会很高:如果服务器崩溃了或者不可访问了怎么办 ?数据库至少会有 一段时间不可用 。如果是硬件出了问题,可能需要将数据转移到另一个机器上。在最坏的情况下,磁盘或者网络 问题可能会导致数据损坏或者数据不可访问 。
使用复制可以将数据副本保存到多台服务器上,建议在所有的生产环境中都要使用 。使用 MongoDB 的复制功能 ,即使一台或多台服务器出错 ,也可以保证应用程序 正 常运行和数据安全 。
在MongoDB中,创建一个副本集之后就可以使用复制功能了。副本集是一组服务器 ,其中有一个主服务器 (primary) ,用于处理客户端请求, 还有多个备份服务器 ( secondary ),用于保存主服务器 的数据副本。如果主服务器崩溃了 ,备份服务器会自动将其中一个成员升级为新的主服务器 。
使用复制功能时 ,如果有一台服务器宕机了 ,仍然可以从副本集的其他服务器上访问数据。如果服务器上的数据损坏或者不可访问,可以从副本集的某个成员中创建 一份新的数据副本 。
副本集是一种创建多个MongoDB实例的方式,这些实例将拥有相同的数据(冗余)和其它相关设置。主从复制、主主复制、复制对等方法都被副本集的概念所取代。在MongoDB中,副本集由一个主节点以及多个辅助或仲裁节点组成,一个副本集最少应该有3个成员。在MongoDB 3.0中,副本集最多可以有50个被动成员和7个主动成员。通常建议副本集有奇数个成员,这条规则主要是为了避免“脑裂”(split brain)问题,也就是说当网络出现问题时,有两台服务器成为主服务器的情况。
1.1 主动成员与被动成员
副本集提供了主动成员与被动成员。当前的主服务器不可用时,被动服务器不会参与新的主服务器的选举,但它们可投票否决某个成员的主服务器资格。
1.2 master
在副本集术语中,主服务器是在特定时间内副本集的数据来源。它是副本集中唯一可以写入的节点。所有其它节点都将从主服务器复制出它们的数据。主服务器由所有主动成员中的大多数投票产生,这被称为法定人数(quorum)。
主服务器的概念是(并且应该是)短暂的。理想情况下不应该固定地认为哪个节点是主服务器。
1.3 secondary
辅助服务器成员是具有数据的非主服务器成员,理论上它可以成为主服务器。它是一个只读节点,同时它将以尽可能接近于实时的方式从主服务器复制数据。默认情况下,如果连接到辅助服务器但不使用任何读偏好,就不能执行读操作。这是因为读取非主服务器时,如果复制过程中存在延迟,读取的可能是旧数据。可以使用rs.slaveOk()将当前连接设置为可从辅助服务器读取数据。或者如果使用的是某种语言的MongoDB驱动,那么也可以设置读偏好。
MongoDB的读偏好是它选择从哪个副本集成员读取数据的方式。通过为驱动指定一个读偏好,它将知道应该在副本集的哪个成员上执行查询。如果设置了读偏好,就意味着可能从辅助服务器读取数据。必须注意,得到的数据可能不是最新的。
1.4 arbiter
仲裁服务器是不含数据的节点,如果副本集中的主动成员是偶数,它就用于提供额外的主动成员,决定哪个节点成为主服务器。仲裁服务器用于帮助避免“脑裂”。
1.5 oplog
oplog(操作日志)是一个固定大小的集合,保存主服务器实例对数据库做出修改的记录,目的是在辅助服务器重做这些操作,保证数据库处于一致状态。副本集的每个成员维护自己的oplog,并且辅助服务器将查询主服务器(或者用过复制链进行其它数据更新的辅助服务器)的oplog,从而获得新条目,并应用到自己的数据库副本中。
oplog将为每个条目创建一个时间戳。通过这种方式,辅助服务器可以记录从上一次读取开始过去了多久,以及有多少oplog需要读取。可将oplog看成主服务器实例最近活动的窗口:如果窗口太小,那么记录中的某些操作可能在被应用到辅助服务器之前丢失。如果当前实例的oplog尚未创建,那么使用--oplogSize启动选项可以设置oplog的大小(以MB为单位)。在64位Linux系统中,oplogSize默认设置为可以磁盘空间的5%,最小为1GB,最大为50GB。
二.副本集维护
环境如下:
IP | 主机名 | 类别 |
---|---|---|
10.31.1.126 | 10-31-1-126 | 主动成员1 |
10.31.1.125 | 10-31-1-125 | 主动成员2 |
10.31.1.124 | 10-31-1-124 | 被动成员1 |
10.31.1.123 | 10-31-1-123 | 仲裁 |
vi /etc/hosts
10.31.1.123 10-31-1-123
10.31.1.124 10-31-1-124
10.31.1.125 10-31-1-125
10.31.1.126 10-31-1-126
2.1 创建副本集
2.1.1 启动副本集成员
以下命令在126上执行:
# 建立autokey文件
mkdir -p /usr/local/mongodb/
cd /usr/local/mongodb/
openssl rand -base64 756 > autokey
# 修改读写模式
chmod 400 autokey
# 复制到副本集成员节点
scp autokey 10.31.1.125:/usr/local/mongodb/
scp autokey 10.31.1.124:/usr/local/mongodb/
scp autokey 10.31.1.123:/usr/local/mongodb/
修改配置文件
mkdir -p /usr/local/mongodb/data/db
mkdir -p /usr/local/mongodb/data/logs
-- 清空配置文件
>/etc/mongod.conf
vi /etc/mongod.conf
如下为配置文件内容:
processManagement:
fork: true
storage:
dbPath: "/usr/local/mongodb/data/db"
systemLog:
destination: file
path: "/usr/local/mongodb/data/logs/mongodb.log"
logAppend: true
net:
port: 27017
bindIp: 0.0.0.0
security:
authorization: enabled
keyFile: /usr/local/mongodb/autokey
replication:
replSetName: rs
重启mongod服务
pkill mongod
mongod -f /etc/mongod.conf
2.1.2 初始化副本集
在126实例中执行:
-- root用户才有权限进行下列操作,其它用户会报错
use admin
db.auth("root","123456")
-- 添加集群用户
db.getSiblingDB("admin").createUser(
{
"user" : "clusteradmin",
"pwd" : "123456",
roles: [ { "role" : "clusterAdmin", "db" : "admin" },{ role: "userAdminAnyDatabase", db: "admin" } ]
}
)
> rs.initiate();
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "10-31-1-126:27017",
"ok" : 1
}
rs:SECONDARY>
2.2 向副本集添加服务器
在126实例中执行:
rs.add("10.31.1.125:27017");
rs.add("10.31.1.124:27017");
测试记录:
rs:PRIMARY> rs.add("10.31.1.125:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604991804, 1),
"signature" : {
"hash" : BinData(0,"i5uD9w9i5OH20FxMY9+ZXv2fe8Q="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604991804, 1)
}
rs:PRIMARY>
rs:PRIMARY> rs.add("10.31.1.124:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992027, 1),
"signature" : {
"hash" : BinData(0,"eF7nAViPRSGL8QMOpX0PZJS1gek="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992027, 1)
}
rs:PRIMARY>
2.3 设置辅助服务器
在126实例中执行以下命令,将124设置为隐藏,并且优先级为0:
rs:PRIMARY> conf = rs.conf();
{
"_id" : "rs",
"version" : 3,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "10-31-1-126:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.31.1.125:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.31.1.124:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa09da100d84a061f33286")
}
}
rs:PRIMARY> conf.members[2].hidden = true
true
rs:PRIMARY> conf.members[2].priority = 0
0
rs:PRIMARY> rs.reconfig(conf);
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992141, 1),
"signature" : {
"hash" : BinData(0,"C7QDx9sWsMwGSeZYMZUf+8hWFL0="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992141, 1)
}
rs:PRIMARY>
这样124不会被选举为主服务器。
2.4 向副本集添加仲裁服务器
在126实例中执行:
rs:PRIMARY> rs.addArb("10.31.1.123:27017");
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992252, 1),
"signature" : {
"hash" : BinData(0,"BLF8bW3Ug2/g6Cjz8W+j9Yf95AI="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992252, 1)
}
rs:PRIMARY>
2.5 设置被动服务器
现在副本集中有4个节点,需要使主动成员数为奇数,在126实例中执行:
rs:PRIMARY> conf = rs.conf()
{
"_id" : "rs",
"version" : 5,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "10-31-1-126:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.31.1.125:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.31.1.124:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : true,
"priority" : 0,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 3,
"host" : "10.31.1.123:27017",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa09da100d84a061f33286")
}
}
rs:PRIMARY> conf.members[2].votes = 0
0
rs:PRIMARY> rs.reconfig(conf)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1604992330, 1),
"signature" : {
"hash" : BinData(0,"k8bFCCLaGDXGQmBIgN7r2VFobjA="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1604992330, 1)
}
rs:PRIMARY>
124的votes值设置为0,现在hdp2完全变成被动服务器,它被客户端看成副本集的一部分,并且不会参与选举,也永远不会变成主服务器。
2.6 管理副本集
命令 | 描述 |
---|---|
rs.help() | 返回命令列表。 |
rs.status() | 返回副本集当前的状态信息。该命令列出了每个成员服务器及其状态信息,包括最后联系时间。该调用可被用于提供整个集群的简单健康检查。 |
rs.initiate() | 使用默认参数初始化副本集。 |
rs.initiate(replSetcfg) | 使用配置描述初始化副本集。 |
rs.add("host:port") | 使用含有主机名和特定端口(可选)的简单字符串向副本集中添加成员服务器。 |
rs.add(membercfg) | 使用配置描述向副本集中添加成员服务器。如果希望指定特定的属性(如设置新成员服务器的优先级),那么必须使用这种方法。 |
rs.addArb("host:port") | 添加新的成员服务器作为仲裁者。该成员不需要使用—replSet选项:任何运行在可达机器上的mongod实例都可以执行该任务。注意该服务器必须对副本集中的所有成员可达。 |
rs.stepDown() | 在副本集的主服务器成员中使用该命令时,将使主服务器放弃它的角色,并且在集群中重新选举新的主服务器。注意只有主动辅助服务器可用作主服务器的候选,并且在60秒(缺省)之内如果没有出现其它可用的成员,那么原有的主服务器将重新成为主服务器。 |
rs.syncFrom("host:port") | 使辅助服务器从指定的成员同步数据,可用于组成同步链。 |
rs.freeze(secs) | 冻结指定的成员,并使它在指定秒数内无法成为主服务器。 |
rs.remove("host:port") | 从副本集中删除指定成员。 |
rs.secondaryOk()() | 通过该选项,可以允许从辅助服务器读取数据。 |
rs.conf() | 重新显示当前副本集的配置结构。改配置结构可以被修改,然后用作rs.reconfig()的参数,从而修改结构的配置。 |
db.isMaster() | 该函数不只可作用于副本集:它是一个通用的复制支持函数。通过它,应用或驱动可以判断出被连接的特定实例在复制拓扑结构中是否是主服务器。 |
rs.status字段的值:
值 | 描述 |
---|---|
_id | 副本集中该成员的ID |
Name | 该成员的主机名 |
Health | replSet的健康值 |
State | 状态数值 |
StateStr | 副本集状态的字符串表示 |
Uptime | 该成员的运行时间 |
optime | 应用在该成员上最后一个操作的时间,格式为一个时间戳和一个整数值 |
optimeDate | 最后一个被应用操作的日期 |
lastHeartbeat | 最后一次发送心跳的日期 |
lastHeartbeatRecv | 最后一次收到心跳的日期 |
configVersion | 这个成员使用的副本集配置的版本 |
syncingTo | 使用哪个副本集成员同步数据 |
FAQ
1.重新初始化
cfg = rs.conf()
cfg.members[0].host = "你的IP 或者域名"
rs.reconfig(cfg)
测试记录:
rs:PRIMARY> cfg = rs.conf()
{
"_id" : "rs",
"version" : 9,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "10-31-1-126:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5faa09da100d84a061f33286")
}
}
rs:PRIMARY> cfg.members[0].host = "10.31.1.126"
10.31.1.126
rs:PRIMARY> rs.reconfig(cfg)
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1605085418, 1),
"signature" : {
"hash" : BinData(0,"hSupkyIZ07GWPVflfMd4M4iHV6c="),
"keyId" : NumberLong("6893333011551485956")
}
},
"operationTime" : Timestamp(1605085418, 1)
}
2.删除副本集
主节点是删除不了的,至少要有一个主节点要存在。
另外,其它节点虽然从副本集退出了,但是旧的配置依旧存在,如果要配置其它的,会影响到
-- 125 被清理出副本集之后,重新配置分片无法成功,清理这个表之后成功
-- 如果有授权问题,先忽略授权,删除了之后,再调整配置文件
> use local
switched to db local
>
>
> db.dropDatabase();
{ "dropped" : "local", "ok" : 1 }
>
参考
1.MongoDB权威指南(第二版)
2.https://blog.csdn.net/wzy0623/article/details/83113823
3.https://www.cnblogs.com/s6-b/p/11288583.html
4.https://blog.csdn.net/yuanwei1144/article/details/103840914