事务系统实现模式很简单?你确定没忽视这些差异?
由于直接复制Journal会引起一系列复杂的耦合问题,大部分数据库都选择单独写一个binlog/oplog来实现复制,不过在实现时可以做优化,因为如果真的写两个log会有原子性的问题(一个写成功了另一个没写成功)以及IO放大的问题。 这里的设计空间比较庞大,不做详细讨论,仅仅考虑在简化的模型下复制顺序的问题。 对于并发执行的事务,为了确定复制顺序,这里维护一个称之为OpTime的自增ID。后续的复制会按照OpTime的顺序,OpTime小的先复制。如果OpTime仅仅是在事务的开始和结束之间分配,会带来问题:
因此,OpTime的分配需要有更强的限制:对于并发且有冲突的事务,OpTime的顺序要和事务的Serialization Order一样: 在S2PL的场景中,我们把OpTime分配放到Lock之后Commit之前,即可满足这个要求。因为按照S2PL的调度,事务的Commit-Point就是Lock完成和Unlock之间。对照上面的例子,事务T2的OpTime被推迟到T1之后,复制的顺序也会相应改变,不会发生先前的异常了。 推广到其他的并发控制方法也是类似,例如上面的Snapshot Isolation。提交之前会检查[begin, end]是否有冲突,有冲突直接重启事务。相当于在[begin, end]区间内分配OpTime即可。 这种方法通过OpTime,保留了Transaction Serialization Order和RSM的Order之间的关系:
不过这里留下了一个问题,留待读者思考: 如何按照OpTime复制,因为有事务Abort的情况,OpTime做不到连续自增,仅仅是单调自增。 二、对比 第一种其实是Spanner,第二种是TiKV、Percolator,第三种是MySQL、MongoDB。 (编辑:西安站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |