MongoDB复制集架构

发布时间:2024年01月07日

在生产环境中,不建议使用单机版的 MongoDB 服务器。原因如下:

  • 单机版的 MongoDB 无法保证可靠性,一旦进程发生故障或是服务器宕机,业务将直接不可用。
  • 一旦服务器上的磁盘损坏,数据会直接丢失,而此时并没有任何副本可用。

复制集介绍

MongoDB 复制集(Replication Set)由一组 MongoDB 实例(进程)组成,包含一个 Primary 节点和多个 Secondary 节点,MongoDB Driver(客户端)的所有数据都写入 Primary,Secondary 从 Primary 同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。复制集提供冗余和高可用性,是所有生产部署的基础。它的现实依赖于两个方面的功能:

  • 数据写入时将数据迅速复制到另一个独立节点上
  • 在接受写入的节点发生故障时自动选举出一个新的替代节点

image.png
在实现高可用的同时,复制集实现了其他几个附加作用:

  • 数据分发:将数据从一个区域复制到另一个区域,减少另一个区域的读延迟
  • 读写分离:不同类型的压力分别在不同的节点上执行
  • 异地容灾:在数据中心故障时候快速切换到异地

早期版本的 MongoDB 使用了一种 Master-Slave 的架构,该做法在 MongoDB 3.4 版本之后已经废弃。

三节点复制集模式

常见的复制集架构由 3 个成员节点组成,其中存在几种不同的模式。

PSS 模式(官方推荐模式)

PSS 模式由一个主节点和两个备节点所组成,即 Primary+Secondary+Secondary。
image.png
此模式始终提供数据集的两个完整副本,如果主节点不可用,则复制集选择备节点作为主节点并继续正常操作。旧的主节点在可用时重新加入复制集。
image.png

PSA 模式

PSA 模式由一个主节点、一个备节点和一个仲裁者节点组成,即 Primary+Secondary+Arbiter。
image.png
其中,Arbiter 节点不存储数据副本,也不提供业务的读写操作。Arbiter 节点发生故障不影响业务,仅影响选举投票(类似于 Zookeeper 的 Observer 节点)。此模式仅提供数据的一个完整副本,如果主节点不可用,则复制集将选择备节点作为主节点。
image.png

典型三节点复制集环境搭建

复制集注意事项

关于硬件:

  • 因为正常的复制集节点都有可能成为主节点,它们的地位是一样的,因此硬件配置上必须一致;
  • 为了保证节点不会同时宕机,各节点使用的硬件必须具有独立性;

关于软件:

  • 复制集各节点软件版本必须一致,以避免出现不可预知的问题;
  • 增加节点不会增加系统写性能;

环境准备

  • 安装 MongoDB 并配置好环境变量
  • 确保有 10GB 以上的硬盘空间

(1)准备配置文件
复制集的每个 mongod 进程应该位于不同的服务器。我们现在在一台机器上运行 3 个进程,因此要为它们各自配置:

  • 不同的端口(28017/28018/28019)
  • 不同的数据目录
mkdir -p /data/db{1,2,3}
  • 不同日志文件路径(例如:/data/db1/mongod.log)

创建配置文件/data/db1/mongod.conf,内容如下:

# /data/db1/mongod.conf
systemLog:
  destination: file
  path: /data/db1/mongod.log # log path
  logAppend: true
storage:   
  dbPath: /data/db1 # data directory      
net:
  bindIp: 0.0.0.0
  port: 28017 # port
replication:
  replSetName: rs0  
processManagement:
  fork: true

参考上面配置修改端口、路径,依次配置db2、db3。注意必须是 yaml 格式。

(2)启动 MongoDB 进程

mongod -f /data/db1/mongod.conf 
mongod -f /data/db2/mongod.conf 
mongod -f /data/db3/mongod.conf

注意:如果启用了 SELinux,可能阻止上述进程启动。简单起见请关闭 SELinux。

# 永久关闭,将SELINUX=enforcing改为SELINUX=disabled,设置后需要重启才能生效
vim /etc/selinux/config
# 查看SELINUX
/usr/sbin/sestatus -v

配置复制集

复制集通过 mongosh 的 rs.initiate() 进行初始化,初始化后各个成员间开始发送心跳消息,并发起 Priamry 选举操作,获得大多数成员投票支持的节点,会成为 Primary,其余节点成为 Secondary。

# mongosh --port 28017 
# 初始化复制集
> rs.initiate({
    _id: "rs0",
    members: [{
        _id: 0,
        host: "192.168.65.174:28017"
    },{
        _id: 1,
        host: "192.168.65.174:28018"
    },{
        _id: 2,
        host: "192.168.65.174:28019"
    }]
})

验证主从节点读写操作:

  • MongoDB 主节点进行写入
# mongosh --port 28017
rs0 [direct: primary] test> db.user.insertMany([{name:"firechou"},{name:"monkey"}])
  • 切换到从节点写入,抛出异常 MongoBulkWriteError: not primary
# mongosh --port 28018  
rs0 [direct: secondary] test> db.user.insertMany([{name:"firechou"},{name:"monkey"}])
  • MongoDB 从节点进行读
# mongosh --port 28018
# 指定从节点可读
rs0:SECONDARY> rs.secondaryOk()
rs0:SECONDARY> db.user.find()

复制集状态查询

  • 查看复制集整体状态:
rs.status()

可查看各成员当前状态,包括是否健康,是否在全量同步,心跳信息,增量同步信息,选举信息,上一次的心跳时间等。
image.png
说明:

members 一列体现了所有复制集成员的状态,主要如下:
health:成员是否健康,通过心跳进行检测。
state/stateStr:成员的状态,PRIMARY 表示主节点,而 SECONDARY 则表示备节点,如果节点出现故障,则可能出现一些其他的状态,例如 RECOVERY。
uptime:成员的启动时间。
optime/optimeDate:成员同步最后一条 oplog 的时间。
optimeDurable/optimeDurableDate:成员同步最后一条 oplog 持久化的时间。
pingMs:成员与当前节点的 ping 时延。
syncingTo:成员的同步来源。

  • 查看当前节点角色:
db.isMaster()

除了当前节点角色信息,是一个更精简化的信息,也返回整个复制集的成员列表,真正的 Primary 是谁,协议相关的配置信息等,Driver 在首次连接复制集时会发送该命令。

Mongos 复制集常用命令:

**命令 **描述
rs.add()为复制集新增节点
rs.addArb()为复制集新增一个 arbiter
rs.conf()返回复制集配置信息
rs.freeze()防止当前节点在一段时间内选举成为主节点
rs.help()返回 replica set 的命令帮助
rs.initiate()初始化一个新的复制集
rs.printReplicationInfo()以主节点的视角返回复制的状态报告
rs.printSecondaryReplicationInfo()以从节点的视角返回复制状态报告
rs.reconfig()通过重新应用复制集配置来为复制集更新配置
rs.remove()从复制集中移除一个节点
rs.secondaryOk()为当前的连接设置 从节点可读
rs.status()返回复制集状态信息
rs.stepDown()让当前的 primary 变为从节点并触发
electionrs.syncFrom()设置复制集节点从哪个节点处同步数据,将会覆盖默认选取逻辑

安全认证

创建用户

在主节点服务器上,启动 mongo

use admin

# 创建用户
db.createUser( {
    user: "firechou",
    pwd: "firechou",
     roles: [ { role: "clusterAdmin", db: "admin" } ,
         { role: "userAdminAnyDatabase", db: "admin"},
         { role: "userAdminAnyDatabase", db: "admin"},
         { role: "readWriteAnyDatabase", db: "admin"}]
})

创建 keyFile 文件

keyFile 文件的作用:集群之间的安全认证,增加安全认证机制 KeyFile(开启 keyfile 认证就默认开启了 auth 认证了)。

# mongo.key采用随机算法生成,用作节点内部通信的密钥文件。
openssl rand -base64 756 > /data/mongo.key
# 权限必须是600
chmod 600 /data/mongo.key  

注意:创建 keyFile 前,需要先停掉复制集中所有主从节点的 mongod 服务,然后再创建,否则有可能出现服务启动不了的情况。
将主节点中的 keyfile 文件拷贝到复制集其他从节点服务器中,路径地址对应 mongo.conf 配置文件中的 keyfile 字段地址,并设置 keyfile 权限为600。

启动 mongod

# 启动mongod
mongod -f /data/db1/mongod.conf --keyFile /data/mongo.key
mongod -f /data/db2/mongod.conf --keyFile /data/mongo.key
mongod -f /data/db3/mongod.conf --keyFile /data/mongo.key

测试

# 进入主节点
mongosh --port 28017

报错,提示没有权限。

# 进入主节点
mongosh --port 28017 -u firechou -p firechou --authenticationDatabase=admin

正常展示查询结果。

复制集连接方式

方式一:
直接连接 Primary 节点,正常情况下可读写 MongoDB,但主节点故障切换后,无法正常访问。

mongosh -u firechou -p firechou 192.168.65.206:28018

方式二(强烈推荐):
通过高可用 Uri 的方式连接 MongoDB,当 Primary 故障切换后,MongoDB Driver 可自动感知并把流量路由到新的 Primary 节点。

mongosh mongodb://firechou:firechou@192.168.65.206:28017,192.168.65.206:28018,192.168.65.206:28019/admin?replicaSet=rs0

springboot 操作复制集配置:

spring:
  data:
    mongodb:
        uri: mongodb://firechou:firechou@192.168.65.174:28017,192.168.65.174:28018,192.168.65.174:28019/test?authSource=admin&replicaSet=rs0

复制集成员角色

复制集里面有多个节点,每个节点拥有不同的职责。
在看成员角色之前,先了解两个重要属性:

属性一:Priority = 0

当 Priority 等于 0 时,它不可以被复制集选举为主,Priority 的值越高,则被选举为主的概率更大。通常,在跨机房方式下部署复制集可以使用该特性。假设使用了机房 A 和机房 B,由于主要业务与机房 A 更近,则可以将机房 B 的复制集成员 Priority 设置为 0,这样主节点就一定会是 A 机房的成员。

属性二:Vote = 0

不可以参与选举投票,此时该节点的 Priority 也必须为 0,即它也不能被选举为主。由于一个复制集中最多只有 7 个投票成员,因此多出来的成员则必须将其 vote 属性值设置为 0,即这些成员将无法参与投票。

成员角色

  • Primary

主节点,其接收所有的写请求,然后把修改同步到所有备节点。一个复制集只能有一个主节点,当主节点“挂掉”后,其他节点会重新选举出来一个主节点。

  • Secondary

备节点,与主节点保持同样的数据集。当主节点“挂掉”时,参与竞选主节点。分为以下三个不同类型:
Hidden = false:正常的只读节点,是否可选为主,是否可投票,取决于 Priority,Vote 的值;
Hidden = true:隐藏节点,对客户端不可见,可以参与选举,但是 Priority 必须为 0,即不能被提升为主。由于隐藏节点不会接受业务访问,因此可通过隐藏节点做一些数据备份、离线计算的任务,这并不会影响整个复制集。
Delayed :延迟节点,必须同时具备隐藏节点和 Priority0 的特性,会延迟一定的时间(secondaryDelaySecs 配置决定)从上游复制增量,常用于快速回滚场景。

  • Arbiter(仲裁)

仲裁节点,只用于参与选举投票,本身不承载任何数据,只作为投票角色。比如你部署了2个节点的复制集,1 个 Primary,1 个 Secondary,任意节点宕机,复制集将不能提供服务了(无法选出 Primary),这时可以给复制集添加?个 Arbiter 节点,即使有节点宕机,仍能选出 Primary。Arbiter 本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入?个 Arbiter 节点,以提升复制集可用性。

配置隐藏节点

很多情况下将节点设置为隐藏节点是用来协助 delayed members 的。如果我们仅仅需要防止该节点成为主节点,我们可以通过 priority 0 member 来实现。

cfg = rs.conf()
cfg.members[1].priority = 0
cfg.members[1].hidden = true
rs.reconfig(cfg)

设置完毕后,该从节点的优先级将变为 0 来防止其升职为主节点,同时其也是对应用程序不可见的。在其他节点上执行 db.isMaster() 将不会显示隐藏节点。

配置延时节点

当我们配置一个延时节点的时候,复制过程与该节点的 oplog 都将延时。延时节点中的数据集将会比复制集中主节点的数据延后。举个例子,现在是 09:52,如果延时节点延后了 1 小时,那么延时节点的数据集中将不会有 08:52 之后的操作。

cfg = rs.conf()
cfg.members[1].priority = 0
cfg.members[1].hidden = true
# 延迟1分钟
cfg.members[1].secondaryDelaySecs = 60
rs.reconfig(cfg)

查看复制延迟:
如果希望查看当前节点 oplog 的情况,则可以使用rs.printReplicationInfo()命令。
这里清晰地描述了 oplog 的大小、最早一条 oplog 以及最后一条 oplog 的产生时间,log length start to end所指的是一个复制窗口(时间差)。通常在 oplog 大小不变的情况下,业务写操作越频繁,复制窗口就会越短。
在节点上执行rs.printSecondaryReplicationInfo()命令,可以一并列出所有备节点成员的同步延迟情况。

添加投票节点

# 为仲裁节点创建数据目录,存放配置数据。该目录将不保存数据集
mkdir /data/arb
# 启动仲裁节点,指定数据目录和复制集名称
mongod --port 30000 --dbpath /data/arb --replSet rs0 
# 进入mongo shell,添加仲裁节点到复制集
rs.addArb("ip:30000")

如果添加节点遇到下面的错误:

MongoServerError: 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.
# 执行命令
db.adminCommand( {"setDefaultRWConcern" : 1, "defaultWriteConcern" : { "w" : 2 } } )

移除复制集节点

使用 rs.remove() 来移除节点

# 1.关闭节点实例
# 2.连接主节点,执行下面命令
rs.remove("ip:port")

通过 rs.reconfig() 来移除节点

# 1.关闭节点实例
# 2.连接主节点,执行下面命令
cfg = rs.conf()
cfg.members.splice(2,1) # 从2开始移除1个元素
rs.reconfig(cfg)

更改复制集节点

cfg = rs.conf()
cfg.members[0].host = "ip:port"
rs.reconfig(cfg)
文章来源:https://blog.csdn.net/u010355502/article/details/135444015
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。