# 副本集 - Replica Sets
# 简介
MongoDB 中的副本集(Replica Set)是一组维护相同数据集的 mongod 服务, 副本集可提供冗余和高可用性,是所有生产部署的基础
副本集类似于有自动故障恢复功能的主从集群,通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载
# 副本集三个角色
# 主要成员(Primary)
主要接收所有写操作,就是主节点
# 副本成员(Replicate)
从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但是可以读操作(需要配置),是啥默认的一种节点类型
# 仲裁者(Arbiter)
不保留任何数据的副本,只具有投票选举作用,当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以师仲裁者,也是一种节点类型
![image-20230715101754912]()
# 副本集架构
![image-20230715101849830]()
# 副本集的创建
# 创建主节点
# 创建目录
| |
| |
| mkdir -p /mongodb/replica_sets/myrs_27017/log \ & |
| mkdir -p /mongodb/replica_sets/myrs_27017/data/db |
# 新建或修改配置文件
| vim /mongodb/replica_sets/myrs_27017/mongod.conf |
# 配置文件内容
| systemLog: |
| |
| destination: file |
| |
| path: "/mongodb/replica_sets/myrs_27017/log/mongod.log" |
| |
| logAppend: true |
| storage: |
| |
| dbPath: "/mongodb/replica_sets/myrs_27017/data/db" |
| journal: |
| |
| enabled: true |
| processManagement: |
| |
| fork: true |
| |
| pidFilePath: "/mongodb/replica_sets/myrs_27017/log/mongod.pid" |
| net: |
| |
| |
| |
| bindIp: localhost,192.168.0.2 |
| |
| |
| port: 27017 |
| replication: |
| |
| replSetName: myrs |
# 启动节点服务
| /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27017/mongod.conf |
# 创建副本节点
# 建立存放数据和日志的目录
| |
| |
| mkdir -p /mongodb/replica_sets/myrs_27018/log \ & |
| mkdir -p /mongodb/replica_sets/myrs_27018/data/db |
# 新建或修改配置文件
| vim /mongodb/replica_sets/myrs_27018/mongod.conf |
# 配置文件内容
| systemLog: |
| |
| destination: file |
| |
| path: "/mongodb/replica_sets/myrs_27018/log/mongod.log" |
| |
| logAppend: true |
| storage: |
| |
| dbPath: "/mongodb/replica_sets/myrs_27018/data/db" |
| journal: |
| |
| enabled: true |
| processManagement: |
| |
| fork: true |
| |
| pidFilePath: "/mongodb/replica_sets/myrs_27018/log/mongod.pid" |
| net: |
| |
| |
| |
| bindIp: localhost,192.168.0.2 |
| |
| |
| port: 27018 |
| replication: |
| |
| replSetName: myrs |
# 启动节点服务
| /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf |
# 创建仲裁节点
# 创建目录
| |
| |
| mkdir -p /mongodb/replica_sets/myrs_27019/log \ & |
| mkdir -p /mongodb/replica_sets/myrs_27019/data/db |
# 修改配置文件
| vim /mongodb/replica_sets/myrs_27019/mongod.conf |
# 配置文件内容
| systemLog: |
| |
| destination: file |
| |
| path: "/mongodb/replica_sets/myrs_27019/log/mongod.log" |
| |
| logAppend: true |
| storage: |
| |
| dbPath: "/mongodb/replica_sets/myrs_27019/data/db" |
| journal: |
| |
| enabled: true |
| processManagement: |
| |
| fork: true |
| |
| pidFilePath: "/mongodb/replica_sets/myrs_27019/log/mongod.pid" |
| net: |
| |
| |
| |
| bindIp: localhost,192.168.0.2 |
| |
| |
| port: 27019 |
| replication: |
| |
| replSetName: myrs |
# 启动节点服务
| /usr/local/mongodb/bin/mongod -f /mongodb/replica_sets/myrs_27019/mongod.conf |
# 初始化副本集和主节点
# 连接主节点
| /usr/local/mongodb/bin/mongo --host=180.76.159.126 --port=27017 |
# 语法
| rs.initiate(configuration) |
# 参数
Parameter |
Type |
Description |
configuration |
document |
|
# 示例
# 查看副本集配置内容
# 语法
# 示例
| myrs:PRIMARY> rs.conf() |
| { |
| "_id" : "myrs", |
| "version" : 1, |
| "protocolVersion" : NumberLong(1), |
| "writeConcernMajorityJournalDefault" : true, |
| "members" : [ |
| { |
| "_id" : 0, |
| "host" : "180.76.159.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("5d539bdcd6a308e600d126bb") |
| } |
| } |
# 参数说明
"id": "myrs"
:副本集配置数据存储的主键值,默认是副本集的名字
"members"
:副本集成员数组,此时只有一个: "host":"180.76.159.126:27017"
,该成员是仲裁节点: "arbiterOnly":false
,优先级(权重值): "priority":1
"settings"
:副本集的参数配置
# 查看副本集状态
# 语法
# 示例
| rs.status() |
| { |
| "set" : "myrs", |
| "date" : ISODate("2019-08-14T05:29:45.161Z"), |
| "myState" : 1, |
| "term" : NumberLong(1), |
| "syncingTo" : "", |
| "syncSourceHost" : "", |
| "syncSourceId" : -1, |
| "heartbeatIntervalMillis" : NumberLong(2000), |
| "optimes" : { |
| "lastCommittedOpTime" : { |
| "ts" : Timestamp(1565760578, 1), |
| "t" : NumberLong(1) |
| }, |
| "readConcernMajorityOpTime" : { |
| "ts" : Timestamp(1565760578, 1), |
| "t" : NumberLong(1) |
| }, |
| "appliedOpTime" : { |
| "ts" : Timestamp(1565760578, 1), |
| "t" : NumberLong(1) |
| }, |
| "durableOpTime" : { |
| "ts" : Timestamp(1565760578, 1), |
| "t" : NumberLong(1) |
| } |
| }, |
| "lastStableCheckpointTimestamp" : Timestamp(1565760528, 1), |
| "members" : [ |
| { |
| "_id" : 0, |
| "name" : "180.76.159.126:27017", |
| "health" : 1, |
| "state" : 1, |
| "stateStr" : "PRIMARY", |
| "uptime" : 419, |
| "optime" : { |
| "ts" : Timestamp(1565760578, 1), |
| "t" : NumberLong(1) |
| }, |
| "optimeDate" : ISODate("2019-08-14T05:29:38Z"), |
| "syncingTo" : "", |
| "syncSourceHost" : "", |
| "syncSourceId" : -1, |
| "infoMessage" : "could not find member to sync from", |
| "electionTime" : Timestamp(1565760476, 2), |
| "electionDate" : ISODate("2019-08-14T05:27:56Z"), |
| "configVersion" : 1, |
| "self" : true, |
| "lastHeartbeatMessage" : "" |
| } |
| ], |
| "ok" : 1, |
| "operationTime" : Timestamp(1565760578, 1), |
| "$clusterTime" : { |
| "clusterTime" : Timestamp(1565760578, 1), |
| "signature" : { |
| "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), |
| "keyId" : NumberLong(0) |
| } |
| } |
| } |
# 参数说明
"set":"myrs"
:副本集的名字
"myStatus":1
:说明状态正常
"numbers"
:副本集成员数组,此时只有一个: "name":"180.76.156.154:27017"
,该成员角色是 "stateStr":"PRIMARY"
,该节点是健康的: "health":1
# 添加副本从节点
# 语法
| rs.add(host, arbiterOnly) |
# 示例
| myrs:PRIMARY> rs.add("180.76.159.126:27018") |
| { |
| "ok" : 1, |
| "operationTime" : Timestamp(1565761757, 1), |
| "$clusterTime" : { |
| "clusterTime" : Timestamp(1565761757, 1), |
| "signature" : { |
| "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), |
| "keyId" : NumberLong(0) |
| } |
| } |
| } |
# 添加仲裁从节点
# 语法
# 示例
| myrs:PRIMARY> rs.addArb("180.76.159.126:27019") |
| { |
| "ok" : 1, |
| "operationTime" : Timestamp(1565761959, 1), |
| "$clusterTime" : { |
| "clusterTime" : Timestamp(1565761959, 1), |
| "signature" : { |
| "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), |
| "keyId" : NumberLong(0) |
| } |
| } |
| } |
# 副本集的读写操作
# 登录主节点
| /usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27017 |
# 登录从节点
| /usr/local/mongodb/bin/mongo --host 180.76.159.126 --port 27018 |
# 设置读操作权限
# 主节点的选举原则
# 修改优先级
# 先配置导入 cfg 变量
| myrs:SECONDARY> cfg=rs.conf() |
# 然后修改值
| myrs:SECONDARY> cfg.members[1].priority=2 |
# 重新加载配置
| myrs:SECONDARY> rs.reconfig(cfg) |
| { "ok" : 1 } |
# 故障测试
# 副本节点故障测试
关闭 27018 副本节点:发现,主节点和仲裁节点对 27018 的心跳失败,因为主节点还在,因此,没有触发投票选举,如果此时,在主节点写入数据,再启动从节点,会发现,主节点写入的数据会同步给从节点
| db.comment.insert({"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"}) |
# 主节点故障测试
关闭 27017 节点发现,从节点和仲裁节点对 27017 的心跳失败,当失败超过 10 秒,此时因为没有主节点了,会自动发起投票,而副本节点只有 27018,因此,候选人只有一个就是 27018,开始投票,27019 向 27018 投了一票,27018 本身自带一票,因此共两票,超过了 “大多数” 27019 是仲裁节点,没有选举权,27018 不向其投票,其票数是 0,最终结果,27018 成为主节点。具备读写功能,在 27018 写入数据查看再启动 27017 节点,发现 27017 变成了从节点,27018 仍保持主节点,登录 27017 节点,发现是从节点了,数据自动从 27018 同步,,从而实现了高可用
| db.comment.insert({"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"}) |
# 仲裁节点和主节点故障
先关掉仲裁节点 27019,关掉现在的主节点 27018,登录 27017 后,发现,27017 仍然是从节点,副本集中没有主节点了,导致此时,副本集是只读状态,无法写入,为啥不选举了?因为 27017 的票数,没有获得大多数,即没有大于等于 2,它只有默认的一票(优先级是 1)如果要触发选举,随便加入一个成员即可:
- 如果只加入 27019 仲裁节点成员,则主节点一定是 27017,因为没得选了,仲裁节点不参与选举,但参与投票。
- 如果只加入 27018 节点,会发起选举。因为 27017 和 27018 都是两票,则按照谁数据新,谁当主节点
# 仲裁节点和从节点故障
先关掉仲裁节点 27019,关掉现在的副本节点 27018,10 秒后,27017 主节点自动降级为副本节点(服务降级),副本集不可写数据了,已经故障了
# SpringDataMongoDB 连接副本集
# 基本语法
| mongodb://host1,host2,host3/articledb? |
| connect=replicaSet&slaveOk=true&replicaSet=副本集名字 |
slaveOk=true
:开启副本节点读的功能,可实现读写分离
connect=replicaSet
:自动到副本集合中选择读写的主机,如果 slaveOk
是打开的,则实现了读写分离
# 示例
| spring: |
| |
| data: |
| mongodb: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| uri: mongodb://180.76.159.126:27017,180.76.159.126:27018,180.76.159.126:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs |
# 分片集群
# 分片概念
分片(sharding)是一种跨多台机器分布数据的方法, MongoDB 使用分片来支持具有非常大的数据集和高吞吐量操作的部署
# 分片集群组件
# 分类
- 分片(存储):每个分片包含分片数据的子集,每个分片都可以部署为副本集
- mongos(路由):mongos 充当查询路由器,在客户应用程序和分片集群之间提供接口
- config servers(调度的配置):配置服务器存储集群的元数据和配置设置,从 MongoDB 3.4 开始,必须将配置服务器部署为副本集(CSRS)
# 交互图解
![image-20230715111117325]()
# 分片集群架构目标
![image-20230715111156970]()
# 分片(存储)节点到副本集的创建
# 配置节点副本集的创建
# 路由节点的创建和操作
# 第一个路由节点的创建和连接
# 创建目录
| |
| mkdir -p /mongodb/sharded_cluster/mymongos_27017/log |
# 修改配置文件
| vi /mongodb/sharded_cluster/mymongos_27017/mongos.conf |
# 配置文件 mongos.conf
| systemLog: |
| |
| destination: file |
| |
| path: "/mongodb/sharded_cluster/mymongos_27017/log/mongod.log" |
| |
| logAppend: true |
| processManagement: |
| |
| fork: true |
| |
| pidFilePath: /mongodb/sharded_cluster/mymongos_27017/log/mongod.pid" |
| net: |
| |
| |
| |
| bindIp: localhost,192.168.0.2 |
| |
| |
| port: 27017 |
| sharding: |
| |
| configDB: |
| myconfigrs/180.76.159.126:27019,180.76.159.126:27119,180.76.159.126:27219 |
# 启动 mongos
| /usr/local/mongodb/bin/mongos -f /mongodb/sharded_cluster/mymongos_27017/mongos.conf |
# 在路由节点上进行分片配置操作
# 添加分片
# SpringData 连接分片集群
| spring: |
| |
| data: |
| mongodb: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| uri: mongodb://180.76.159.126:27017,180.76.159.126:27117/articledb |
# 安全认证
# MongoDB 用户和角色权限简介
MongoDB 实例启动运行时是没有启用用户访问权限控制的,也就是说,在实例本机服务器上都可以随意连接到实例进行各种操作,MongoDB 不会对连接客户端进行用户验证,这是非常危险的
# 操作权限命令
| |
| db.runCommand({ rolesInfo: 1 }) |
| |
| db.runCommand({ rolesInfo: 1, showBuiltinRoles: true }) |
| |
| db.runCommand({ rolesInfo: "<rolename>" }) |
| |
| db.runCommand({ rolesInfo: { role: "<rolename>", db: "<database>" } } |
| |
| db.runCommand( |
| { |
| rolesInfo: [ |
| "<rolename>", |
| { role: "<rolename>", db: "<database>" }, |
| ... |
| ] |
| } |
| ) |
# 数据库角色分类
- 数据库管理角色:dbAdmin、dbOwner、userAdmin
- 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
- 备份恢复角色:backup、restore
- 超级用户角色:root
- 内部角色:system