AMDB
分布式存储(Advanced Mass Database,AMDB)通过对表结构的设计,既可以对应到关系型数据库的表,又可以拆分使用KV数据库存储。通过实现对应于不同数据库的存储驱动,AMDB理论上可以支持所有关系型和KV的数据库。
- CRUD数据、区块数据默认情况下都保存在AMDB,无需配置,合约局部变量存储可根据需要配置为MPTState或StorageState,无论配置哪种State,合约代码都不需要变动。
- 当使用MPTState时,合约局部变量保存在MPT树中。当使用StorageState时,合约局部变量保存在AMDB表中。
- 尽管MPTState和AMDB最终数据都会写向RocksDB,但二者使用不同的RocksDB实例,没有事务性,因此当配置成使用MPTState时,提交数据时异常可能导致两个RocksDB数据不一致。
名词解释
Table
存储表中的所有数据。Table中存储AMDB主key到对应Entries的映射,可以基于AMDB主key进行增删改查,支持条件筛选。
Entries
Entries中存放主Key相同的Entry,数组。AMDB的主Key与Mysql中的主key不同,AMDB主key用于标示Entry属于哪个key,相同key的Entry会存放在同一个Entries中。
Entry
对应于表中的一行,每行以列名作为key,对应的值作为value,构成KV结构。每个Entry拥有自己的AMDB主key,不同Entry允许拥有相同的AMDB主key。
Condition
Table中的删改查接口支持传入条件,这三种接口会返回根据条件筛选后的结果。如果条件为空,则不做任何筛选。
数据更新或者插入过程中,需要根据主Key获取数据并将对数据更新或者append操作,然后再写回存储系统。因此,在一个主Key对应的的Entries中Entry个数很多的时候,执行效率会受到影响;同时,会加大内存的使用。所以,实际生产过程中主Key对应的的Entries中Entry个数不宜过多。
举例
以某公司员工领用物资登记表为例,解释上述名词。
Name* | item_id | item_name |
---|---|---|
Alice | 1001001 | laptop |
Alice | 1001002 | screen |
Bob | 1002001 | macbook |
Chris | 1003001 | PC |
解释如下:
- 表中Name是AMDB主key。
- 表中的每一行为一个Entry。一共有4个Entry,每个Entry以Map存储数据。4个Entry如下:
- Entry1:
{Name:Alice,item_id:1001001,item_name:laptop}
- Entry2:
{Name:Alice,item_id:1001002,item_name:screen}
- Entry3:
{Name:Bob,item_id:1002001,item_name:macbook}
- Entry4:
{Name:Chris,item_id:1003001,item_name:PC}
- Entry1:
- Table中以Name为主key,存有3个Entries对象。第1个Entries中存有Alice的2条记录,第2个Entries中存有Bob的1条记录,第3个Entries中存有Chris的一条记录。
- 调用Table类的查询接口时,查接口需要指定AMDB主key和条件,设置查询的AMDB主key为Alice,条件为
item_id = 1001001
,会查询出Entry1。
AMDB表分类
表中的所有entry
,都会有_status_
,_num_
,_hash_
内置字段。
系统表
系统表默认存在,由存储驱动保证系统表的创建。
表名 | keyField | valueField | 存储数据说明 | AMDB主key |
---|---|---|---|---|
sys_tables | tablename | key_field,value_field | 存储所有表的结构,以表名为主键 | 所有表的表名 |
_sys_consensus | name | type,nodeid,enable_num | 存储共识节点和观察节点的列表 | node |
_sys_table_access | tablename | address,enable_num | 存储每个表的具有写权限的外部账户地址 | 表的表名 |
_sys_cns | name | version,address,abi | 存储CNS映射关系 | 合约名 |
sys_config | key | value,enablenum | 存储需要共识的群组配置项 | 配置项 |
_sys_current_state | key | value | 存储最新的状态 | currentnumber/total_transaction_count |
_sys_tx_hash_2_block | hash | value,index | 存储交易hash到区块号的映射 | 交易hash的16进制 |
sys_number_2_hash | hash | value | 存储区块号到区块头hash的16进制表示的映射 | 区块高 |
sys_hash_2_block | key | value | 存储hash到序列化的区块数据 | 区块头hash的16进制 |
sys_block_2_nonces | number | value | 存储区块中交易的nonces | 区块高 |
用户表
用户调用CRUD接口所创建的表,以_user_<TableName>
为表名,底层自动添加_user_
前缀。
StorageState账户表
_contract_data_
+Address
+_
作为表名。表中存储外部账户相关信息。表结构如下
key* | value |
---|---|
balance | |
nonce | |
code | |
codeHash | |
alive |
StorageState
StorageState是一种使用AMDB实现的存储账户状态的方式。相比于MPTState主要有以下区别:
StorageState | MPTState | |
---|---|---|
账户数据组织方式 | AMDB表 | MPT树 |
历史状态 | 不支持,不维护历史状态 | 支持 |
MPTState每个账户使用MPT树存储其数据,当历史数据逐渐增多时,会因为存储方式和磁盘IO导致性能问题。StorageState每个账户对应一个Table存储其相关数据,包括账户的nonce
,code
,balance
等内容,而AMDB可以通过实现对应的存储驱动支持不同的数据库以提高性能,我们使用RocksDB测试发现,StorageState性能大约是MPTState的两倍。