258_Mongodb_集合_副本集2

网友投稿 550 2022-05-29

MongoDB副本集模式

通过实时数据同步提高数据的可用性, 包括写入策略(write concern) 和 读取策略(read preference)来提升数据的读写性能

1 副本集角色

主节点(primary)

副节点(secondary)

仲裁节点(Arbiter)

一个副本集, 至少包括一个主节点(primary), 与一个副节点(secondary),通过不同的节点与数量,可以配置不同效果的副本集

主节点与副节点

主节点与副节点均属于数据节点,保存完整的数据

主节点: 接收数据写入需求, 然后通过同步机制同步到所有的副节点, 节点通过”心跳”机制进行沟通, 确保所有节点正常运行

仲裁节点 当主宕机后, 参与投票,选出新主,本身不存储数据, 这样在资源有限的情况下 给了副本集模式很大弹性

副本集的基本架构: 1个主节点 + 1个副节点 + 一个冲裁节点 (奇数 3个具有投票权的节点 可进行有效的投票)

2 高可用(节点故障转移)

在副本集中实现高可用 通过以下重要机制

Oplog 同步

心跳机制(Hearbeat)

选举策略(vote)

副本集回滚(RollBack)

Oplog 同步

主节点的oplog异步同步到从节点,副本集可以在一个或多个成员失败的情况下继续运行 从数据库成员将这些操作复制并应用本身。所有副本集成员都将心跳(ping)发送给所有其他成员,任何从成员都可以从任何其他成员应用操作日志,如果副本集只剩一个节点,该节点会变成从节点(不能写)操作日志中的每个操作都是幂等的,也就是说oplog操作会产生相同的结果,无论是一次还是多次应用于目标数据集

Oplog(操作日志)是一个特殊的capped集合,保持所有修改存储在数据库中的数据的操作的记录,类似于MySQL的Binlog

Oplog 记录操作记录, 是副本集成员特有集合,默认固定大小(5% 且不超过50G)可以通过oplogSizeMB 进行设置, 此参数仅在集群初始化前配置有效, 一旦创建完成无法进行修改

Oplog 本质是一个Capped Collections(环形队列), 新操作进来,会写入下一个位置(偏移量 & 时间戳)

Oplog 会被记录在数据节点 local库中 oplog.rs的集合中

Oplog 初始化

新加入副本节点如果落后primary太多, 会从副本节点进行完整的数据复制(整个数据文件&oplog, 新节点用全备进行创建,然后构建主从)

258_Mongodb_集合_副本集2

Oplog 同步

节点同步会对比其它节点状态, 选择数据比自己更完整的节点作为同步源进行同步(可指定:use admin; db.adminCommad({replSetSyncFrom: “hostname<:port>”}))

设置同步源后三种情况会恢复默认同步机制:

此节点实例重新启动

此节点与同步源节点之间断开连接

同步源节点数据落后其它副本节点超过30S

Oplog状态查看

rs.printReplicationInfo() 查看oplog的状态,输出信息包括oplog日志大小,操作日志记录的起始时间 configured oplog size: oplog文件大小 log length start to end: oplog日志的启用时间段 oplog first event time: 第一个事务日志的产生时间 oplog last event time: 最后一个事务日志的产生时间 now: 现在的时间

db.getReplicationInfo() 可以用来查看oplog的状态、大小、存储的时间范围 在primary/secondary上查看从库落后信息 rs.printSlaveReplicationInfo() 查看slave状态 通过"db.printSlaveReplicationInfo()"可以查看slave的同步状态 副本节点中执行db.printSlaveReplicationInfo()命令可以查看同步状态信息 source——从库的IP及端口 syncedTo——当前的同步情况,延迟了多久等信息

bertram:PRIMARY> use local; switched to db local bertram:PRIMARY> show tables; me oplog.rs replset.election replset.minvalid startup_log system.profile system.replset local库下面的me集合保存了服务器名称 local库下面的replset.minvalid集合保存了数据库最新操作的时间戳 local库下面的startup_log集合记录这mongod每一次的启动信息 local库下面的system.indexes集合记录当前库的所有索引信息 local库下面的system.replset记录着复制集的成员配置信息rs.conf()读取这个集合 local库下面的oplog.rs集合记录着所有操作,MongoDB就是通过oplog.rs来实现数据同步的。当Primary节点插入一条数据后,oplog.rs集合中就会多一条记录 bertram:PRIMARY> db.oplog.rs.findOne(); { "ts" : Timestamp(1465879171, 238), "h" : NumberLong("-2275413922284641862"), "v" : 2, "op" : "u", "ns" : "MyDB.SyncTable", "o2" : { "_id" : "bbf80260-3d58-49f1-9c8c-e093d5d57527" }, "o" : { "_id" : "bbf80260-3d58-49f1-9c8c-e093d5d57527", "EntityId" : "362569", "TypeName" : "Product", "Times" : 14208, "CreateTime" : ISODate("2014-11-15T14:35:51.916Z"), "LastModified" : ISODate("2016-06-14T04:38:21.708Z"), "LastOperationTime" : ISODate("2016-06-14T04:39:30.957Z") } } 字段含义 ts:8字节的 时间戳,由4字节unix timestamp + 4字节自增计数表示。在选举(如master宕机时)新primary时,会选择ts最大的那个secondary作为新primary。 op:1字节的操作类型,例如i表示insert,d表示delete。 ns:操作所在的namespace。 o:操作所对应的document,即当前操作的内容(比如更新操作时要更新的的字段和值) o2: 在执行更新操作时的条件,仅限于update时才有该属性。 其中op,可以是如下几种情形之一: "i": insert "u": update "d": delete "c": db cmd "db":声明当前数据库 (其中ns 被设置成为=>数据库名称+ '.') "n": no op,即空操作,其会定期执行以确保时效性。修改配置,会产生 "n" 操作

同步过程

大致流程:

检查配置、初始化local库的各个集合、转换各个成员的状态(STARTUP -> STARTUP2 -> RECOVERING -> SECONDARY)、10秒后开始选举(SECONDARY -> PRIMARY)

初始化同步:

复制除local数据库外的所有数据库,mongod扫描每个源数据库中的每个集合,并将所有数据插入这些集合的自己的数据库中

版本3.4中更改:在为每个集合复制文档时,初始同步将构建所有集合索引(先同步索引,再同步数据) 在早期版本中,在此阶段仅构建_id索引(先同步数据,再同步索引)

版本3.4中更改:初始同步在数据复制期间提取新添加的操作日志记录。

确保目标成员在local数据库中具有足够的磁盘空间,以在此数据复制阶段持续时间临时存储这些操作日志记录。

mongod使用源中的操作日志,将所有更改应用于数据集。

初始同步完成后,成员将从STARTUP2转换为SECONDARY。

初始化时,同步源的选择取决于mongod启动参数initialSyncSourceReadPreference的值(4.2.7中的新增功能)。

如果无法选择同步源,将记录错误并等待1秒钟,然后重新选择,从mongod最多可以重新初始同步源选择过程10次,然后错误退出。

复制:多线程

MongoDB使用多线程批量应用写入操作以提高并发性。 MongoDB按文档ID(WiredTiger)对批次进行分组,并同时使用不同的线程来应用每组操作,MongoDB始终以原始写入顺序对给定文档应用写入操作

副本集的完整配置信息和状态

副本集的完整配置信息和状态通过 rs.status & db.admincommand({replSetGetStatus : 1 }) 查看

https://docs.mongodb.com/manual/reference/command/replSetGetStatus/#std-label-rs-status-output

rs.status命令新增了一些可参考监控项,例如:

replSetGetStatus.optimes.lastCommittedOpTime:已写入大多数副本集成员的最新操作时间;

replSetGetStatus.optimes.appliedOpTime:已应用于副本集的该成员的最新操作时间;

replSetGetStatus.optimes.durableOpTime:已写入该副本集的该成员的journal日志的时间

MongoDB数据节点状态编号

状态值

状态名

状态说明

0

STARTUP

节点刚启动未完成加载副本集,配置初期为该状态

1

PRIMARY

有投票权主节点状态,唯一支持写的节点。有投票资格

2

SECONDARY

有投票权 副本节点状态,可进行数据同步,拥有投票权

3

RECOVERING

有投票权 特殊原因导致数据落后,节点自我检查/修复,无法读取数据

5

STARTUP2

有投票权 节点加载完副本集配置,并已经运行初始同步

6

UNKNOWN

无投票权 从副本集的另一个成员的角度来看,该成员的状态尚不清楚

7

ARBITER

有投票权 仲裁节点

8

DOWN

无投票权 节从副本集的另一个成员的角度来看,该成员不可访问。例网络问题

9

ROLLBACK

有投票权 执行回滚, 暂不能读取数据,回滚后进入recovering状态

10

REMOVED

节点曾在副本集中, 但被移除

非投票成员的属性如

{ "_id" : , "host" : , "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 0, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 0 }

rs.status() { "set" : "replset", "date" : ISODate("2019-12-04T04:49:18.693Z"), "myState" : 1, "term" : NumberLong(3), # 代表副本集成员数量 "syncingTo" : "", "syncSourceHost" : "", # 代表primary "syncSourceId" : -1, # 代表primary "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { #已写入大多数副本集成员的最新操作时间 "ts" : Timestamp(1575434954, 1), "t" : NumberLong(3) }, "lastCommittedWallTime" : ISODate("2019-12-04T04:49:14.378Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1575434954, 1), "t" : NumberLong(3) }, "readConcernMajorityWallTime" : ISODate("2019-12-04T04:49:14.378Z"), "appliedOpTime" : { #已应用于副本集的该成员的最新操作时间 "ts" : Timestamp(1575434954, 1), "t" : NumberLong(3) }, "durableOpTime" : { #已写入该副本集的该成员的journal日志的时间 "ts" : Timestamp(1575434954, 1), "t" : NumberLong(3) }, "members" : [ { "_id" : 0, "name" : "m1.example.net:27017", "ip" : "198.51.100.1", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2019, "optime" : { "ts" : Timestamp(1575434954, 1), "t" : NumberLong(3) }, "optimeDate" : ISODate("2019-12-04T04:49:14Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1575434944, 1), "electionDate" : ISODate("2019-12-04T04:49:04Z"), "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" },

3 选举和投票机制

选举(election)与投票(Vote)机制, MongoDB primary发生异常时, 促使副本集自动修复, 从有投票权中的secondary节点挑选出最适合的节点来接替primary工作

投票机制:大多数原则 (总节点数/2) +1 取整数; 例 5个节点的副本集,5/2+1=3; 至少得三票,最高可以容错2台机器down掉

4 回滚机制

Primary A写操作未同步给secondary节点,网络异常导致中断, secondary选取新主primary B,原A 扔写入数据 加入副本集后 成为secondary 这样数据就有了差异,需要回滚

回滚的前提

在同步源上没有查到比其更新的oplog(我们刚刚通过一系列麻烦的规则选出它作为同步源,但是我们的oplog却比它还新)

返回的的第一条oplog和其最新的oplog的OpTime和hash都不同,注意这里是比较整个OpTime,即除了时间戳之外还包括term,首先会比较term,如果term不同,那就不同

大概流程: 首先找到B与A的共同操作点,A将共同操作点后的操作写入 rollback目录下的BSON文件文件, 并撤销Oplog记录, 然后继续同步B节点数据

BSON 文件格式:...bason

回滚的限制

4.0 之后版本,回滚数量无限制, 回滚时间默认24h (rollbackTimeLimitSecs)

4.0 之前版本, 数量不能超过300M  回滚时间不能超过30min

5 数据读写策略

5.1 写入策略(write Concern)

不同场景对应写入策略不同,要求最终一致性(日志业务),要求很高的响应时间(支付业务)

客户端 使用write concern来配置,通过写入响应(acknowledgement)层级,决定数据写入何时返给客户端

Write concern 包含字段 {w: <值>, J: <布尔值>, wtimeout:<数字>}

W字段 整数N 表示反馈完成操作必须同步到N个副本集上

1 表只写入主节点

0 不需要写入任何节点, 可能会出现未写入成功但未收到报错信息

大于1 代表必须写入大于1的节点数,不然会报错 “not enough data-bearing nodes at….”

Majority: 写入大多数节点(半数+1 )

J 字段 表示写操作是否需要记录到日志文件中(journal) 若写入日志中,则服务意外时, 可通过日志恢复数据

Wtimeout  表示等待时间阈值,单位ms , 超过阈值代表写入失败

db.collection.insert({name:”alex”},writeConcern:{w:1})  # 代表写入主节点

5.2 读取策略

类似写入策略,可以配置读取策略 Read Concern & Read Preference 非互斥, 可配合使用

Read concern 的作用是让客户端指定什么样的数据可以被读取,如 数据写入primary A 后,A异常,集群重新选B, 则A要回滚,这时A的数据是不可取的

语法

db.collection.find().readConcern()

level参数配置如下

local 从primary节点读取时的默认值, 在未写入大部分节点前就反数据(此做法会导致脏读)

available 从secondary读取的默认值,在未写入大部分节点前就反数据(此做法会导致脏读)

majority  数据操作必须更新至大多数节点才能被读取

linearizable  只允许在主节点读取(readConcern(“majority”)配置时候 能保证读到已经确认的数据且查询结果为单个文档生效)

snapshot  4.0 版本提供 多文档事物中使用

read Preference

配置该参数,可以让客户端驱动知道从哪个节点去读取数据,可以配置读写分离,就近读取数据的负载均衡效果

Mongo.setReadPref(,)

Mode可设置

Primary 主节点读取

PrimaryPreferred  优先从主节点读取,若主节点无法读取, 从副节点读取

Secondary 从副节点读取

SecondaryPreferred 优先从副节点驱动,若无法读取,从primary读取

Nearest 根据网络情况从最近的节点读取, 可搭配知道副本的tags限制读取来源 db.collection.find().readPref(“nearest”,[‘source’:’rpt’])

MongoDB 数据库

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:ModelArts Notebook快速开源项目实战 — U2Net
下一篇:如何进行CAE分析?
相关文章