WiredTiger存储引擎之五:与事务相关的数据结构以及并发控制机制

前言
WiredTiger存储引擎系列文章将从逻辑正确、内容完整的角度全面介绍WiredTiger存储引擎。本篇是WiredTiger存储引擎系列文章第5篇,前面篇章分别是:

WiredTiger存储引擎之一:基础数据结构分析

WiredTiger存储引擎之二:一个Page的生命周期

WiredTiger存储引擎之三:Checkpoint原理

WiredTiger存储引擎之四:WT工具编译与元数据文件剖析

本篇包含以下内容:

  • 与事务相关的数据结构是如何支撑事务的?
  • MongoDB事务采取的多版本并发控制机制(MVCC)

事务的数据结构 

事务在内存里面也会维护相应的数据结构以支撑事务的并发、回滚、持久化等操作,事务相关的数据结构如下图所示:

 

图:事务相关的数据结构

上图左边是一个leaf page在内存的数据结构,放在这的目的是为了更好的看到内存里的修改操作与事务的关系,本节重点关注事务的数据结构即WT_TXN,详细描述如下:

id字段

这是事务的全局唯一标识,通过它与具体的操作关联,这样就能知道一个事务里面包含哪些操作。

snapshot_data字段

因为MongoDB使用的是快照隔离级别的事务,这个字段保存事务的快照信息,具体来说它会有snap_min和snap_max两个属性,通过这两个属性能够计算一个事务开始时能够看到的数据范围,每个事务开始时都会构造一个这样的快照。

commit_timestamp字段

表示事务提交的时间。

durable_timestamp字段

表示事务修改的数据已持久化的时间,与具体操作里面的durable_ts字段关联。

prepare_timestamp字段

表示事务开始准备的时间。

WT_TXN_OP字段

包含事务的修改操作,用于事务rollback和生成事务的Journal日志。

logrec字段

表示事务日志的缓存,用于在内存里面保存事务日志(对于MongoDB来Journal日志就是事务日志)。

MVCC并发控制机制

要实现事务间的并发操作,可以使用锁机制或MVCC控制等。

对于WiredTiger来说,使用的是MVCC控制来实现并发的,相较于其它锁机制的并发,MVCC实现的是一种乐观并发机制,因此它较轻量级。

MVCC是通过在内存里面维护一个多版本的行数据(leaf page上的WT_UPDATE结构),也就是说它会将多个写操作,针对同一行记录的修改以不同行版本号的形式保存下来,实现事务的并发。

具体如何实现事务并发与冲突检查,如下图所示:

图:MVCC并发控制机制

详细描述如下:

1)  A事务首先从表中读取到要修改的行数据,读取到库存值为100,行记录的版本号为1;

2)  B事务也从中读取到要修改的相同行数据,读取库存值为100,行记录版本号为1;

3)  A事务修改库存值后提交,同时行记录版本号加1,即变为2,大于一开始读取到的版本号1,A事务可以提交;

4)  但B事务提交时发现此时行记录版本号已经变为2,产生冲突,B事务提交失败;

5)  B事务尝试重新提交,此时再读取到的版本号为2,加1,即变为3,不会产生冲突,正常提交B事务。

下面再通过一段代码来分析事务的并发与冲突:

session1 = client.start_session()#开启一个session1 session1.start_transaction()#开启一个事务1 inventory.delete_one({'_id':4}, session=session1) doc1 = inventory.find_one({'_id': 4},session=session1) pprint.pprint(doc1)#会输出none,说明在事务里面已经删除 session2 = client.start_session()#再开启一个session2 session2.start_transaction()#在session2中开启一个事务 inventory.delete_one({_id:4}, session=session2)#执行会发生事务冲突 session1.abort_transaction()#终止事务1 session1.end_session()#结束session1 session2.abort_transaction()#终止事务2 session2.end_session()#结束session2 doc2 = inventory.find_one({'_id': 4})#隐式开启第三个session和事务 pprint.pprint(doc2)#在事务外可以找到,说明事务1被终止后,回滚了

其中语句:doc1 = inventory.find_one({‘_id’: 4},session=session1),在session1内部查询,数据已被删除,访问不到;

语句:inventory.delete_one({‘_id’:4}, session=session2),两个未提交的事务(session1和session2中的删除操作),同时修改相同的文档,则产生冲突。

 

专栏作者:郭远威
资深大数据解决方案咨询顾问与架构师,MongoDB中文社区委员,长沙分会主席,多年通信行业大数据研发、规划、咨询经验;《大数据存储MongoDB实战指南》作者;阿里云云计算ACP认证专家。
也许您还感兴趣——
WiredTiger存储引擎之一:基础数据结构分析
WiredTiger存储引擎之二:一个Page的生命周期

WiredTiger存储引擎之三:Checkpoint原理

WiredTiger存储引擎之四:WT工具编译与元数据文件剖析

性能最佳实践:查询模式和分析
性能最佳实践:MongoDB数据建模和内存大小调整
MongoDB for VS Code:使用Mongo的新方法
MongoDB的WiredTigerLAS.wt大小异常分析
常用高并发网络线程模型设计及MongoDB线程模型优化实践
MongoDB网络传输处理源码实现及性能调优-体验内核性能极致设计
MongoDB 事务,复制和分片的关系
赞(3)
未经允许不得转载:MongoDB中文社区 » WiredTiger存储引擎之五:与事务相关的数据结构以及并发控制机制
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!