前言
最近留意到了一款优秀的国产数据库tidb
,研究了一下他们实现的分布式事务,属于二段提交(2PC)。tidb
借鉴了 google 用于实现 big table 的分布式事务实践 Percolator 。下面会讲一下分布式事务的乐观和悲观锁。
悲观 or 乐观?
拿去餐厅用餐等位置的经历来举例
乐观者
这个时候餐厅应该不会很多人吧?我去先去看看排的队长不长,长我就先回家等等,不长我就去用餐了。
悲观者
这个时候餐厅应该会很多人吧?我先打个电话预约一下餐桌,免得到时候人多白跑一趟。
分析
不难发现,乐观者会先假设餐厅是相对空闲的一个状态,避免了占用资源但是暂时不使用的浪费资源现象。而悲观者会基于资源是相对繁忙的一个情况,会先对资源进行预约占用(上锁)。
乐观事务
下面来讲一下乐观事务的事务流程。在事务提交之前,会先把数据的 update/delete 操作缓存到内存。然后大体分为两个步骤完成事务提交。
Prewrite
把需要修改的 key 分为两部分:随机1个 primary 、其他作为 secondaries 。
- 首先把 primary 上锁,会有两种情况上锁失败:
- key 已经被上锁
- 在本次事务开始时间戳(startTs)后,已经有过写操作,此处称为冲突(Conflict)。
- 把 secondaries 用 primary key 类似的上锁方法上锁
Commit
Prewrite 完成之后,需要开始进行提交操作。
- 提交 primary key:写入数据,记录事务提交时间戳(commitTs)。
- 解开 primary key 的锁
- 异步进行提交 secondaries key 操作。
重试
由于在 Prewrite 阶段有可能会产生失败,失败就会产生回滚和重试。在一些大事务当中,冲突率有可能非常高,导致频繁重试。此时需要引入悲观事务。
悲观事务
悲观锁事务其实整体流程都非常类似乐观锁事务。不同的是,把 prewrite 阶段的锁,提前到客户端开启事务中的DML语句当中。
版权声明
本文版权归作者所有,请勿私自转载文章,感谢!