当前位置: 首页 > 科技观察

区块链存储机制解密:与数据库存储机制接轨

时间:2023-03-13 23:33:33 科技观察

从数据库的角度来看,区块链的存储机制会更加简单直观。在标准的关系型数据库中,存储一般分为三类:日志存储、用户数据存储、索引存储(有些数据库可能还包括大对象存储等)。区块链项目中所有“账本”存储的本质都是交易日志存储。根据不同的项目有选择地采用用户数据存储。例如,对于UTXO结构的区块链项目,每个账户对应的余额直接存储在内存哈希表中(或者在LevelDB等嵌入式KV数据库中),因此不需要独立的外部用户数据存储模块。Hyperledger等通用区块链框架通常包括存储最终结果数据的StateStore等模块。当前大多数区块链项目中不存在索引存储。1、账本格式区块链的链式结构在此不再赘述。每个区块都包含前一个区块的哈希值,内容使用默克尔树进行验证,实现快速验证。每条记录都使用数字签名的方法保证它必须来自拥有私钥的用户。图1:区块链数据结构与传统数据库的日志结构相比,区块链结构并不复杂。一般来说,所有传统数据库的日志结构都比较相似。每个日志文件包含一个日志头和多个日志数据页,其中日志头代表它的起始事务号(在Oracle中称为SCN,在DB2中称为LSN),即日志文件中第一条日志记录的起始字节号整个日志空间,以及日志文件大小和日志页面大小等元数据信息。然后将真正的日志记录以二进制码流的形式依次存储在文件中。每条日志记录头包含该记录的事务号、事务号、同一事务中前一条记录的事务号(反向指针)。以及变化前后的数据(满足回滚要求)。图2:数据库日志结构因此,从结构上看,区块链账本和数据库日志本质上没有区别,只是在数据结构上做了一些优化,以满足一些特定的需求。2、从日志的角度来看,通用数据库与目前大多数区块链账本项目(如比特币、以太坊等,不包括Hyperledger等区块链平台)存在巨大差异。原因在于区块链账本项目对日志格式进行了高度定制化,并与业务绑定。一般来说,传统的数据库日志包含了数据页的变化信息,我们称之为“写入前镜像”和“写入后镜像”,代表了新数据写入前记录的样子,同时新的数据写入了这条记录是什么样子的。这样就可以方便的对数据页在磁盘中的指定偏移量进行数据的前滚和回滚操作。例如,数据库日志不记录INSERT操作的具体命令,而是采用“X数据页的第Y槽,对应偏移地址数据由ABC变为DEF,总长度为Z”的方式”。反映。因此,数据库日志几乎可以记录任何信息,这也是为什么可以用一个通用的数据库来实现任何业务逻辑的原因。大多数分类帐项目高度自定义其日志结构。例如,以太坊的每笔交易信息都会包含输入量、输出量、燃料等信息,然后每个节点在进行验证时必须判断自己是否符合一定的规则。否则不会通过。这种机制可以看作是一个完全高度定制化的数据库业务。每条日志记录不仅记录数据内容的变化,而且与业务逻辑紧密耦合,记录每个账户的余额变化。因此,从可扩展性来看,以太坊等项目虽然支持“智能合约”,但其核心本质仍然是一个高度定制化的账本系统,其业务逻辑与交易结算紧密绑定。3.设计思路从设计理念来看,目前的区块链和数据库在支持通用服务方面采用了两种不同的策略。对于传统数据库,其秉承的设计理念是“业务与数据分离”的思想,即数据库只负责数据的存储,通过提供灵活的查询语言,应用程序可以直接访问数据库进行增删改查,但基本上所有的业务逻辑都是由应用程序本身定义的。但是,对于区块链来说,存储和业务逻辑是紧耦合的。在区块链尤其是公链的设计理念中,由于每个存储节点和应用都是不可信任的,所以大部分业务逻辑都需要在协议层进行高度定制。区块链节点需要对协议层进行解析和封装,同时负责数据的本地化和存储。因此,虽然区块链在高层次上可以看作是一个多活数据库,但从具体的实现层面来说,每个区块链节点都不能简单地看作是传统数据库的多活替代品。它是一套包括协议解析和封装以及部分业务逻辑的应用软件。4.用户数据存储如果未来区块链的目标是作为存储各类数据的通用平台,其日志格式和存储必须回归到数据库的通用本源。目前的账本模型可以作为一个特殊的模块存在于系统中,用于账户之间的结算,但不能扩展为一个通用的业务平台。由于要成为一个通用的数据存储平台,UTXO模型有一定的局限性。在典型的银行业务中,零售业务可能包含数千万甚至数亿个账户。不同的账户可能使用不同的计息规则,也可能会出现冻结等特殊状态。交易流量信息每天可能达到数千万。如果将业务扩展到非金融行业,每天可能有数亿条交易信息。因此,从一般账户+流量的商业模式来看,一般企业都会建立账户表和流量表,并以不同的策略进行管理。帐户表通常称为余额数据。在典型的数据治理系统中,需要定期进行快照备份(比如月初号、月末号);而流表则成为流数据,一般直接以原始交易格式进行存储和备份。通过恢复余额数据的快照备份,重做指定账户在一定时间范围内的所有交易记录,可以获得账户任意时间点的余额信息。UTXO的本质是日志中存储的信息不是记录的最终结果,而是变更行为。在传统数据库中,每个事务记录数据的写入前和写入后的内容。例如,要将一条记录从5更改为8,它的数据库日志记录原始数据为5,新数据为8,而不是记录“+3”。但UTXO记录找零信息,主要目的是为了解决双花问题(比如一个100元的账户,一个人在中国转10元,另一个人同时在美国转10元时间,如果记录最后的结果,那么中国的服务器会认为这个人有90元,美国的服务器也会认为这个人有90元,没有全局锁,最后写入到块,它将变成90元的余额,而不是80元)。UTXO机制在没有锁的情况下可以有效避免双花问题,但缺点是不存储余额表,所有信息都是通过重做流数据从头生成。对于一个已经存在了十几年,包含上百亿事务的系统来说,这种做法就像是每次重启都要重做几百个事务,存入内存(或者KV数据库)。一种非常原始且不经济的方式。另一方面,从区块链日志的结构来看,由于在多活系统中难以实现全局锁,需要调整交易日志的结构来满足传统数据库中的交易功能。在传统数据库中,两个账户之间转账需要开启一个交易。在事务日志中,增加一个账户和减少一个账户的业务逻辑需要体现为一个包含三个记录的链表(最后一个commit操作也是一个记录)。在数据库崩溃或异常发生后,只要重做所有任务,对所有未提交的事务进行反向操作,就可以获得原子性和持久性。在区块链系统中,由于没有交易概念,操作日志与结算业务紧密耦合,每条交易记录都会包含一个输入账户和多个输出账户,也就是说只有一条交易记录被成功处理。如果发送到一个节点,可以保证记录内的所有输入输出账户都被统一更改。可以说,区块链通过定制化的交易日志简化了交易操作的复杂性,但带来的影响是业务和代码紧耦合,密不可分。但无论如何,首先,UTXO并不是一个通用的数据结构,而是一个针对交易业务高度定制化的数据结构。如果要运行图灵完备的智能合约(或存储过程),使用UTXO会有很多限制。二、对于长时间运行的大型系统(与大中型银行核心交易系统产生的交易流量相比,比特币从诞生到现在的交易量可以忽略不计),UTXO要求所有历史交易对于每个初始化日志。这种模式是完全不可能适用于大型交易系统的。因此,有两种方法可以解决这个问题。第一种方法利用传统账户表和流表的机制,以流的形式反映UTXO,并定期保存账户快照,避免每次重构数据库时都需要重做所有交易(该机制需要考虑在账户和水表的多活系统,如何在没有全局锁的情况下实现一致性)。对于非结算交易,通用的区块链项目可能会采用日志结合用户数据存储的方式,能够普遍满足通用的业务需求(这种机制需要依赖比nonce更好的排序机制来避免双花)。5.索引存储目前基本没有支持用户数据自定义索引的区块链项目。这种机制肯定会在未来的通用区块链项目中得到补偿。从本质上讲,目前的区块链项目结构没有理由不能在其上构建通用的索引能力(包括B树索引、位图索引、全文搜索等)。总结区块链的存储系统在80年代还处于数据库阶段。目前最大的问题在于日志结构和业务逻辑的紧耦合(读者可以理解为应用程序必须对每一个业务逻辑从头实现。又是Oracle)。其本质原因在于多活数据库中事务的原子性和锁极难保证。因此,当涉及到多账户的转账原子操作时,目前的账本区块链项目大多要自定义日志结构。将每笔交易的所有信息放在一条记录中。从数据库的角度来看,在区块链项目中实现跨记录的原子操作(包括全局锁)是极其复杂的,这也是区块链技术向通用数据存储演进的关键。笔者认为,随着区块链应用越来越广泛,在不久的将来,人们会将各种区块链应用概括为一系列典型场景和需求。基于这些场景和需求,将会有一批优秀高效的多活数据存储。不管这些机制的实现背景是否基于“块”架构,需要打破的是现有数据库系统无法实现双活的局限性(即去中心化)。