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")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~