MongoDB复制集架构

在生产环境中,不建议使用单机版的 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:[email protected]:28017,192.168.65.206:28018,192.168.65.206:28019/admin?replicaSet=rs0

springboot 操作复制集配置:

spring:
  data:
    mongodb:
        uri: mongodb://firechou:[email protected]: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)

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>