一致性无锁读包含两层含义:
一致性读,即快照读。在InnoDB中,事务中的查询会基于某个时间点创建的快照返回结果集,而非查询数据库表空间中的当前数据。一致性读(MySQL官方文档)。
一致性读与当前读相对立:
一致性读说白了就是让一个事务中的普通读操作不受其他事务的影响(不同的隔离级别有所差异)
InnoDB中,在RR、RC隔离级别下,默认开启一致性读,但是其创建快照的时机不同。
InnoDB,普通的select读操作是不会对记录加锁的,否则就会产生比较大的性能开销。
InnoDB中通过快照(Read-View)、MVCC、undo-log来实现一致性无锁读
read_view_t
结构体对象的形式存在,里面记录的与创建快照的timepoint相关联的一些信息(如当时系统中出现过的最大事务ID,活跃的最小事务ID等)MVCC,即:Multi-Versioning Concurrency Control(多版本并发控制)
MVCC 是InnoDB在RC(Read-Commited)和RR(Read-Repeated)隔离级别下提高并发和支持Rollback的技术,它保存了被修改行的历史版本信息,结合undo-log形成历史版本链。
InnoDB可以使用MVCC实现以下两个目标:
本文主要介绍如何基于MVCC实现一致性无锁读
MVCC为每张表增加了下面三个隐藏列:
一致性读中的快照,在程序中医Read-View对象的形式存在。源码链接
struct read_view_t{
ulint type;
undo_no_t undo_no;
trx_id_t low_limit_no;
trx_id_t low_limit_id;
trx_id_t up_limit_id;
ulint n_trx_ids;
trx_id_t* trx_ids;
trx_id_t creator_trx_id;
UT_LIST_NODE_T(read_view_t) view_list;
};
这里对几个关键的字段进行下解释说明:
undo-log是InnoDB中与单个读写事务关联的撤消日志记录的集合。
undo-log中包含了如何撤销事务对聚簇索引记录所做的修改的信息。
当InnoDB需要读取某行记录的旧版本时,可以顺着undo-log找到对应的历史版本。
undo-log可以分为两大类:
题外话:insert undo log在事务提交后即可删除,可以推出InnoDB无法基于undo-log和MVCC解决幻读问题。 幻读问题在RR隔离级别下仍然可能出现。
有了前面的基础知识,我们来看下如何基于MVCC、Read-View、undo-log实现一致性无锁读。
首先,undo-log中提供了rebuild记录历史版本的信息(SQL语句),而MVCC则提供了重建历史版本的入口(指向undo-log的指针)。
那么现在的问题就是,如何确定一致性读对应的历史版本。
因为MVCC和undo-log中的版本信息是以事务ID来表示的,所以问题其实就是转化为:确定哪些事务对记录行的修改对当前可见。
快照创建前已经提交的事务所做的修改对当前快照可见,快照创建后才提交的事务所做的修改,对当前快照不可见。
因此一致性读的重点就是将Read-View中几个与事务ID相关的重点字段与数据库当前表数据和undo-log中DB_TRX_ID
列进行对比。
如果能够直接知道创建Read-View时哪些事务提交,哪些事务未提交,那么一切就会变得简单。然后并没有这样的直接渠道。 数据库中,很可能事务ID大的先提交,事务ID小的后提交。
在Read-View中我们维护了low_limit_id
、up_limit_id
、trx_ids
, 将他们与MVCC、undo-log中的DB_TRX_ID
列对比,即可得到哪些事务在创建Read-View已提交,哪些不是。
DB_TRX_ID
< up_limit_id
, 则修改改记录的事务在创建Read-View之前就提交了。该版本对这个一致性读可见。DB_TRX_ID
> low_limit_id
, 则修改改记录的事务在创建Read-View时事务还未开启(更不用谈提交了),因此改版本对这个一致性读不可见。up_limit_id
< DB_TRX_ID
< low_limit_id
, 只能说明事务在创建Read-View前已经开启,但是无法判断其是否提交。需要与活跃列表进一步对比。
3.1 DB_TRX_ID
在活跃列表trx_ids
中,即事务还在活跃(还未提交),因此其修改不可见。
3.2 DB_TRX_ID
不在活跃列表trx_ids
中,即事务已经开启且不活跃,那必然就是已经提交。因此其修可见。MySQL 5.7 Reference Manual: Consistent Nonlocking Reads
MySQL 5.7 Reference Manual: InnoDB Multi-Versioning
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。