MongoDB分布式原理以及read-preference和readConcern解决读写一致性问题

MongoDB词汇表:

https://docs.mongodb.com/manual/reference/glossary/#term-replica-set

 

MongoDB分布式原理

primary

In a replica set, the primary is the member that receives all write operations. See Primary.

副本集中主库是接收所有写操作的节点。

secondary

replica set member that replicates the contents of the master database. Secondary members may handle read requests, but only the primary members can handle write operations. See Secondaries.

一个副本集,其复制所述主数据库中的内容。次节点:读请求。主库:写操作。

复制

允许多个数据库服务器共享相同数据的功能,从而确保冗余并促进负载平衡。请参见复制

https://docs.mongodb.com/manual/replication/#replication-auto-failover

复制提供冗余并提高 数据可用性。使用不同数据库服务器上的多个数据副本,复制可提供一定程度的容错能力,以防止丢失单个数据库服务器。

在某些情况下,复制可以提供更大的读取容量,因为客户端可以将读取操作发送到不同的服务器。在不同数据中心中维护数据副本可以提高数据本地性和分布式应用程序的可用性。您还可以维护其他副本以用于专用目的,例如灾难恢复,报告或备份。

异步复制

辅助节点复制主节点的操作日志,并将操作异步应用于其数据集。通过使次要节点的数据集反映主要节点的数据集,即使一个或多个成员失败,副本集也可以继续运行。

故障转移

在发生故障时允许副本集辅助成员成为主库成的过程。请参阅自动故障转移

如果主要节点不可用,则符合条件的次要节点将进行选举以自行选举新的主要节点。

自动故障转移
时机:当主节点与集合中的其他成员的通信electionTimeoutMillis时间超过配置的时间段(默认为10秒)时。

由于突发的网络延迟等因素,群集可能会频繁选举,即使该主节点处于健康状态也是如此。

 

方式:合格的辅助节点将要求选举以提名自己为新的主节点。群集尝试完成新主数据库的选择并恢复正常操作。

 

副本集无法处理写入操作直到选举成功完成

如果将副本集配置为在主副本处于脱机状态时在次副本上运行,则副本集可以继续提供读取查询 。

应用程序连接逻辑应包括对自动故障转移和后续选举的容忍度。

从MongoDB 3.6开始,MongoDB驱动程序客户端可以检测到主数据库的丢失,并一次自动 重试某些写入操作,从而提供了自动故障转移和选择的其他内置处理。

https://docs.mongodb.com/manual/core/retryable-writes/#retryable-writes

 

选举

副本集的成员在启动时和发生故障时选择主库的过程。请参阅 副本集选择

https://docs.mongodb.com/manual/core/replica-set-elections/#replica-set-elections

 

最终一致性

分布式系统的属性,允许对系统的更改逐渐传播。在数据库系统中,这意味着不需要可读成员始终反映最新的写入。

====================

readPreference和readConcern配合使用

  • readPreference 主要控制客户端 Driver 从复制集的哪个节点读取数据,这个特性可方便的实现读写分离、就近读取等策略。

    • primary 只从 primary 节点读数据,这个是默认设置
    • primaryPreferred 优先从 primary 读取,primary 不可服务,从 secondary 读
    • secondary 只从 scondary 节点读数据
    • secondaryPreferred 优先从 secondary 读取,没有 secondary 成员时,从 primary 读取
    • nearest 根据网络距离就近读取
  • readConcern 决定到某个读取数据时,能读到什么样的数据。

    • local 能读取任意数据,这个是默认设置
    • majority 只能读取到『成功写入到大多数节点的数据』

========================

read-preference

官网地址:https://docs.mongodb.com/manual/core/read-preference/

读取首选项描述了MongoDB客户端如何将读取操作路由到副本集的成员。

默认情况下,应用程序将其读取操作定向到副本集中的 主要成员(即读取首选项模式“主要”)。但是,客户端可以指定读取首选项,以将读取操作发送到辅助对象。

读取首选项模式描述
primary

默认模式。所有操作均从当前副本集primary读取 。

包含读取操作的多文档事务必须使用读取首选项primary。给定事务中的所有操作必须路由到同一成员。

primaryPreferred在大多数情况下,操作从主服务器读取,但如果不可用,则从辅助 成员读取操作。
secondary所有操作均从副本集的辅助成员读取。
secondaryPreferred在大多数情况下,操作会从辅助 成员读取,但如果没有辅助成员可用,则操作会从primary读取。
nearest

副本集的成员读取的操作具有最小的网络延迟,而与成员的类型无关。

 

==================

readConcern

官网地址:https://docs.mongodb.com/manual/reference/read-concern/

该readConcern选项使您可以控制从副本集和副本集分片读取的数据的一致性和隔离性。

通过有效使用写入关注点和读取关注点,您可以适当地调整一致性和可用性保证的级别,例如等待更强的一致性保证,或者放宽一致性要求以提供更高的可用性。

为MongoDB 3.2或更高版本更新的MongoDB驱动程序支持指定读取关注。

 

readConcern 的是为了在于解决脏读问题,用户从 MongoDB 的 primary 上读的数据并没有同步到大多数节点,然后 primary 宕机恢复, primary节点会将未同步到大多数节点的数据回滚,导致用户读到了脏数据

当指定 readConcern 级别为majority ,能保证用户读到的数据已经写入到大多数节点,而这样的数据肯定不会发生回滚,避免了脏读的问题。

需要注意的是,readConcern 只是保证读到的数据不会发生回滚,但并不能保证读到的数据最新

参考官网:

误区: majority并非从多节点读取,依然是单节点读取。

readConcern 原理

snapshot 0,1,2,3......N的状态是committed/uncommitted

同步到大多数节点时,对应的snapshot会标记为commmited。

用户读取:读最新的 commited 状态的 snapshot,这样就保证了读到的数据是已经同步到大多数节点。

secondary节点在自身oplog发生变化会同步信息到primary。

primary节点统计超过半数的节点的同步信息就修改该snapshot为uncommitted->commited。

同时secondary拉取oplog的同时从primary节点得到最新一条已经同步到大多数节点的oplog,更新自身的 snapshot 状态。

 

参考:

https://yq.aliyun.com/articles/60553

https://yq.aliyun.com/articles/663931

readConcern 主要用于跟 mongos 与 config server 的交互上

当写入新文档时,mongos 从config server 上获取集合的路由表本地,如写入shardX的文档,则请求被路由到shardX上写入。

mongos 从 config server 上获取到路由表后,会缓存在本地内存,避免每次写入/查询都去 config server 上取表。

mongos 在写入时,会带上自身缓存的路由表版本,当请求到达 shard后,shard 发现 mongos 的路由表版本比自己的低,则说明路由表已经发生过更新,这时 mongos 会重新到 config server 上取最新的路由表,然后按新的路由表来写入。

https://yq.aliyun.com/articles/58689

Mongos本身并不持久化数据,Sharded cluster所有的元数据都会存储到Config Server,而用户的数据则会分散存储到各个shard。Mongos启动后,会从config server加载元数据,开始提供服务,将用户的请求正确路由到对应的Shard。

https://yq.aliyun.com/articles/32434

================

Read Concern "majority"

https://docs.mongodb.com/manual/reference/read-concern-majority/index.html

考虑以下写入三个成员副本集的操作Write0的时间轴:

注意 为了简化,该示例假定:

Write0之前的所有写操作已成功复制到所有成员。

Writeprev是Write0之前的上一次写入。

Write0之后未发生其他写操作。

然后,下表总结了在时间T具有“多数”读取关注的读取操作将看到的数据状态。

 

最新数据不在大部分机器: 

 

 

脏数据:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值