MVCC浅析

在并发读写数据库时,读操作可能会不一致的数据(脏读)。为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问。由于,加锁会将读写操作串行化,所以不会出现不一致的状态。但是,读操作会被写操作阻塞,大幅降低读性能。在java concurrent包中,有copyonwrite系列的类,专门用于优化读远大于写的情况。而其优化的手段就是,在进行写操作时,将数据copy一份,不会影响原有数据,然后进行修改,修改完成后原子替换掉旧的数据,而读操作只会读取原有数据。通过这种方式实现写操作不会阻塞读操作,从而优化读效率。而写操作之间是要互斥的,并且每次写操作都会有一次copy,所以只适合读大于写的情况。

MVCC的原理与copyonwrite类似,全称是Multi-Version Concurrent Control,即多版本并发控制。在MVCC协议下,每个读操作会看到一个一致性的snapshot,并且可以实现非阻塞的读。MVCC允许数据具有多个版本,这个版本可以是时间戳或者是全局递增的事务ID,在同一个时间点,不同的事务看到的数据是不同的。

实现原理: 

------------------------------------------------------------------------------------------> 时间轴

|-------R(T1)-----|

|-----------U(T2)-----------|

如上图,假设有两个并发操作R(T1)和U(T2),T1和T2是事务ID,T1小于T2,系统中包含数据a = 1(T1),R和W的操作如下:

R:read a (T1)

U:a = 2    (T2)

R(读操作)的版本T1表示要读取数据的版本,而之后写操作才会更新版本,读操作不会。在时间轴上,R晚于U,而由于U在R开始之后提交,所以对于R是不可见的。所以,R只会读取T1版本的数据,即a = 1。

由于在update操作提交之前,不能影响已有数据的一致性,所以不会改变旧的数据,update操作会被拆分成insert + delete。需要标记删除旧的数据,insert新的数据。只有update提交之后,才会影响后续的读操作。而对于读操作而且,只能读到在其之前的所有的写操作,正在执行中的写操作对其是不可见的。

上面说了一堆的虚的理论,下面来点干活,看一下mysql的innodb引擎是如何实现MVCC的。innodb会为每一行添加两个字段,分别表示该行创建的版本删除的版本,填入的是事务的版本号,这个版本号随着事务的创建不断递增。在repeated read的隔离级别(事务的隔离级别请看这篇文章)下,具体各种数据库操作的实现:

select:满足以下两个条件innodb会返回该行数据:(1)该行的创建版本号小于等于当前版本号,用于保证在select操作之前所有的操作已经执行落地。(2)该行的删除版本号大于当前版本或者为空。删除版本号大于当前版本意味着有一个并发事务将该行删除了。

insert:将新插入的行的创建版本号设置为当前系统的版本号。

delete:将要删除的行的删除版本号设置为当前系统的版本号。

update:不执行原地update,而是转换成insert + delete。将旧行的删除版本号设置为当前版本号,并将新行insert同时设置创建版本号为当前版本号。

其中,写操作(insert、delete和update)执行时,需要将系统版本号递增。

由于旧数据并不真正的删除,所以必须对这些数据进行清理,innodb会开启一个后台线程执行清理工作,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫做purge。

通过MVCC很好的实现了事务的隔离性,可以达到repeated read级别,要实现serializable还必须加锁。

  • 23
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
PostgreSQL的MVCC(多版本并发控制)是一种用于支持事务并维持数据一致性的同时,允许并发读写的机制。这种技术在数据库管理系统中非常关键,尤其是在处理事务性和并发操作时。 ### MVCC的工作原理 #### 时间戳隔离 在MVCC中,每一行数据都有一个称为“时间戳”的版本标识符。当一个事务开始时,它会获取一个时间点作为其活动的开始,这个时间点包含了所有已提交事务的时间戳信息。事务在其整个生命周期内,只能够访问和修改那些在这个时间点前或同时创建的数据。 #### 数据行和快照 在MVCC中,数据行不是直接存储其原始值,而是包含了一个额外的版本信息。每个查询或操作都会从数据库中加载一组所谓的“快照”,即特定时刻的所有活跃事务的状态。这些快照由一系列的版本(版本树)组成,其中每个节点表示一个事务的更新状态。 #### 写入与删除 写入操作会在现有数据上建立一个新的版本,并将旧版本标记为历史记录。如果需要,可以保留多个历史版本供日志和恢复使用。删除操作实际上是修改数据的一次写操作,将其标记为不可见而非物理删除,以便于保持查询性能。 ### 相关优势 1. **高并发性**:通过限制事务对数据的访问范围,使得多个事务可以在同一时间内运行而不相互干扰。 2. **冲突解决**:自动管理并发操作带来的冲突,减少了应用开发者在并发处理上的复杂度。 3. **安全性**:避免了死锁和其他并发问题,提高了系统的稳定性和可靠性。 4. **性能优化**:通过避免全表扫描等低效操作,提高查询效率。 ### 使用场景及限制 1. **多用户环境**:在大量并发用户同时请求的情况下,MVCC能有效减少锁定等待时间和提高系统吞吐量。 2. **数据完整性**:确保在高负载下仍能满足ACID(原子性、一致性、隔离性、持久性)属性的需求。 3. **复杂查询**:支持复杂的SQL查询,包括JOIN操作,而不会因为并发读写引起的问题。 然而,尽管有上述优点,MVCC也有其局限性: - 需要更多的磁盘空间来存储额外的版本数据。 - 对一些特殊的查询或需求可能不如其他并发控制策略高效。 ---
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值