关于 Scalar DLT 的第一部分 – Scalar DB 编辑
我从12月份开始在一家叫做 Scalar 的公司工作(入职申请在这里)。Scalar 是一家开发和销售具有可扩展性和防篡改性的分布式账本软件 Scalar DLT 的数据库供应商。这次,我想要借此机会来解释一下 Scalar DLT,也是为了自己的学习。

Scalar DB是什么?
Scalar DB是一个Java库,可以将不符合ACID标准的分布式数据库/存储转变为符合ACID标准的。Scalar DB只是一个库,数据并不由Scalar DB自身保存,而是存储在使用的分布式数据库/存储中。
此外,Scalar DB不会损害使用的分布式数据库/存储(例如Cassandra)的可扩展性和可用性,同时支持ACID事务。关于这些机制,将在接下来进行说明。
标量数据库的架构

关于存储适配器的实现
在实现「存储适配器」时,需要根据所需实现的存储方式,实现以下的DistributedStorage接口。
然而,在Scalar DB中,我们假设满足以下条件的存储器。
-
- Linearizableなレコードの読み込みができる
-
- Linearizable(Atomic)なコンディショナルアップデート(いわゆるCAS操作)ができる
- 各レコードにメタデータを入れることができる
Scalar DB的数据模型
Scalar DB的数据模型是所谓的多维映射结构。一条记录包含分区键(Partition key)和聚簇键(Clustering key),以及带有名称(Value name)的多个值(Value content)。一个值会根据分区键、聚簇键以及该值的名称进行唯一映射。
(Partition key, Clustering key, Value name) -> Value content

此外,每个值都有其相应的数据类型。目前支持以下数据类型。
-
- BOOLEAN
-
- INT
-
- BIGINT
-
- FLOAT
-
- DOUBLE
-
- TEXT
- BLOB
关于交易功能
标量DB的事务在客户端进行协调,因此不需要主控中心的角色。这样一来,可以在不影响分布式数据库/存储的可伸缩性和可用性的情况下执行事务。

关于事务协议。
Scalar DB采用乐观并发控制(OCC)作为其并发控制方法,并类似于2阶段提交作为其提交协议。此外,还采用了称为惰性恢复(Lazy Recovery)的处理方式,即当事务发生崩溃时,当其他事务读取已由崩溃事务进行写入的记录时,将触发恢复处理。
Scalar DB的事务协议如下所示。
-
- 开始事务,并进行数据的读写。对于数据的读取,实际上是从存储中读取,并将该数据存储在本地内存的读取集中。对于数据的写入,在此时并不实际写入到存储中,而是将其存储在本地内存中的写入集中。
-
- 当读写操作完成后,进入准备阶段。
针对每条写入记录,使用条件更新(条件为Version=<前一个Version>且TxID=<前一个TxID>)将状态更改为PREPARED,并更新Version和TxID,并将应用程序数据和WAL信息写入。
如果对所有记录的条件更新都成功,则Prepare操作成功。如果对所有记录的条件更新都失败,则回滚已成功的条件更新记录,并使事务中止。
如果Prepare操作成功,则进入Commit阶段。
将新TxID的记录作为COMMITTED使用条件更新(条件是该TxID的记录不存在)插入到Coordinator表中。
如果条件更新操作成功,则使用条件更新(条件为Status=PREPARED且TxID=<新TxID>)将每条记录的状态更改为COMMITTED。如果条件更新操作失败,则回滚所有记录。
这个协议的主要点在于使用了条件更新。举个例子,在准备阶段,通过对每个记录进行条件更新,即使有多个事务同时尝试对同一条记录进行写入,只有一个事务会成功。对于对Coordinator表的写入,也是同样的情况,无论是事务还是Lazy Recovery同时尝试进行写入,只会有一个成功。这样可以防止产生矛盾的状态。
如果仅仅通过文章难以理解的话,请参考以下资料:
关于Lazy Recovery大懒癌和偷懒的观点
当读取到未提交(状态不为COMMITTED)的记录时,Lazy Recovery会被触发,它位于事务协议中的第一个位置。
懒人恢复的步骤如下:
-
- 根据要恢复的记录的TxID,查询Coordinator表,检查该事务的Status。
-
- 如果Status为COMMITED,则执行前向回滚并按照事务协议3-2的步骤将要恢复的记录的Status更改为COMMITED。
-
- 如果Status为ABORTED,则执行回滚操作,并根据WAL的信息将要恢复的记录的数据还原到先前的版本。
-
- 如果Coordinator表中不存在具有该TxID的记录,则将该TxID的记录插入Coordinator表,并将Status设置为ABORT,使用条件性更新(条件是不存在具有该TxID的记录)。
- 执行回滚操作,将要恢复的记录的数据通过WAL的信息还原到先前的版本。
关于事务崩溃时的恢复
如果在事务协议1的过程中发生事务崩溃,则在此时尚未对存储进行任何写入,因此无需采取任何措施。
如果在事务协议2中,对某些记录的条件更新成功后发生事务崩溃,则在恢复目标记录被其他事务读取时将触发延迟恢复,该记录将被回滚,崩溃的事务将被正式中止。
如果在事务协议3-1中,将新TxID记录作为其状态为COMMITTED放入Coordinator表后崩溃,则在恢复目标记录被其他事务读取时将触发延迟恢复,并且将进行前向恢复。
换句话说,如果事务在进行中崩溃,并且存在部分完成的记录,Lazy Recovery将通过惰性方式进行恢复。
关于分离水平的问题
Scalar DB 支持快照隔离(以下简称SI)和可串行化作为隔离级别。不过,Scalar DB 的SI与ANSI定义的SI有所不同,更接近于SQL Server 中使用的读取已提交的快照隔离(RCSI)。在Scalar DB 的SI中,除了通常发生在SI的异常现象,如写偏斜异常和只读事务异常外,还可能发生读取偏斜异常。关于这些异常现象,可以参考本文。
在Serializable级别中,目前有两种实现方法,分别为Extra-write和Extra-read,并且可以选择使用。这两种方法都是避免SI中可能发生的异常现象——反依赖性的方法。Extra-write主要是通过将读取转换为写入来消除反依赖性,而Extra-read则是在提交阶段重新读取读取集中的数据,并检查反依赖性是否实际发生。
总结
这次,我们讲解了Scalar DLT的一个组成要素Scalar DB。下一次,我们计划要讲解另一个组成要素Scalar DL。
我们正在招聘!
Scalar正在招募一起工作的成员!详细信息请查看以下链接:
https://angel.co/company/scalar-inc/jobs
如果您在阅读这篇文章后对Scalar产生了一丝兴趣,并且希望参与其中,请通过上述URL报名!
如果您还有其他问题、咨询或其他事项,可以直接通过我的Twitter账号向我私信。
请在中国人自然语言中对以下内容进行改写:
参考
Scalar DB
Scalar DB 设计文档
Scalar DB:一个使非ACID数据库符合ACID标准的库
使Cassandra更加强大、更快、更可靠(在ApacheCon@Home 2020会议上)