5.Mongodb之readConcern模式

在readPreference选择了指定的节点后,readConcern决定这个节点上的数据哪些是可读的,类似于关系数据库中的隔离级别。可选值包括:

  • available:读取所有可用的数据
  • local:读取所有可用且属于当前分片的数据,默认值
  • majority:读取在大多数节点上提交完成的数据
  • linearizable:可线性化读取文档
  • snapshot:读取最近快照中的数据

1.ReadConcern:local和available区别?

在复制集中local和available是没有区别的。两者的区别主要体现在分片集上。考虑以下场景:

  • 一个chunk x正在从shard1向shard2迁移;
  • 整个迁移过程中chunk x中的部分数据会在shard1和shard2中同时存在,但源分片shard1仍然是chunk x的负责方:
    • 所有对chunk x的读写操作仍然进入shard1;
    • config中记录的信息chunk x仍然属于shard 1;
  • 此时如果读shard2,则会体现出local和available的区别:
    •  local:只取应该由shard2负责的数据(不包括x);
    • available:shard2上有什么就读什么(包括x)

如下图:

2.readConcern:majority

这种只会读取大多数节点上都提交了的数据,比如说有以下场景:

  • 集合中院原有文档{x:0}
  • 将x值更新为1;

如果在各个节点应用{readCncern:"majority" }来读取数据的话:

上面的图挺有意思的,看是一定要抓住majority 大多数。

考虑t3时刻的Secondary1,此时:

  • 对于要求majority的读操作,它将返回x=0
  • 对于不要求majority的读操作,它将返回x=1;

如何实现?

节点上维护多个x版本,MVCC机制

mongoDB通过维护多个快照来链接不同的版版:

  • 每个被大多数节点确认过的版本都将是一个快照
  • 快照持续到没有人使用为止才被删除。

实验:readConcern : "majority" vs "local"

1.安装3节点复制集

2.注意配置文件内server参数enableMajorityReadConcern

3.将复制集中的两个从节点使用db.fsyncLock()锁住写入(模拟同步延迟)

readConcern验证:

  1.db.test.insert({x:1})  #主节点

  2.db.fsyncLock()      #两个从节点执行

  3.db.test.insert({x:2}) # 主节点上执行

  4.db.test.find().readConcern("local")   #主节点上执行

  5.db.test.find().readConcern("majority")  #主节点上执行

  实验过程:

  首先在主节点上执行第一条命令

  在两个从节点上执行db.fysncLock()锁住节点,不让这两个从节点写入数据

  然后再在主节点上执行db.test.insert({x:2})插入数据

  最后我们在主节点分别用命令db.test.find().readConcern("local")和db.test.find().readConcern("majority")进行查看

  结果:发现当用local查的时候,有两条数据,但是用majority会发现只有一条数据

rs0:PRIMARY> db.test.find().readConcern("local")
{ "_id" : ObjectId("6267f7725874a8ba78647abd"), "x" : 1 }
{ "_id" : ObjectId("6267f8765874a8ba78647abe"), "x" : 2 }
rs0:PRIMARY> db.test.find().readConcern("majority")
{ "_id" : ObjectId("6267f7725874a8ba78647abd"), "x" : 1 }
rs0:PRIMARY> 

  结论:

  • 使用local参数,则可以直接查询到写入数据
  • 使用majority,只能查询到已经被多数节点确认过的数据
  • update与remove与上同理

MongoDB中的回滚:

  • 写操作到达大多数节点之前都是不安全的,一旦主节点崩溃,而从节点还没有复制到该次操作,刚才的写操作就丢失了。
  • 把一次写操作视为一个事务,从事务的角度,可以认为事务被回滚了。

所以从分布式系统的角度来看,事务的提交被提升到了分布式集群的多个节点级别的"提交",而不再是单个节点上的"提交"

在可能发生回滚的前提下考虑脏读的问题:

  • 如果在一次写操作到达大多数节点前读取了这个写操作,然后因为系统故障该操作回滚了,则发生了脏读问题;

使用{readConcern: "majority"}可以有效闭避免脏读

 

readConcern:如何实现安全的读写分离  

  考虑如下场景:

  向主节点写入一条数据,然后立即从从节点读取这条数据。如果保证自己能够读到刚刚写入的数据?

  有两种方式:

  第一种(这种可能读取不到):

  db.orders.insert({oid:101,sku:'kite',q:1})

  db.orders.find({oid:101}).readPref("secondary")

  第二种(使用writeConcer + readConcern majority)来解决

  db.orders.insert({oid:101,sku:"kiteboar",q:1},{writeConcern:{w:"majority"}})

  db.ordes.find({oid:101}).readPref("secondary").readConcern("majority") 

   

posted on   太白金星有点烦  阅读(838)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示