MongoDB 事务与数据落盘

文章目录

    • 概要
    • 一、持久性
        • 1.1、journal log刷盘机制
        • 1.2、数据刷盘机制
        • 1.3、复制集下的写安全机制
    • 二、隔离性
    • 总结

概要

MongoDB并不像MySQL一样天然支持多文档事务,其演变过程如下:

  • MongoDB4.0之前只支持单文档事务,在单个文档上支持ACID原子性,并且不对外暴漏API,用户无法控制事务,完全是MongoDB自行控制;
  • MongoDB4.0开始支持多文档事务以及复制集和分片集群下的事务,统称为分布式事务,并提供API允许用户像MySQL事务那样控制事务的开始与结束。

但是MongoDB4.0的事务仍有限制:

  1. 事务的默认最大运行时间是 60s。
    1)通过在 mongod 实例级别上修改transactionLifetimeLimitSeconds 的限制来增加。对于分片集群,必须在所有分片副本集成员上设置该参数。超过此时间后,事务将被视为已过期,并由定期运行的清理进程中止。清理进程每 60 秒或每 transactionLifetimeLimitSeconds/2 运行一次,以较小的值为准。
    2)要显式设置事务的时间限制,建议在提交事务时指定 maxTimeMS 参数。如果 maxTimeMS 没有设置,那么将使用 transactionLifetimeLimitSeconds;如果设置了 maxTimeMS,但这个值超过了 transactionLifetimeLimitSeconds,那么还是会使用 transactionLifetimeLimitSeconds。
    3)事务等待获取其操作所需锁的默认最大时间是 5 毫秒。可以通过修改由maxTransactionLockRequestTimeoutMillis 参数控制的限制来增加。如果事务在此期间无法获得锁,则该事务会被中止。maxTransactionLockRequestTimeoutMillis 可以设置为 0、-1 或大于 0 的数字。将其设置为 0 意味着,如果事务无法立即获得所需的所有锁,则该事务会被中止。设置为 -1 将使用由 maxTimeMS 参数所指定的特定于操作的超时时间。任何大于 0 的数字都将等待时间配置为该时间(以秒为单位)以作为事务尝试获取所需锁的指定时间段。

  2. MongoDB 将当前事务中的所有写操作日志放入单文档中,而oplog只是一个特殊的collection,其单个文档也象正常集合一样受16MB的大小限制。这个限制在MongoDB4.2做了很大的优化,即调整成为当前事务中的每一个写操作日志都创建一个单文档。

综上两点限制,不管如何还是要避免长事务与大事务。

MongoDB的oplog相当于MySQL的binlog,用于主备节点数据复制
MongoDB的journal log相当于MySQL的redo log,用于实现事务持久性,尽量保证数据不丢失以及崩溃恢复

事务的四大特性这里就不多说了,这里主要聊一下MongoDB的事务持久性与隔离性。

PS:针对MongoDB的WiredTiger存储引擎

一、持久性

持久性是指一个事务提交后,其所做的写操作会被永久保存到数据库中,即使此时数据库or操作系统崩溃,修改的数据也不会丢失。
下面我们来看看MongoDB事务持久性是否是这样的,先看一下下图:

MongoDB数据落盘示意图
我们已经知道journal log记录的是最新的写操作内容,即redo,所以只要写的内容到了journal log,MongoDB就可以在崩溃重启后恢复。

1.1、journal log刷盘机制

journal log主要受两个配置参数控制。

storage:journal:enabled: <boolean>  #是否开启journal logcommitIntervalMs: <num> #journal log刷盘的间隔,默认100ms,范围是1-500ms,值越小,丢失数据越少,性能越低;

除了配置文件,也可以通过如下命令调整journalCommitInterval的值:

db.adminCommand({"setParameter":1,"journalCommitInterval":10}); #设置为10ms

可知最多有journalCommitIntervalms的数据丢失。

另外在db.collection.insert({x:1}, {writeConcern: {j: true}})写命令中可以通过设置 j 的值为true来确保该语句的journal log刷盘。当然这并不意味着每一个写操作就等于一个IO。MongoDB并不会对每一个操作都立即刷盘,而是会等最多30ms,把30ms内的写操作集中到一起,采用顺序追加的方式写入到盘里。在这30ms内客户端线程会处于等待状态。这样对于单个操作的总体响应时间将有所延长,但对于高并发的场景,综合下来平均吞吐能力和响应时间不会有太大的影响。特别是你能给journal部署一个对顺序写有优化的IO带宽足够的专门的存储系统的话,这个对性能的影响可以降到最低。

还有就是缓冲区buffer中的journal log大小达到100MB(因为journal log文件的大小限制是100MB)也会触发刷盘。

总共三种,可以看到在写操作语句中指定j: true可确保journal log刷盘,保证数据不丢失。

1.2、数据刷盘机制

MongoDB的数据刷盘也有和MySQL一样的checkpoint机制,触发条件如下:

  • 按一定时间周期(由storage.syncPeriodSecs控制):默认60s,执行一次checkpoint;
  • 按journal log文件大小:当journal log文件大小达到2GB(如果已开启),执行一次checkpoint;

从数据刷盘机制可知,MongoDB的持久性只要靠journal log保证。

1.3、复制集下的写安全机制

db.collection.insert({x:1}, {writeConcern: {w: 1}}) #默认w值为1
  1. {w:0} 即Unacknowledged
    Unacknowledged指的是对每一个写入操作,MongoDB并不会返回一个是否成功的状态值。这个级别是写入性能最好但也是最不安全的级别。比如说,你试图插入一个违反了唯一性的文档(重复的身份证号),那么MongoDB会拒绝写入并报错。但是由于驱动端并没有在乎你的报错,应用程序还满心欢喜以为一切都没问题,下回再来查询那条数据的时候就会出现数据缺失的情况。
  2. {w:1} 即Acknowledged
    Acknowledged 的意思就是对每一个写入MongoDB都会确认操作的完成状态,不管是成功还是失败。当然这个确认只是基于主节点的内存写入。但是这个级别,已经可以侦测到重复主键, 网络错误,系统故障或者是无效数据等错误。
  3. {w:“majority”} 写到多数节点
    MongoDB 的默认部署是至少3个节点的复制集(Replicaset),使用复制集的好处很多,最关键的就是提高系统的高可用性。但是也带来了一个问题,主备不一致,该参数就可以很好的解决该问题。
    假设复制集中有A、B、C三个节点,A为主节点,此时w=1,那么:
    1)在A接收一个写命令x并返回成功时,A与B,C失联了;
    2)下一刻A发现自己无法和从节点B,C 联络上,主动降级为从节点,停止接受写操作;
    3)B、C选举出B为主节点,接收客户端请求,稍后网络恢复A节点重新加入复制集。这个时候A的oplog 和B的oplog已经有不一致了。A会主动把B上面不存在的写操作回滚掉(rollback),并写入一个回滚文件。
    这个时候应用如果再去查询写命令x的内容,MongoDB 将会说文档不存在,w=majority就避免了该问题。

所以说,可以通过w和j的值合理安排自己所需要的数据安全级别和性能要求。

二、隔离性

隔离性其实很好理解,即一个事务所做的写操作在它提交之前,对于其他事务是不可见的。那A事务修改了id=5的数据后B事务如何还能读到未修改数据呢,当然是记录下历史数据了,但是记录历史数据这个实现有两大流派,James Gray老爷子 的undo log流派和Michael Stonebraker老爷子的多版本派,二者在增删改上各有千秋。

所以说,MongoDB是没有undo log的,事务回滚是靠多版本,不像MySQL,SQLServer等会有undo log 段。

总结

待续…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/20514.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs2013 英文语言包

因为安装其它插件报错&#xff0c;有文档说需要更换为英文包。我电脑只有中文&#xff0c;于是开始了英文语言包下载。 官网下载 https://my.visualstudio.com/Downloads?qVisual%20Studio%202013%20Language%20Pack 刚开始没有使用官网&#xff0c;因为除了要注册登陆&…

Redis_客户端命令和数据操作(3)

目录 切换数据库 键命令 数据结构 string类型 hash类型 list类型 set类型 zset类型 查看中文value 源码等资料获取方法 切换数据库 redis数据库没有名称&#xff0c;默认有16个&#xff0c;通过0-15来标识&#xff0c;连接redis默认选择第一个数据库&#xff0c;可以…

Nacos(服务注册与发现)+SpringBoot+openFeign项目集成

&#x1f4dd; 学技术、更要掌握学习的方法&#xff0c;一起学习&#xff0c;让进步发生 &#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我&#xff0c;不迷路 。 &#x1f490;学习建议&#xff1a;1、养成习惯&#xff0c;学习java的任何一个技术…

安卓JNI从0到1入门教程(二)

经过上一篇《安卓JNI从0到1入门教程&#xff08;一&#xff09;》介绍&#xff0c;我们对JNI有了初步认识&#xff0c;接下来我会从ndk-build方式和cmake方式分别来介绍怎么构建native库&#xff1a; 一、ndk-build ndk-build依赖配置文件Android.mk&#xff0c;存放代码的位…

感受C++模版的所带来的魅力

一、泛型编程思想 首先我们来看一下下面这三个函数&#xff0c;如果学习过了 C函数重载 和 C引用 的话&#xff0c;就可以知道下面这三个函数是可以共存的&#xff0c;而且传值会很方便 void Swap(int& left, int& right) {int temp left;left right;right temp; }…

HarmonyOS/OpenHarmony应用开发-Stage模型UIAbility组件使用(四)

UIAbility组件与UI的数据同步 基于HarmonyOS的应用模型&#xff0c;可以通过以下两种方式来实现UIAbility组件与UI之间的数据同步。 1.EventHub&#xff1a;基于发布订阅模式来实现&#xff0c;事件需要先订阅后发布&#xff0c;订阅者收到消息后进行处理。 2.globalThis&…

macOS Sonoma 14beta 3 (23A5286i)第二个更新「附黑/白苹果镜像下载」

系统镜像下载&#xff1a; 系统介绍 黑果魏叔 7 月12 日消息&#xff0c;苹果今天发布 macOS Sonoma 14.0 Beta 3&#xff08;内部版本号&#xff1a;23A5286i&#xff09;第二个更新。 目前尚不清楚苹果为什么要发布 macOS Sonoma Beta 3 的第二个版本&#xff0c;但它可能…

MQ的优劣势及RabbitMQ相关概念

一&#xff0c;MQ 1&#xff0c;MQ 的概念 MQ 全称 Message Queue&#xff08;消息队列&#xff09;&#xff0c;是用来存储消息数据的容器&#xff08;是一个中间件&#xff09;&#xff0c;一般用于分布式系统间的通信&#xff1b;MQ主要介于生产者和消费者之间&#xff0c…

微服务系列文章之 Redisson实现分布式锁

一、高效分布式锁 当我们在设计分布式锁的时候&#xff0c;我们应该考虑分布式锁至少要满足的一些条件&#xff0c;同时考虑如何高效的设计分布式锁&#xff0c;这里我认为以下几点是必须要考虑的。 1、互斥 在分布式高并发的条件下&#xff0c;我们最需要保证&#xff0c;同…

Redis_设置密码

目录 一、临时设置密码 二、永久设置密码 源码等资料获取方法 一、临时设置密码 # 获取密码 config get requirepass # 设置密码为123456 config set requirepass 123456 # 验证密码。当设置密码后&#xff0c;进入redis就要验证 auth 密码 # 取消密码 config set requirep…

vscode插件开发之终端那些事儿

在开发vscode插件的时候&#xff0c;好几个设计都需要集成终端。 查资料后发现vsocd为开发者提供了丰富的终端API。 结合我自己的需求来展开终端的那些事儿吧&#xff1a; 从treeview中点击触发打开一个终端 无关的代码省略&#xff1a; vscode.window.createTerminal({name…

【JavaEE进阶】使用注解存储对象

使用注解存储对象 之前我们存储Bean时&#xff0c;需要在spring-config 中添加一行 bean注册内容才行&#xff0c;如下图所示&#xff1a; 问题引入&#xff1a;如果想在Spring 中能够更简单的进行对象的存储和读取&#xff0c;该怎么办呢&#xff1f; 问题解答&#xff1a;实…