数据库并发控制
在数据库中,并发控制是指在多个进程同时对数据库进行操作时,如何保证事务的一致性和隔离性的同时,实现最大程度地并发。
当多个进程同时对数据库进行操作时,会出现3种冲突情形
读-读,不存在问题
读-写,可能遇到脏读 ,幻读等
写-写,可能丢失更新
要解决冲突,一种办法是是锁,即基于锁的并发控制,比如2PL,这种方式开销比较高,而且无法避免死锁
单机
2PL (2 Phase Locking)
两阶段锁,是一种悲观并发控制,即在一个事务里面,分为加锁(lock)阶段和解锁(unlock)阶段
第一阶段:获得锁的阶段,称为扩展阶段
第二阶段:释放锁的阶段,称为收缩阶段
加锁阶段,主要是用共享锁(读锁)和排它锁(写锁)
- 读锁:对数据项加读锁(共享锁),读锁不阻塞其他事务
- 写锁:写锁(排他锁)不允许对给定资源进行读和写操作
优点:
- 维护锁开销较小时、数据冲突较少时性能较好
缺点:
- 加锁协议开销大
- 为了避免死锁,额外增加死锁检测
- 在持有锁的情况下可能会等待I/O操作,会降低系统的并发吞吐量
- 第一阶段加锁后影响了其他事务的读写操作,第二阶段释放了数据项上的锁之后,才能运行其他要操作相同数据项的事务
- 很多真实的业务应用场景都是高并发. 低竞争的
在2PL的基础上,可延伸为:
S2PL(Strict 2PL),在2PL的基础上,写锁保持到事务结束
SS2PL(Strong 2PL),在2PL的基础上,读写锁都保持到事务结束
OCC (Optimistic Concurrency Control)
OCC是在2PL并发控制存在比较多缺点的基础上提出,是一种乐观并发控制,用来解决写-写冲突的无锁并发控制,OCC认为事务间争用没有那么多,所以先进行修改,在提交事务前,检查一下事务开始后,有没有新提交改变,如果没有就提交,如果有就放弃并重试
实现分为三阶段:
- Read Phase, 对于读,放到Read Set,对于写,把写记到临时副本,放到Write Set。因为写是写到临时区的,属于未提交结果,其它事务读不到
- Validation Phase,重扫Read Set,Write Set,检验数据是否满足Isolation Level,如果满足则Commit,否则Abort
- WritePhase,或者叫做Commit Phase,把临时副本区的数据更新到数据库中,完成事务提交
优点:
- 不需要维护锁
- 数据不冲突时吞吐量比较高
缺点:
- 事物回滚比较高
OCC适用于低数据争用,写冲突比较少的环境。
扩展阅读 理论研究-BOCC/FOCC
BOCC-检查待验证事务的读集是否与事务读取阶段完成的事务的写集有交集
FOCC-检查待验证事务的写集是否与当前活跃事务的读集有交集
MVCC (Multi Version Concurrency Control)
多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,简单来说是使用版本号控制数据,为每个修改保存一个版本号,以对表数据的读写互不阻塞,增大并发量。
读操作不用阻塞写操作,写操作不用阻塞读操作,避免了脏读和不可重复读
InnoDB中MVCC的实现是通过在每一行记录后面保存两个隐藏的列来实现: DATA_TRX_ID 、 DATA_ROLL_PTR
每开始一个新事务,版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行纪录的版本号进行比较
Column | Length | remark |
---|---|---|
DATA_TRX_ID | 6 | 记录最近更新这条行记录的事务ID |
DATA_ROLL_PTR | 7 | 回滚段(rollback segment)的指针,InnoDB便是通过这个指针找到之前版本的数据 |
DB_ROW_ID | 6 | 行标识(隐藏自增ID),如果表没有主键,InnoDB会自动生成一个隐藏主键 |
优点:
1、读写互不阻塞,回滚率也比OCC好
- MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read)
- Read uncimmitted存在脏读,即能读到未提交事务的数据行,所以不适用MVCC,原因是MVCC的创建版本和删除版本只要在事务提交后才会产生
- Seriallizable会对所涉及到的表数据加锁,不存在行的版本控制问题
多版本并发控制可以结合基于锁的并发控制来解决写-写冲突,即MVCC+2PL
也可以结合乐观并发控制来解决写-写冲突,即MVCC+OCC。
Transactional Information Systems
分布式
上面几种并发控制都是基于单机,在分布式事务系统架构下的并发控制又有以下几种并发控制
2PC(Two-phaseCommit)
二阶段提交(Two-phaseCommit),基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法(Algorithm)。二阶段提交也被称为是一种协议(Protocol))
第一阶段:准备阶段(投票阶段)
- 协调者向所有的参与者发送是否可以执行提交操作,并开始等待各参与者的响应
- 各个参与者节点执行本地事务操作,但在执行完成后并不会真正提交数据库本地事务,而是先向协调者发送确认信息
- 各参与者向协调者反馈各事务操作结果的响应
第二阶段:提交阶段(执行阶段)
- 成功,只有所有参与者反馈成功才会执行提交,释放所有事务处理过程中使用的锁资源
- 失败/超时,直接给每个参与者发送回滚(Rollback)消息
缺点:
-
同步阻塞问题
无论是在第一阶段的过程中,还是在第二阶段,所有参与节点都是事务阻塞型的,只有当所有节点准备完毕,协调者才会通知进行全局提交 -
单点故障
当协调者发生故障,所有的参与者会一直阻塞下去
3PC(Three-phase commit)
三阶段提交(Three-phase commit),也叫三阶段提交协议(Three-phase commit protocol),是二阶段提交(2PC)的改进版本,三阶段提交协议(3PC)主要是为了解决两阶段提交协议的阻塞问题
待完善
LCN(Lock Control Notify)
LCN 一种基于java代理协调技术的分布式事务系统,并不生产事务,LCN 只是本地事务的协调工。LCN模式是通过代理Connection的方式实现对本地事务的操作,然后在由TxManager统一协调控制事务
优点:
- 兼容SpringCloud、Dubbo
- 基于切面的强一致性事务框架
- 高可用,使用简单,低依赖,代码完全开源
- 事务补偿机制,服务故障或挂机再启动时可恢复事务
主要模式:
TCC(Try、Confirm、Cancel)
TCC方案其实是2PC的一种改进。其将整个业务逻辑的每个分支显式的分成了Try、Confirm、Cancel三个操作
Try:完成业务的准备工作,confirm:完成业务的提交,cancel:完成事务的回滚
github地址
LCN原理
GTS(Global Transaction Service)
全局事务服务(Global Transaction Service,简称 GTS)是阿里推出的分布式事务处理方案,将分布式事务问题从业务中剥离出来,作为一个独立的技术切面来单独管理,以服务的形式给构建
消息中间件
消息一致性方案是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么两者都成功或者都失败。下游应用向消息系统订阅该消息,收到消息后执行相应操作
待完善
by: 梁振波