惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
Jina AI
Jina AI
雷峰网
雷峰网
月光博客
月光博客
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
B
Blog RSS Feed
美团技术团队
C
CXSECURITY Database RSS Feed - CXSecurity.com
小众软件
小众软件
Security Latest
Security Latest
Microsoft Azure Blog
Microsoft Azure Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
Last Week in AI
Last Week in AI
A
Arctic Wolf
Latest news
Latest news
Attack and Defense Labs
Attack and Defense Labs
I
Intezer
F
Fortinet All Blogs
罗磊的独立博客
MongoDB | Blog
MongoDB | Blog
Webroot Blog
Webroot Blog
S
Secure Thoughts
Help Net Security
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
V
Visual Studio Blog
P
Proofpoint News Feed
博客园 - 【当耐特】
P
Privacy International News Feed
V
Vulnerabilities – Threatpost
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
云风的 BLOG
云风的 BLOG
Hacker News: Ask HN
Hacker News: Ask HN
L
LINUX DO - 最新话题
H
Help Net Security
爱范儿
爱范儿
酷 壳 – CoolShell
酷 壳 – CoolShell
S
SegmentFault 最新的问题
Forbes - Security
Forbes - Security
T
Tailwind CSS Blog
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tenable Blog
Cloudbric
Cloudbric
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog

博客园 - Nucky_yang

windows系统下安装openclaw,无权限打开软件,无权限打开浏览器,无权限读写文件的问题。 just a demo presto集成 hive(转载) java可重入锁与不可重入锁 的设计 动态规划 背包问题 java ThreadPoolExecutor线程池在美团的最佳实践 回溯 八皇后问题 与 0-1背包 技术学习 线程间通信 计算机网络基础知识总结(各种协议) 大数据Phoenix专题 ClickHouse深度揭秘 hbase 查询组件phoenix redis的设计与实现 第二版 位图 Java并发编程:volatile关键字解析 socket 多路复用原理和代码 select poll epoll mongDB需要注意的事项和 监控命令mongostat mongotop mongoDB学习 mongo的聚合框架、join
mongoDB的事务
Nucky_yang · 2020-06-21 · via 博客园 - Nucky_yang

官网传送门:

https://docs.mongodb.com/manual/core/replica-set-write-concern/

https://docs.mongodb.com/manual/core/transactions/#read-concern-write-concern-read-preference

MongoDB ACID 多文档事务支持

事务属性 支持程度
Atomocity 原子性 单表单文档 : 1.x 就支持
复制集多表多行:4.0 复制集
分片集群多表多行4.2
Consistency 一致性 writeConcern, readConcern (3.2)
Isolation 隔离性 readConcern (3.2)
Durability 持久性 Journal and Replication

Atomocity 原子性 

一个事务作为一个提交单位,要么一起成功要么一起失败,分布式关注的重点就是多节点之间数据的原子性控制。

Consistency 一致性 

读和写的一致性,会不会读到脏数据。

Isolation 隔离性   

每个事务相互之间是独立的,每个事务内与主表之间也是互不影响、相互独立的。
Durability 持久性   

数据落盘持久化,通过记录Journal日志文件和备份副本。

先从mongoDB的一致性相关的writeConcern, readConcern说。

什么是 writeConcern ?

writeConcern 决定一个写操作落到多少个节点上才算成功。writeConcern 的取值包括:
0:发起写操作,不关心是否成功;
1~集群最大数据节点数:写操作需要被复制到指定节点数才算成功;默认是1。
majority:写操作需要被复制到大多数节点上才算成功。

• all:写入所有节点才算成功。
发起写操作的程序将阻塞到写操作到达指定的节点数为止


默认情况 w:“1”

 

大多数节点确认(即一半以上节点)   w: “majority” 

全部节点确认 w: “all”

j:true

 writeConcern 可以决定写操作到达多少个节点才算成功,journal 则定义如何才算成
功。取值包括:
true: 写操作落到 journal 文件中才算成功;
false: 写操作到达内存即算作成功。

数据库数据写入的顺序  数据在内存中先写日志文件(journal 中落地持久化日志文件),再写数据文件

 mongoDB shell中使用

db.test.insert( {count: 1}, {writeConcern: {w: "majority"}})
db.test.insert( {count: 1}, {writeConcern: {w: 3 }})
db.test.insert( {count: 1}, {writeConcern: {w: 4 }})

readPreference与readConcern

readPreference 设置 分布式数据库从哪里读

readConcern 什么样的数据可以读

readPreference 

readPreference 决定使用哪一个节点来满足正在发起的读请求。可选值包括:

primary: 只选择主节点;

primaryPreferred:优先选择主节点,如果不可用则选择从节点;

secondary:只选择从节点;

secondaryPreferred:优先选择从节点,如果从节点不可用则选择主节点;

nearest:选择最近的节点;

 场景举例:大量高并发读取的数据场景可以选择从节点,写入数据的时候,用主节点。

readPreference的 配置方式

通过 MongoDB 的连接串参数:
• mongodb://host1:27107,host2:27107,host3:27017/?replicaSet=rs&readPreference=secondary
通过 MongoDB 驱动程序 API:
• MongoCollection.withReadPreference(ReadPreference readPref)
Mongo Shell:
• db.collection.find({}).readPref( “secondary” ) 

readConcern

在 readPreference 选择了指定的节点后,readConcern 决定这个节点上的数据哪些是可读的,类似于关系数据库的隔离级别。可选值包括:
available:读取所有可用的数据;
local:读取所有可用且属于当前分片的数据;
majority:读取在大多数节点上提交完成的数据;
linearizable:可线性化读取文档;
snapshot:读取最近快照中的数据;

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

注意事项:
• 虽然看上去总是应该选择 local,但毕竟对结果集进行过滤会造成额外消耗。在一些无关紧要的场景(例如统计)下,也可以考虑 available;
• MongoDB <=3.6 不支持对从节点使用 {readConcern: "local"};
• 从主节点读取数据时默认 readConcern 是 local,从从节点读取数据时默认readConcern 是 available(向前兼容原因)。

readConcern : ”majority” vs “local”

majority 如果有如下场景:

应业务需要做读写分离,主节点A主要做写入操作,从节点做读取操作;向主节点写入一条数据;立即从从节点读取这条数据。

如果用默认配置local,有的复制集从节点B到主A可能是有延时的,而导致在主节点A上修改数据后,立刻在从节点读取,发现有脏数据,主从数据不同步。所以需要majority配置,和其他节点互交确认大多数据节点上都是一样的数据才返回。

#注意配置文件内server参数开启 
enableMajorityReadConcern:ture

#这种方式读取不到刚写入的数据
db.orders.insert({ oid: 101, sku: ”kite", q: 1}) //主节点写入
db.orders.find({oid:101}).readPref("secondary") //从节点读取
#使用 writeConcern + readConcern majority来解决
db.orders.insert({ oid: 101, sku: "kiteboar", q: 1}, {writeConcern:{w: "majority”}}) //主节点写入
db.orders.find({oid:101}).readPref(“secondary”).readConcern("majority")         //从节点读取

readConcern: majority 与脏读
MongoDB 中的回滚:

• 写操作到达大多数节点之前都是不安全的,一旦主节点崩溃,而从节还没复制到该次操作,刚才的写操作就丢失了;
• 把一次写操作视为一个事务,从事务的角度,可以认为事务被回滚了。所以从分布式系统的角度来看,事务的提交被提升到了分布式集群的多个节点级别的“提交”,而不再是单个节点上的“提交”。在可能发生回滚的前提下考虑脏读问题:
• 如果在一次写操作到达大多数节点前读取了这个写操作,然后因为系统故障该操作回滚了,则发生了脏读问题;
使用 {readConcern: “majority”} 可以有效避免脏读

readConcern: linearizable

只读取大多数节点确认过的数据。和 majority 最大差别是保证绝对的操作线性顺序:

在写操作自然时间后面的发生的读,一定可以读到之前的写(会在读取的节点,向其他所有节点发起确认请求)
- 只对读取单个文档时有效;
- 可能导致非常慢的读,因此总是建议配合使用 maxTimeMS;

下图情况是在主节点网络异常时,从节点发起选举期间发生的脏读

readConcern: snapshot(最高级别)

{readConcern: “snapshot”} 只在多文档事务中生效。将一个事务的 readConcern
设置为 snapshot,将保证在事务中的读:
• 不出现脏读;
• 不出现不可重复读;
• 不出现幻读。
因为所有的读都将使用同一个快照,直到事务提交为止该快照才被释放。

官网mongoDB Java Client 事务使用示例:

final MongoClient client = MongoClients.create(uri);
/*
    Prereq: Create collections. CRUD operations in transactions must be on existing collections.
 */
client.getDatabase("mydb1").getCollection("foo")
        .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("abc", 0));
client.getDatabase("mydb2").getCollection("bar")
        .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("xyz", 0));
/* Step 1: Start a client session. */
final ClientSession clientSession = client.startSession();
/* Step 2: Optional. Define options to use for the transaction. */
TransactionOptions txnOptions = TransactionOptions.builder()
        .readPreference(ReadPreference.primary())
        .readConcern(ReadConcern.LOCAL)
        .writeConcern(WriteConcern.MAJORITY)
        .build();

/* Step 3: Define the sequence of operations to perform inside the transactions. */
TransactionBody txnBody = new TransactionBody<String>() {
    public String execute() {
        MongoCollection<Document> coll1 = client.getDatabase("mydb1").getCollection("foo");
        MongoCollection<Document> coll2 = client.getDatabase("mydb2").getCollection("bar");
        /*
           Important:: You must pass the session to the operations.
         */
        coll1.insertOne(clientSession, new Document("abc", 1));
        coll2.insertOne(clientSession, new Document("xyz", 999));
        return "Inserted into collections in different databases";
    }
};
try {
    /*
       Step 4: Use .withTransaction() to start a transaction,
       execute the callback, and commit (or abort on error).
    */

    clientSession.withTransaction(txnBody, txnOptions);
} catch (RuntimeException e) {
    // some error handling
} finally {
    clientSession.close();
}

java 示例2:

//MongoDB 多文档事务的使用方式与关系数据库非常相似:
try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    collection.insertOne(clientSession, docOne);
    collection.insertOne(clientSession, docTwo);
    clientSession.commitTransaction();
}

 db.fsyncLock() 与db.fsyncUnlock() 可以锁定/解锁节点的写入,可以用来做事务代码的测试。