海北藏族自治州网站建设_网站建设公司_需求分析_seo优化
2026/1/10 13:26:58 网站建设 项目流程

04- MongoDB 集群中的数据一致性和隔离性保证

1、writeConcern

1.1 MongoDB的应答机制

  1. 定义:MongoDB应答机制指数据库将写入成功与否告知客户端(db.getLastError())。
    流程:客户端发出写入请求 → MongoDB Server 端写入 → 通知客户端写入结果。
  2. 应答机制类型
    • 应答式写入(默认,安全写入,适用于强一致性场景)
    • 非应答式写入(非安全写入,适用于弱一致性场景)
  3. 实现方式:通过 writeConcern 实现,客户端驱动调用db.getLastError()方法,错误返回客户端。

1.2 什么是writeConcern

  1. 定义:Write Concern 描述了 MongoDB 写入到 mongod 单实例、副本集或分片集群时何时应答客户端。决定写操作落到多少个节点上才算成功,类似于 MySQL 的半同步复制,保证数据最终一致性。
  2. 配置
    • 支持客户端灵活配置写入策略。
    • 从 MongoDB 4.4 开始,副本集和分片集群支持设置全局默认 writeConcern(使用setDefaultRWConcern)。

1.3 setDefaultRWConcern

  1. 作用:设置全局默认的 writeConcern 和 readConcern。
  2. 使用方式
    // 设置全局默认 writeConcerndb.adminCommand({"setDefaultRwConcern":1,"defaultWriteConcern":{"w":2}});// 设置全局默认 readConcerndb.adminCommand({"setDefaultRwConcern":1,"defaultReadConcern":{"level":"majority"}});

1.4 journal日志

  1. 定义:Journal 是存储引擎的预写日志(WAL,类似 MySQL Redo log)。MongoDB 每 n(2~300)毫秒刷盘一次。
  2. 开启方式
    • 方式1:storage.journal.enabled决定是否开启;storage.journal.commitInternalMs决定刷盘间隔(默认 100ms)。
    • 方式2:写入时指定writeConcern{j: true},确保每次写入 journal 刷盘。

1.5 writeConcern测试

1.5.1 非应答式写入图示

MongoDB 不对客户端应答,驱动仅检查套接字、网络错误等。

1.5.2 应答式写入图示

默认方式。MongoDB 在内存中应用写入后应答,但不保证数据已写入磁盘。

1.5.3 带journal应答式写入图示

确认写操作已写入 journal 日志后才应答客户端。

1.5.4 副本集应答写入图示

缺省仅从主节点应答。建议修改为特定节点数或 majority 以保证可靠性。

1.6 注意事项

  • writeConcern 是性能与强一致性的权衡,需根据业务场景设定。
  • 通常设置w: "majority",避免设置总节点数。
  • 重要数据建议{w: "majority", j: true},普通数据可用{w: 1}以保证性能。

2、readPreference 读配置

2.1 介绍

readPreference 控制客户端从副本集的哪个节点读取数据,支持读写分离、就近读取等策略。

构成

  • read preference mode
  • tag set list
  • maxStalenessSeconds
  • hedged read(MongoDB 4.4+ 分片集群)

read preference mode 可选值

  • primary:仅从主节点读(默认)
  • primaryPreferred:优先从主节点,不可用时从 secondary
  • secondary:仅从 secondary 读
  • secondaryPreferred:优先从 secondary,不可用时从 primary
  • nearest:根据网络延迟就近读取

2.2 readPreference 场景举例

  • 用户下单后跳转订单详情页 →primary/primaryPreferred
  • 查询历史订单 →secondary/secondaryPreferred
  • 生成报表 →secondary
  • 全球图片分发 →nearest

2.3 readPreference 与 Tag

Tag 可将节点选择控制到特定节点。例如,为线上节点打 tag{purpose: "online"},为报表节点打 tag{purpose: "analyse"}

2.4 readPreference 配置使用

  • 连接串参数:mongodb://host1:27017/?replicaSet=rs&readPreference=secondary
  • 驱动程序 API:MongoCollection.withReadPreference(ReadPreference readPref)
  • Mongo Shell:db.getMongo().setReadPref('secondary')

2.5 实验:从节点读

  1. 主节点写入数据。
  2. 锁定从节点写入(db.fsyncLock())。
  3. 主节点再次写入。
  4. 分别设置读偏好为primarysecondary查询,观察结果。
  5. 解锁从节点(db.fsyncUnlock())后再查询。

2.6 注意事项

  • 指定primary时,若主节点故障则无法读取,建议使用primaryPreferred
  • 使用 Tag 时需考虑单点故障,多个节点可设置相同 Tag 以提高可用性。
  • 报表节点可设置优先级为 0,避免成为主节点。

3、readConcern 读隔离性保证

3.1 什么是 readConcern?

readConcern 决定从节点读取哪些数据,保证事务隔离性,避免脏读。

配置

  • 支持客户端灵活配置。
  • 从 MongoDB 4.4 开始支持全局默认设置。

可选值

  • available:读取所有可用数据(可能回滚)
  • local:读取当前分片可用数据(默认从 primary/secondary 读)
  • majority:读取大多数节点已提交的数据(需 WiredTiger 引擎)
  • snapshot:读取最近快照中的数据
  • linearizable:可线性化读取

3.2 readConcern: local 和 available

在副本集中两者无区别,区别体现在分片集群:

  • local:只读取当前分片负责的数据。
  • available:读取当前分片上所有数据(包括迁移中的数据)。

3.3 readConcern: majority

只读取大多数节点已提交的数据,通过 MVCC 多版本机制实现。

3.4 实验:readConcern “majority” vs “local”

  1. 锁定从节点写入(模拟延迟)。
  2. 主节点写入数据。
  3. 使用local可立即读到数据,使用majority需等待多数节点确认。

3.5 readConcern: majority 与脏读

使用{readConcern: "majority"}可避免读取未提交(可能回滚)的数据。

3.6 如何实现安全的读写分离

写入时使用{writeConcern: {w: "majority"}},读取时使用{readConcern: "majority"}可确保读到已提交的数据。

3.7 读隔离性和 MySQL 的对比

readConcern: "majority"对应 MySQL 的 Read Committed 隔离级别。

4、MongoDB的ACID事务支持

4.1 介绍

MongoDB 从 4.2 开始全面支持多文档事务,但应谨慎使用,优先通过设计文档模型避免事务。

4.2 MongoDB ACID 多文档事务支持

事务属性支持程度
Atomicity单表单文档:1.x;复制集多文档:4.0;分片集群多文档:4.2
ConsistencywriteConcern, readConcern (3.2)
IsolationreadConcern (3.2)
DurabilityJournal and Replication

4.3 使用方法

try(clientSession clientSession=client.startSession()){clientSession.startTransaction();collection.insertOne(clientSession,docOne);collection.insertOne(clientSession,docTwo);clientSession.commitTransaction();}

4.4 事务的隔离级别

  • 事务外操作无法访问事务内未提交的修改。
  • 使用{readConcern: "snapshot"}可实现可重复读(Repeatable Read)。

4.5 实验:启用事务后的隔离性

事务内修改数据,事务外查询不到未提交的更改。

4.6 实验:可重复读 Repeatable Read

使用{readConcern: "snapshot"}的事务内多次读取同一文档,结果一致。

4.7 事务写机制

  • 事务内修改的文档若在事务外被修改,事务提交时会触发 Abort 错误,需重试。
  • 事务外修改事务内正在操作的文档会等待事务完成。

4.8 注意事项

  • 需使用兼容 MongoDB 4.2 的驱动。
  • 事务默认需在 60 秒内完成。
  • 事务涉及的分片不能使用仲裁节点。
  • 多文档事务中的读操作必须使用主节点读。
  • 必须是 WiredTiger 引擎才支持事务。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询