随着区块链技术发展和应用场景逐步丰富,越来越多的人开始接触区块链。但在过程中,很多人提过这样的问题:“底层用区块链系统和用数据库有什么区别呢?”、“区块链系统是不是就是一个OLTP数据库系统?”等,趣链科技区块链基础平台部技术专家郭威来解惑。

从直观的角度来说,完整的区块链系统内部一定会包含一个「存储模块」,整体上来说,区块链系统确实可以起到持久化数据的作用。但从这个角度出发,直接将区块链系统看作是一个数据库,这样的观点也是不合适的。在作出最终比较之前,趣链科技区块链技术专家郭威带您先来分析一下传统数据库系统的运行机制以及区块链系统内部存储模块的功能职责。

 传统OLTP数据库存什么?现在的数据库系统、存储引擎的设计一般是面向某一通用场景的,比如sql型数据库、NoSQL型数据库(kv数据库、文档数据库等),而不是面向具体业务场景的,那一般的OLTP数据库内部的数据分为四大类:

第一类,数据库内部的管理性质的元数据。这部分数据基本上对用户是透明的,负责数据库内部的管理与控制逻辑;

第二类,用户自定义数据。这部分数据是用户通过API向数据库写入的数,数据库系统一般不关心这部分数据的具体内容,而是侧重于如何正确、完整的将这些数据保存到持久化设备;

第三类,索引数据。索引数据一般是数据库设计中不可或缺的一个组成部分。为了保证数据库“读数据”功能的响应时间在用户可接受范围内,几乎所有数据库系统都需要或多或少的引入索引;

第四类,日志数据。日志数据是一种数据库内部数据,其内容一般是记录数据变更行为,一般用于数据库宕机重启后的数据恢复。在不同的数据库中,日志数据的内容差距也非常大,比如:有的数据库使用日志来记录存储层的数据变更(磁盘上位置X开始,连续N个字节从Value1变成了Value2),有的数据库使用日志来记录用户的写入命令请求(比如插入操作,内容为key=1,value="ABC")等等。

 区块链存储模块有何不同?站在区块链系统内部“数据存储”功能的角度看待“区块链系统”时,会发现区块链系统具有确定性的系统架构、确定性的内部业务逻辑,以及一些通用的数据组织格式(比如:区块是一种append-only形式的数据、只有虚拟机执行指令的过程中会修改状态数据等)。区块链系统中的数据存储只需要满足这一套运转逻辑过程中的持久化需求即可,也就是说,区块链系统为其存储模块划定了比通用数据库更小的模块功能边界。

图表 1趣链科技区块链数据存储流程

区块链存储存什么?——世界状态,从使用者角度来看,一个最常规的区块链服务是由一个区块链网络提供的。区块链网络由多个节点构成,用户可以向区块链服务发送交易,区块链网络中的所有参与共识的节点会针对交易的内容、执行过程、执行结果达成一致的决议,并将执行结果返回给发起交易的用户。

上述过程是一个最常规的区块链服务使用流程。但是,如果从区块链网络中的节点的角度出发,节点感知的过程或者变化有哪些呢?略去网络交互、共识、执行等等的细节说明,趣链科技区块链技术专家郭威直接带您讨论关注的重点——“世界状态”:

如果将区块链可以看为一个分布式的状态机:所有节点从同一个创世状态开始,依次执行相同顺序的交易,驱动各个节点的状态按照相同操作序列不断变化,实现所有节点在同一交易序列执行完成后,状态完全一致。而这个状态,就称为“世界状态”。

在区块链网路中,所有诚实节点本地维护的“世界状态”是一致的,这个“世界状态”就是区块链存储模块要重点关注的内容。解释了 “世界状态” 的定义,还是要关注 “世界状态” 到底包括什么内容:首先,一个区块链系统中的数据状态的更迭,一定是由 “用户交易” 驱动的,那么只需要保证 ‘世界状态’ 能够涵盖交易的“请求内容、执行过程和执行结果” 三部分内容,就可以满足上述 “分布式状态机” 中的一致性要求。接下来,趣链科技区块链技术专家郭威将从三个角度分别分析“世界状态”中要存储的具体内容。

区块链系统通用的存储内容——块链结构,区块链系统中,区块通过保存前序区块的标识(一般都是用区块哈希)来形成逻辑上的一条链。这样做的目的和意义本文不再赘述,这里重点关注的是这个“区块”的数据组织和存储形式。

账本数据——UTXO模型账本VS账户模型账本,区块数据内部包含了交易内容,但是交易的内容一般只定义了对区块链上数据的修改请求,“执行过程” 和 “执行结果” 这两部分数据可能并不包含于交易内容中。本节将首先讨论交易 “执行过程” 对 “世界状态” 的影响。为此,我们引入了 “账本数据” 的概念。

交易执行结果/回执数据,“UTXO模型” 的系统交易执行结果比较直接,所有的合法交易的执行结果就是成功标识+ “交易输出” 内容;所有非法交易的执行结果就是失败标识,而交易的输入部分保持原状。

至此,交易数据+账户空间+交易执行结果三者一同构成了账户模型下的系统的最基本的世界状态。相应的,这类系统中的存储模块,需要提供这三类数据的存储功能。在具体设计和实现存储模块时,可以结合区块链系统的运作模式,综合考虑吞吐量和延迟等指标,根据不同数据的业务特点设计和使用不同的底层存储引擎。

一个完整的区块链系统除了提供上述写入功能外,还需要提供历史数据的查询功能。如果系统中只存储了上述世界状态数据,那么用户对历史数据的查询只能通过遍历所有区块实现,这样的代价和延迟很显然是无法接受的。

因此,一般的区块链系统都会考虑设置一种基本的索引——交易索引。借由这种索引,系统能够快速的确认交易所在的区块,甚至可以更细粒度的直接定位到交易存储于这个区块内的哪个位置。索引的内容一般就是“交易哈希(交易标识)”到“交易所在位置”的映射。

这样的索引设计会给系统持久化区块的过程带来一定的 “写放大” ,单无论从数据量还是从必要性角度出发,一般的区块链系统都会选择接受这种代价。

至此,一个简单通用的区块链系统必要的存储内容已经介绍完毕。但是这还不是区块链系统的存储模块需要考虑的全部内容。在区块链网络中,所有诚实节点在相同的区块执行完毕后,需要拥有完全一致的世界状态。这个世界状态可以由区块确认后的 “区块哈希”表示。

但是,区块链系统一般会运行在一个拜占庭网络环境中;那么,区块链系统随时存在着数据落后的情况,整个网络也存在着随时新增和删除节点的情况。无论是落后的诚实节点,还是新增进入网络的诚实节点,都需要尽快追赶上网络中的其他诚实节点。

那么落后的节点如何 “追赶” 其他的诚实节点呢?这里我们再重新审视一下 “交易” 这个角色。前文提到:“区块链系统的整体数据状态是依赖交易的执行而不断向后演进的”,那么交易就可以看作是区块链系统世界状态变更的 “日志” 。

基于这样的理解角度,落后节点 “追赶” 其他诚实节点可以通过同步诚实节点的区块来实现,因为区块中的区块体包括了全量的交易内容,那么落后节点可以通过重放其缺少交易,最终达到与其他节点一致的世界状态。这个恢复的过程,落后节点不需要参与共识,而是借由一系列校验协议来确保数据的完整性和正确性。

进一步分析上述交易重放流程,如果是UTXO模型的系统,交易的内容和执行过程比较简单;但是对于账户模型的系统,则交易可能是合约执行请求,那么执行这笔交易的过程就不可避免的会涉及执行环境的创建,使用虚拟机执行完整的合约指令等等步骤。那么,对于节点间网络环境较好的场景,是不是有进一步提高落后节点“追赶”速度的策略呢?

由此,在特定的场景下,比如 “联盟链+账户模型” 的系统中,数据同步的过程可以引入另一种策略:如果在交易执行的过程中,系统将所有的账本数据(也就是账户空间)修改相关的操作都记录下来,形成一份账本操作日志数据(可以类比MySQL中Binlog的row模式思路);那么在做数据同步时,落后节点可以直接拉取区块数据、账本操作日志数据和交易回执数据,完成后并将拉取账本操作日志数据按序应用到本地账本数据上,完成应用日志的过程后,落后节点便完成了与其他诚实节点一致的“世界状态”的构建。

基于上述思路,存储模块可以引入另一种与世界状态有关的数据——操作日志数据,这些数据与交易的执行过程强相关。在某些网络带宽充裕、智能合约计算逻辑复杂但账本数据修改不频繁的场景下,上述思路是一种有效加速节点间数据同步的解决方案。

至此,本文第一个引入的 “区块链存储模块是不是数据库” 的问题,可以做一个简单的总结:趣链科技区块链技术专家郭威认为,数据库和区块链存储是可以区分开来看待的概念,区块链存储模块无论从功能边界、服务对象还是自身的拓展优化思路上,都是和 “区块链系统” 这个场景强相关的。但是OLTP数据库系统,其考虑的场景则是一个更宽广、更通用的层面。