一. 架构介绍
从宏观上看,云溪数据库由两局部组成:下层的 SQL 引擎和上层的作为一个整体的分布式 KV 数据库。任何针对于数据库的 SQL 操作,通过 SQL 引擎的解析之后,都会把它们分解成一组组的 kv 操作,比方“select * from t”会被分解成 scan 操作,”update t set a = 1”会被分解成 scan 和 put(conditionalPut)操作 …… 事务次要是在上层的 KV 数据库对 kv 操作进行调度,以实现对更底层的存储引擎的并发读写。
二. Percolar 事务模型介绍
云溪数据库的事务模型是从 Percolator 倒退而来。Percolator 是构建在 BigTable 之上的,通过提供一个 TSO 地方授时服务和一个 client lib 来封装 BigTable 的接口,最终将 BigTable 革新成了一个带有 ACID 快照隔离语义的反对跨行、跨表事务的分布式多维 map。
Percolator 的特点是没有集中式的事务处理措施,比方核心事务管理器、全局死锁探测器 …… 事务产生的锁也是和数据关联在一起分布式存储的。就事务的角度而言,全局的惟一单点就是 TSO。因而 Percolator 模型具备良好的程度扩大能力。然而也正式这种无核心的实现形式,导致各种抵触解决都须要通过必要的网络交互来实现,所以事务的提早绝对较高。如果照搬这种实现形式,是无奈满足 OLTP 数据库对于高性能的事务处理的要求的。
三. 云溪数据库事务模型介绍
云溪数据库事务模型是从 Percolator 倒退而来的。一方面,它进一步实现了去中心化,通过应用 HLC 代替 TSO,打消了最初一个单点,是零碎的程度扩大能力进一步提高;另一方面,它也做了许多致力来减小 Percolator 模型事务提早较高的弊病,比方具体的优化有异步开释锁、并行提交、事务流水线、一阶段提交 ……
1. 规范工夫戳排序协定
云溪数据库通过 MVCC+ 实现戳排序协定实现了 SSI 的事务隔离级别,上面简略介绍一下工夫戳排序协定。
在规范工夫戳排序协定中,每个事务都有一个惟一固定的工夫戳,在事务开始时获取,读、写、提交都在该工夫戳上进行。每个数据项放弃两个工夫戳,W-timestam 示意胜利执 Write(Q)的所有事务的最大工夫戳;R-timestamp 示意胜利执 Read(Q)的所有事务的最大工夫戳。
1:假如事务 Ti 收回 read(Q)。
- 若 TS(Ti)< W-timestamp(Q),则 Ti 须要读入的 Q 值曾经被笼罩。因而 read 操作被回绝,Ti 回滚。
- 若 TS(Ti)>= W-timestamp(Q),则执行 read 操作,R-timestamp(Q)被设置为 R -timestamp(Q)于 TS(Ti)两者的最大值。
2:假如事务 Ti 收回 write(Q)
- 若 TS(Ti)< R-timestamp(Q),则 Ti 产生的 Q 值是先后面所须要的值,且零碎曾经假设该值不会再产生因而,write 操作被回绝,Ti 回滚。
- 若 TS(Ti)< W-timestamp(Q),则 Ti 试图写入的 Q 值曾经过期。因而,write 操作被回绝,Ti 回滚。
- 其余状况,零碎执行 write 操作,将 W -timestamp(Q)设置为 TS(Ti)。
2. 规范工夫戳排序协定的缺点
规范工夫戳排序协定是一个无锁(free lock)的并发控制协议,读写操作都不须要加锁,这尽管能取得高性能,单却存在级联回滚问题和不可复原调度。
不可复原调度问题:当 txn1 回滚时,txn2 原本也应该回滚,因为它读的 A 是 txn1 写入的。然而因为 txn2 曾经提交,所以没有办回滚,导致数据的一致性被毁坏。
级联回滚问题:txn2 依赖 txn1,txn3 依赖 txn2,可能会有 txn4 依赖 txn3……当 txn1 回滚时,会造成大面积的事务回滚。
为了防止下面这两个问题,云溪数据库会对写入的未提交数据加排他锁,这样在相似下面的场景中,txn2 和 txn3 在读 A 时会被阻塞,直到 txn1 提交才回放行。这样就不会产生级联问题和不可复原调度问题。
3. 云溪数据库对规范工夫戳排序协定的优化
工夫戳排序协定是一个比拟乐观的协定,它假如抵触很少产生,因而在事务开启的时候就确定事务也能够在这个工夫戳提交,工夫戳排序的抵触解决规定就是建设在这个前提之上的,任何呈现违反了这个规定的状况都会导致事务回滚。因而在高并发高抵触的场景中,工夫戳排序协定的事务回滚率和回滚代价都是比拟高的。为了升高回滚率,云溪数据库引入了工夫戳 forward(push)机制,规定如下:一个事务保护两个工夫戳,readTS 和 writeTS。事务在 readTS 上执行所有读取操作,以获取始终性快照;所有的写操作在 writeTS 产生,当遇到 RW 抵触时,W 事务的 writeTS forward 到抵触工夫戳的 ts.next,而后继续执行,在必要时刻或者最终提交时进行查看尝试将 readTS refresh 到 writeTS,如果胜利,则事务提交,否则事务回滚。
在这个机制之下,当遇到上图的场景时,因为 txn1 在 commit 时能把它的 readTS refresh 到 writeTS,所以 txn1 还是能够提交。然而在规范的工夫戳排序协定中,因为 txn1 write(B)时发现 B 的 R -Timestamp 大于本人的 ts,所以事务 txn1 须要回滚。
4. 云溪数据库事务模型总结
· 没有单点和集中式解决,扩展性好
· 因为同步点机制,任何抵触都须要拜访同步点来确认抵触的最终后果,网络交互多
· 锁和数据一起存储,每个写操作都会给存储引擎产生两三倍的写入压力,抵触解决流程波折
· HLC 的时钟偏移太大,在某些场景下对同一数据的 W、R 容易导致重试
· 工夫戳排序并发控制协议比拟乐观、导致事务容易重试和回滚,且代价较大