【闲聊杂谈】MongoDB中的分布式事务

导读:本篇文章讲解 【闲聊杂谈】MongoDB中的分布式事务,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

对于传统的关系型数据库而言,事务的控制是调整数据的隔离级别。但是对于MongoDB而言,在数据读和写的时候用于指定怎么读怎么写来控制事务。MongoDB为什么要这么设计呢?因为在传统的关系型数据库而言,更多的是考虑单节点的事物隔离;而MongoDB更多的是考虑多节点的情况下事务的保证,主要分为:写事务(writeConcern)和读事务(readPreference、readConcern)。

1、writeConcern

writeConcern描述了一次写请求的确认级别

{w:<value>, j:<boolean>, wtimeout:<number>}

w:决定一个写操作落到多少个节点上才算成功

  • 0(默认):发起写操作,不关心是否成功;

【闲聊杂谈】MongoDB中的分布式事务

  • 1~集群最大数据节点数:写操作数据需要全部复制到配置节点上才算成功;

【闲聊杂谈】MongoDB中的分布式事务

  • majority:写操作需要被复制到大多数节点上才算成功。

【闲聊杂谈】MongoDB中的分布式事务

j:每个节点日志是否落到磁盘

  • true:刷到磁盘
  • false:仅留在内存中

wtimeout:线程阻塞等待返回客户端时间,超过这个时间以后无论有没有达到配置中的要求都返回客户端成功。wtimeout的默认值是0,如果不设置,当不满足写入节点数条件的时候,会无限期阻塞等待。

接下来我们简单验证一下这几个参数是如何控制MongoDB副本集事务:

配置延迟节点,模拟网络延迟:

【闲聊杂谈】MongoDB中的分布式事务

目前副本其中有三个节点,手动将第3个节点成员设置网络延迟:

conf = rs.conf()

conf.members[2].secondaryDelaySecs=10

conf.members[2].priority=0

rs.reconfig(conf)

看一下网络延迟是否设置成功:

【闲聊杂谈】MongoDB中的分布式事务

数据库清空后,重新进行数据插入演示:

【闲聊杂谈】MongoDB中的分布式事务

当 w:3 时,因为要等待第3个成员节点同步完数据以后才能返回客户端插入成功,所以当数据插入以后没有像 w:1 和 w:2 时立马返回成功,而是进入了阻塞等待,直到10秒钟之后才返回客户端插入成功。

【闲聊杂谈】MongoDB中的分布式事务

而 w:majority 却并不受到影响,因为已经有两台写入成功,第3排有没有写入成功已经不重要了。

【闲聊杂谈】MongoDB中的分布式事务

当设置了 wtimeout:5000 时,即便规定时间之内第3台还没有同步数据,但是此时还是要返回给前端结果,只不过在返回的时候更加详细的说明了返回的情况。这算不上是一种报错,只能说是一种警告,因为副本其中的数据在经过一段时间以后,最终还是趋向于一致性。

【闲聊杂谈】MongoDB中的分布式事务

writeConcern增加了写操作的延迟时间,但不会影响系统吞吐量,也不会显著增加服务器压力,因为写操作最终都会同步到所有节点上,只是影响了写操作的响应时间。综合所有场景来看,majority写延迟是最优,而在实际生产环境中,企业也多将w设置成majority。

2、readPreference

readPreference决定读取的数据来自哪个数据节点,可选值:

  • primary(默认):只读取主节点
  • primaryPreferred:优先读取主节点,如果不可用则选择从节点;
  • secondary:只读取从节点;
  • secondaryPreferred:优先读取从节点,如果从节点不可用则读取主节点;
  • nearest:读取最近的节点。

使用场景:

  • 适用于主从复制延迟很低或者基本无延迟场景,譬如用户下订单后马上跳转到订单详情页:primary / primaryPreferred
  • 适用于不太要求时效性场景,譬如查询历史订单:sencondary / sencondaryPreferred
  • 适用于时效性不高,但是资源需求量大,避免影响线上资源,譬如业务监控报表统计:sencondary
  • 适用于国际化业务,数据中心同步的数据:nearest

注:以上配置只能控制读取一类节点,比如读取secondary。但是secondary中可能有N个节点,还不能达到精准读取,如果想要实现控制精准读取,可以设置副本集tag:

members[n].tags={“<tag1>”:”<string1>”, “<tag2>”:”<string2>”, …..}

譬如:conf=rs.conf(), conf.members[1].tags={region:”south”, datacenter:”A”}

使用方法:

  • Mongo Shell:db.collection.find().readPref(“secondary”)
  • MongoDB驱动API:MongoCollection.withReadPreference(ReadPreference readPref)
  • MongoDB连接字符串(推荐使用):mongodb://<ip>:<port>,<ip>:<port>/test?connect=replicaSet&secondaryOk=true&replicaSet=rs0&readPreference=sencondary

3、readConcern

readConcern决定当前节点上的数据那些是可读取的,类似于关系型数据库的隔离级别,可选值:

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

available 和 local 在副本集中二者是没有区别的,主要的区别体现在分片集群上。譬如一个 chunk 正在从 shard1 向 shard2 迁移,再迁移过程中部分数据会在两个 shard 中同时存在,但是 shard1 仍然是 chunk 的负责方,config 中记录的信息 chunk 仍属于 shard1。此时如果读取 shard2 中数据:

available >>>>> 可读取 shard2 上所有数据,包括正在迁移的 chunk

local >>>>> 只读取原来 shard2 上负责的数据,正在迁移的 chunk 属于 shard1 负责则不可读取

majority 相当于关系型数据库的READ COMMITED

linearizable 和 majority 最大差别是保证绝对的操作线性顺序,在写操作自然时候发生后的读操作,一定可以读到之前的写,相当于关系型数据库的 Serializable

开启 readConcern 后,snapshot 存在内存中,增加了 cache 维护压力,对心梗会有一定的损耗,性能大约降低30%左右。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/111938.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!