MongoDB-(Replica Set)副本集-集群搭建
副本集概述
MongoDB
的副本集(Replica Set)
是一种提供数据冗余和高可用性的架构。它是由多个维护相同数据集的mongod
进程(即数据库实例)组成的一个集合,这些实例分布在不同的服务器上。副本集的设计目标是为了确保在单个服务器发生故障时,数据库服务依然可以继续运作,从而提高了系统的可靠性和容错能力。
副本集的架构
- 一个副本集最多有50个节点。一个副本集最多有7个投票节点,其余节点必须是没有投票权的节点。
- 副本集的最小推荐配置是三个节点:
- 一个主节点和两个从节点。
- 一个主节点、一个从节点和仲裁节点。
副本集的成员
副本集有两种类型三种角色
- 两种类型
- 主节点(Primary)类型:数据操作的主要连接点,可读写
- 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举
- 三种角色
- 主要成员(Primary):主要接收所有写操作。就是主节点。
- 副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型
- 仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用,当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。
- 建议
- 如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
- 如果你的副本+主节点的个数是奇数,可以不加仲裁者。
集群部署
节点划分
一台机器上部署三个mongodb节点
端口 | 角色 |
---|---|
27017 | 主节点 |
27018 | 副本节点 |
27019 | 仲裁节点 |
测试脚本
1 | sudo /opt/data/mongodb-27017/bin/mongod -f /opt/data/mongodb-27017/mongod-27017.yaml |
配置文件
(主节点 mongod-27017.yaml
)
vim /opt/data/mongodb-27017/mongod-27017.yaml
1 | systemLog: |
System 服务命令
1 | [Unit] |
(副本节点 mongod-27018.yaml
)
vim /opt/data/mongodb-27018/mongod-27018.yaml
1 | systemLog: |
System 服务命令
1 | [Unit] |
(仲裁节点 mongod-27019.yaml
)
vim /opt/data/mongodb-27019/mongod-27019.yaml
1 | systemLog: |
System 服务命令
1 | [Unit] |
副本集命令配置
初始化副本集 rs.initiate()
1 | test> show dbs; |
查看副本集的配置内容 rs.config()
1 | replicaset [direct: primary] test> rs.config() |
查看副本集状态 rs.status()
1 | replicaset [direct: primary] test> rs.status() |
添加副本集 rs.add("192.168.0.204:27018")
可以看到是 (not reachable/healthy) ,说明添加的副本节点是有问题的,正常的应该是 SECONDARY ,查看日志
1 | rs.add("192.168.0.204:27018") |
先将添加的副本节点删除 rs.remove("192.168.0.204:27018")
1 | rs.remove("192.168.0.204:27018") |
配置仲裁节点 rs.addArb("192.168.0.204:27019")
1 | rs.addArb("192.168.0.204:27019") |
异常信息
1 | 1. Reconfig attempted to install a config that would change the implicit default write concern. Use the setDefaultRWConcern command to set a cluster-wide write concern and try the reconfig again. |
在 MongoDB 中,
db.adminCommand
是一个用于执行管理命令的方法,而你提到的命令:
1 | db.adminCommand({ |
是用于设置默认的写关注(Write Concern)配置的命令。以下是详细解释:
1. 命令的作用
setDefaultRWConcern
: 这是一个管理命令,用于设置默认的读写关注(Read/Write Concern)配置。1
表示启用此功能。
defaultWriteConcern
: 这是设置默认的写关注配置。w: 2
表示写操作需要在至少两个节点上成功确认后才返回成功。
2. 写关注(Write Concern)
写关注(Write Concern)定义了写操作需要在多少个节点上成功确认后才返回成功。它主要用于控制数据的持久性和一致性。
w: 1
: 默认值,表示写操作只需在主节点上成功即可。w: 2
: 表示写操作需要在主节点和至少一个从节点上成功确认。w: "majority"
: 表示写操作需要在大多数节点上成功确认。
3. 在 MongoDB 集群中的作用
在 MongoDB 集群(如副本集或分片集群)中,写关注配置非常重要,因为它直接影响数据的持久性和性能:
- 高可用性和一致性:设置较高的写关注(如
w: 2
或w: "majority"
)可以确保数据在多个节点上持久化,从而提高数据的可用性和一致性。 - 性能:较高的写关注会增加写操作的确认时间,从而可能降低写性能。因此,需要根据实际需求权衡。
创建MongoDB数据库密码模式
1 | use admin |
数据库需配置密钥链接
配置 MongoDB 副本集时,启用了认证(authorization
),但没有指定密钥文件(keyFile
)。在 MongoDB
副本集中,如果启用了认证功能,密钥文件是必需的,用于成员之间的身份验证。
密钥文件必须具有适当的权限,以防止未经授权的访问。
1 | openssl rand -base64 756 > /opt/data/mongodb-27017/keyfile |
异常信息 keyfile are too open
1 | {"t":{"$date":"2025-05-27T03:01:21.276+00:00"},"s":"I", "c":"ACCESS", "id":20254, "ctx":"main","msg":"Read security file failed","attr":{"error":{"code":30,"codeName":"InvalidPath","errmsg":"permissions on /opt/data/mongodb-27017/keyfile are too open"}}} |
这个错误信息表明 MongoDB 无法启动,因为密钥文件 /opt/data/mongodb-27017/keyfile
的权限设置不正确。MongoDB
要求密钥文件的权限必须严格限制,以确保只有 MongoDB 进程可以访问它。
错误解释
- **
Read security file failed
**:MongoDB 无法读取密钥文件。 - **
permissions on /opt/data/mongodb-27017/keyfile are too open
**:密钥文件的权限设置过于宽松,MongoDB 不允许这种情况。
解决方法
你需要确保密钥文件的权限正确设置,具体步骤如下:
1. 检查密钥文件的当前权限
运行以下命令查看密钥文件的当前权限:
1 | ls -l /opt/data/mongodb-27017/keyfile |
你可能会看到类似以下的输出:
1 | -rw-r--r-- 1 mongodb mongodb 756 May 27 03:00 /opt/data/mongodb-27017/keyfile |
这表示当前权限是 644
(所有者可读写,组可读,其他用户也可读)。
2. 设置正确的权限
MongoDB 要求密钥文件的权限必须是 600
(只有所有者可以读写,其他用户无权限)。运行以下命令设置正确的权限:
sudo chmod 600 /opt/data/mongodb-27017/keyfile
. 验证权限
再次运行 ls -l
命令,确保权限已正确设置:
SpringBoot 配置数据库连接(副本集模式)
无密码模式
1 | spring.data.mongodb.uri=mongodb://192.168.0.204:27017,192.168.0.204:27018,192.168.0.204:27019/my-app?replicaSet=replicaset |
有密码模式
1 | spring.data.mongodb.uri=mongodb://db_manager:db_manager@192.168.0.204:27017,192.168.0.204:27018,192.168.0.204:27019/my-app?replicaSet=replicaset&authSource=admin |
正常状态的 rs.status()
name: ‘192.168.0.204:27017’ stateStr: ‘PRIMARY’
name: ‘192.168.0.204:27018’ stateStr: ‘SECONDARY’
name: ‘192.168.0.204:27019’ stateStr: ‘ARBITER’
主节点的选举原则
1、主节点选举触发条件
- MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件
- 主节点故障
- 主节点网络不可达(默认心跳信息为10秒)
- 人工干预(
rs.stepDown(600)
)primary直接降级在600s内不会把自己选为primary
- 一旦触发选举,就要根据一定规则来选择主节点。
2、选举规则
- 选举规则是根据票数来决定谁获胜
- 票数最高,且获得了“大多数”成员的投票支持的节点获胜。
- “大多数”的定义为:假设复制集内投票成员时N,则大多数为N/2+1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举primary,复制集将无法提供写服务,处于只读状态。
- 若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。
- 数据的新旧是通过操作日志oplog来对比的。
- 在获得票数的时候,优先级(priority)参数影响重大。
可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于增加0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成员主要成员,更低的值可使成员更不符合条件。
- 默认情况下,优先级的值是1
主节点的选举原则
MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
- 1.主节点故障
- 2.主节点网络不可达(默认心跳信息为10秒)
- 3.人工干预(rs.stepDown(600))
一旦触发选举,就要根据一定规则来选主节点。
选举规则是根据票数来决定谁获胜:
票数最高,且获得了“大多数”成员的投票支持的节点获胜。
“大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 +
1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。数据的新旧是通过操作日志oplog来对比的。
在获得票数的时候,优先级(priority)参数影响重大。可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成为主要成员,更低的值可使成员更不符合条件。默认情况下,优先级的值是1
可以看出,主节点和副本节点的优先级各为1,即,默认可以认为都已经有了一票。但选举节点,优先
级是0,(选举节点的优先级必须是0,不能是别的值。即不具备选举权,但具有投票权)
故障测试
1. 副本节点故障测试
提升主节点的优先级
关闭27018副本节点,主节点和仲裁节点对27018的心跳失败。因为主节点还在,因此,没有触发投票选举。
在主节点写入数据
db.comment.insert({})
再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。
如果此时,在主节点写入数据。
2. 主节点故障测试
关闭27017节点后发现,从节点和仲裁节点对27017的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起投票。
而副本节点只有27018,因此,候选人只有一个就是27018,开始投票。27019向27018投了一票,27018本身自带一票,因此共两票,超过了“大多数”27019是仲裁节点,没有选举权,27018不向其投票,其票数是0.最终结果,27018成为主节点。具备读写功能。在27018写入数据查看。
db.comment.insert({})
再启动27017节点,发现27017变成了从节点,27018仍保持主节点。登录27017节点,发现是从节点了,数据自动从27018同步。从而实现了高可用。
3. 仲裁节点和主节点故障测试
先关掉仲裁节点27019,关掉现在的主节点27017。
登录27018节点后发现,27018仍然是从节点,副本集中没有主节点了,导致此时副本集是只读状态,无法写入。
为啥不选举了?因为27018的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)如果要触发选举,随便加入一个成员即可。
- 如果只加入27019仲裁节点成员,则主节点一定是27018,因为没得选了,仲裁节点不参与选举,但参与投票。
- 如果只加入27017节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节点。
4. 仲裁节点和从节点故障测试
先关掉仲裁节点27019,关掉现在的副本节点27018。10秒后,27017主节点自动降级为副本节点。(服务降级)副本集不可写数据了,已经故障了。
集群故障分析
序号 | 故障类型 | 是否影响使用 |
---|---|---|
1 | 主节点故障 | 不影响正常使用 |
2 | 副本节点故障 | 不影响正常使用 |
3 | 仲裁节点故障 | 不影响正常使用 |
4 | 主节点和仲裁节点故障 | 影响正常使用,需要处理 |
5 | 从节点和仲裁节点故障 | 影响正常使用,需要处理 |
6 | 主节点和从节点故障 | 影响正常使用,需要处理 |
7 | 所有节点故障 | 影响正常使用,需要处理 |
1、主节点故障
- 从节点和仲裁节点对主节点的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起投票。
- 而副本节点只有一台,因此,候选人只有一个就是副本节点,开始投票。
- 仲裁节点向副本节点投了一票,副本节点本身自带一票,因此共两票,超过了”大多数”。
- 27019是仲裁节点,没有选举权,27018不向其投票,其票数是0。
- 最终结果,27018成为主节点。具备读写功能。
- 再启动 27017主节点,发现27017变成了从节点,27018仍保持主节点。
- 登录27017节点,发现是从节点了,数据自动从27018同步。
- 此时:不影响正常使用
2、副本节点故障
- 主节点和仲裁节点对副本节点的心跳失败。因为主节点还在,因此,没有触发投票选举。
如果此时,在主节点写入数据。再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。 - 此时:不影响正常使用
3、仲裁节点故障
- 主节点和副本节点对仲裁节点的心跳失败。因为主节点还在,因此,没有触发投票选举。
- 此时:不影响正常使用
4、主节点和仲裁节点故障
副本集中没有主节点了,导致此时,副本集是只读状态,无法写入。
因为27017的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)
如果要触发选举,随便加入一个成员即可。
- 如果只加入 27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举,但参与投票。
- 如果只加入 27018节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节点。
此时:影响正常使用,需要处理
5、从节点和仲裁节点故障
10秒后,27017主节点自动降级为副本节点。(服务降级)
副本集不可写数据了,已经故障了。
此时:影响正常使用,需要处理
6、主节点和从节点故障
集群将处于不完全状态,无法执行写操作,因为剩余的副本节点不足以立即选出新的主节点(假设只剩一个副本节点和仲裁节点)。直到至少有一个额外的副本节点在线并同步,以便选举出新的主节点
此时:影响正常使用,需要处理
7、所有节点故障
- 整个集群不可用,既不能执行读也不能执行写操作。
- 这种情况需要手动干预,逐一排查并恢复各个节点,确保至少一个主节点和多数节点(包括仲裁节点)在线,以恢复集群服务。
- 此时:影响正常使用,需要处理