长安链数据存储介绍及Mysql存储环境搭建

概述

存储模块负责持久化存储链上的区块、交易、状态、历史读写集等账本数据,并对外提供上述数据的查询功能。区块链以区块为单位进行批量的数据提交,一次区块提交会涉及到多项账本数据的提交,比如:交易提交,状态数据修改等,所以存储模块需要维护账本数据的原子性。长安链支持常用的数据库来存储账本数据,如LevelDB、BadgerDB、TikvDB、MySQL等数据库,业务可选择其中任意一种数据库来部署区块链。

账本数据主要分为5类:

1、区块数据,记录区块元信息和交易数据:

  • 区块元数据包括:区块头、区块DAG、区块中交易的txid列表,additionalData等;
  • 交易数据,即序列化后的交易体,为了提供对单笔交易数据的查询,所以对交易数据进行了单独存储。

2、状态数据,记录智能合约中读写的链上状态数据,即世界状态。

3、历史数据,长安链对每笔交易在执行过程中的状态变化历史、合约调用历史、账户发起交易历史都可以进行记录,可用于后续追溯交易、状态数据的变迁过程。

4、合约执行结果读写集数据,长安链对每笔交易在执行过程中的所读写的状态数据集进行了单独保存,方便其他节点进行快速的数据同步。

5、事件数据,合约执行过程中产生的事件日志。

存储模块运行逻辑

针对上述5类账本数据,长安链分别实现了5个DB类,分别是:Block DB、State DB、History DB、Result DB和Contract Event DB。采用多个数据库之后,就需要维护数据库之间的数据一致性,避免仅有部分数据库提交后,发生程序中断而导致不同数据库间的数据不一致,因此,长安链引入了Block binary log组件来持久化存储区块的原始内容,用于重启过程中的数据恢复,类似于数据库中的预写式日志(wal)的功能。 需要注意的是,历史数据、结果数据并不是每个节点必须保存的,节点可以根据自己的业务需要在配置文件中启用或者关闭历史数据库和结果数据库。

1.存储模块未开启区块文件存储时运行逻辑

 区块提交流程

  1. 首先将序列化后的区块、读写集数据、以及最新的区块高度写入Block binary log,用于异常中断后的数据恢复。为了提高性能,加入一层cache,新区块提交请求在更新完Block binary log之后,再将区块数据写入cache,在更新完log和cache后,提交即可返回,由后台线程异步更新Block DB、State DB、ContractEvent DB、History DB和Result DB。

  2. 在Block DB中记录区块元信息与交易信息,其中交易信息以TxID作为主键存储,区块信息以BlockHeight作为主键存储,区块元信息中只记录交易ID列表,同时索引BlockHash到BlockHeight的映射关系。Block DB中额外记录了当前最新的区块高度(LastBlockHeight)作为checkpoint,用以重启后的数据恢复。

  3. 在State DB中保存state数据,key为合约名与对象主键的组合:<contractName, ObjectKey>,同时记录最新的区块高度(LastBlockHeight)作为checkpoint。

  4. 在History DB中记录交易产生的三种类型的索引:

    1. 状态变更历史,以<contractName, ObjectKey,TxId>为索引

    2. 合约调用历史,以<contractName, TxId>为索引

    3. 账户交易历史,以<accountId,TxId>为索引

  5. 在Result DB中记录交易的读写集,读写集以TxID作为key,同时记录最新的区块高度(LastBlockHeight)作为checkpoint。

  6. 在ContractEventDB中记录下交易结果的EventLog,并记录最新区块高度作为checkpoint。

数据库

概述

存储模块中的Block DB、State DB、History DB等都是封装后的DB对象,其具体实现要基于特定的数据库引擎,比如LevelDB、BadgerDB、TikvDB、MySQL等数据库引擎。为了实现可插拔的数据库引擎,长安链在数据库引擎之上封装了一层接口,并将LevelDB、BadgerDB、TikvDB、MySQL等数据库封装成DB provider。用户可以根据业务需求选择合适的数据库引擎作为长安链的底层存储组件。

源码

chainmaker / store · ChainMaker长安链2.0版本存储基础模块项目https://git.chainmaker.org.cn/chainmaker/store

支持的数据库类型

长安链目前支持4种数据库引擎可供选择,分别是LevelDB、BadgerDB、TikvDB、MySQL。

  • LevelDB,默认采用的数据库引擎,LevelDB作为一款嵌入式KV数据库,默认集成在长安链节点中,无需部署,性能也相对关系型数据要更好。

  • BadgerDB,作为另一种形式的KV单机数据库的实现,也是嵌入式KV数据库,性能在写入value比较大时比LevelDB更高,但是读性能可能差于LevelDB

  • TikvDB,作为KVDB的横向扩容版本,需要单独启动tikv服务,底层使用rocksdb,性能更高。tikv部署流程

  • MySQL,关系型数据库,支持schema和富查询,性能较KV数据库低,目前关系型数据库与区块链的状态数据并不能很好的结合,导致很少有区块链采用关系型数据库作为状态数据库。原因主要有两点:1.区块链需要对智能合约所读写的状态数据做严格的控制和校验,而SQL语句相对区块链来说过于灵活,难以控制;2.需要提前创建库表和索引,需要针对不同的智能合约创建不同的数据库表结构,不够灵活。目前长安链支持MySQL存储引擎,在系统数据如Block DB上支持区块元信息、交易信息的关系型语义,状态数据库支持kv的方式和智能合约编写SQL语句方式读写状态数据(world state)。

数据库配置说明

配置文件在节点本地配置文件chainmaker.yml中

storage:
  store_path: ../data/ledgerData  #账本的存储路径, 包括LevelDB、BadgerDB的数据目录,Block binary log的数据目录
  write_buffer_size: 4  #LevelDB的write_buffer_size, 单位为MB,默认为4M
  bloom_filter_bits: 10  #LevelDB的布隆过滤器参数,为每个key分配的额外bit空间,默认为10,如果少于或等于0,则不开启布隆过滤。
  disable_historydb: false  #是否禁用历史读写集的存储功能, 默认为false,也就是保存历史读写集。
  disable_block_file_db: false  #是否禁用区块文件存储功能, 默认为true,也就是未启用,新节点建议此处设置为false。
  logdb_segment_async: false  #区块文件异步落盘与否, 默认为false,也就是默认同步落盘,异步落盘时存在断电后数据损坏风险。
  logdb_segment_size: 128  #区块文件大小,单位MB,默认20MB。
  blockdb_config: #BlockDB 数据库配置
    provider: leveldb #数据库类型,支持LevelDB,BadgerDB,TikvDB,Mysql,这里示例为LevelDB
    leveldb_config: #LevelDB的详细配置
      store_path: ../data/org1/blocks
      write_buffer_size: 4	#LevelDB的write_buffer_size, 单位为MB,默认为4M
      bloom_filter_bits: 10	#LevelDB的布隆过滤器参数,为每个key分配的额外bit空间,默认为10,如果少于或等于0,则不开启布隆过滤。
      block_write_buffer_size:
  statedb_config: #StateDB 数据库配置
    provider: sql  #数据库类型,支持LevelDB,BadgerDB,TikvDB,Mysql,这里示例为Mysql
    sqldb_config: #SQL数据库的详细配置
      sqldb_type:  mysql #具体的RDBMS为mysql,也可以是sqlite、mssql等
      dsn:  root:password@tcp(127.0.0.1:3306)/ #MySQL的数据库连接字符串
      max_idle_conns: 10  #连接池中维持的最大的空闲连接数,默认为10
      max_open_conns: 10  #最大的可用连接数,默认为10
      conn_max_lifetime: 60  #连接维持的最长时间,单位秒,默认为60
  historydb_config: #HistoryDB数据库配置
    provider: badgerdb #数据库类型,支持LevelDB,BadgerDB,TikvDB,Mysql,这里示例为BadgerDB
    badgerdb_config:
      store_path: ../data/org1/history
      compression: 0 # value为0 不压缩,1 Snappy压缩,2 ZSTD压缩,默认为0
      value_threshold: 10240 # 单位为bytes,默认为10240 bytes
  resultdb_config: #ResultDB数据库配置
    provider: tikvdb # 支持LevelDB,BadgerDB,TikvDB,Mysql
    tikvdb_config:
       endpoints: "127.0.0.1:2379" # tikv pd server url,支持多个url, 如: "192.168.1.2:2379,192.168.1.3:2379"
       max_batch_count: 128 # 每次kv batch最大大小 默认128
       grpc_connection_count: 4 # chainmaker连接tikv的连接数, 默认4
       grpc_keep_alive_time: 10 # 保持连接的连接数, 默认10
       grpc_keep_alive_timeout: 3 # 保持连接的超时时间 默认3
       write_batch_size: 128 # 每次提交tikv批次最大大小,默认128
  disable_contract_eventdb: true  #是否禁止合约事件存储功能,默认为true,如果设置为false,需要配置mysql
  contract_eventdb_config:
    provider: sql                 #如果开启contract event db 功能,需要指定provider为sql
    sqldb_config:
      sqldb_type: mysql           #contract event db 只支持mysql
      dsn: root:password@tcp(127.0.0.1:3306)/  #mysql的连接信息,包括用户名、密码、ip、port等,示例:root:admin@tcp(127.0.0.1:3306)/

mysql数据库配置

storage:
  # Default store path
  store_path: ../data/ljh-org1.qianjinlian.com/ledgerData1 # [*]

  # Prefix for mysql db name
  # db_prefix: org1_

  # Minimum block height not allowed to be archived
  unarchive_block_height: 300000

  # Symmetric encryption algorithm for writing data to disk. can be sm4 or aes
  # encryptor: sm4    # [*]

  # Disable block file db, default: false
  disable_block_file_db: false

  # async write block in file block db to disk, default: false, so default is sync write disk
  logdb_segment_async: false

  # file size of .fdb, MB, default: 20
  logdb_segment_size: 128

  # bigfilter config
  enable_bigfilter: false    #default false
  bigfilter_config:
    redis_hosts_port: "127.0.0.1:6300,127.0.0.1:6301"   #redis host:port
    redis_password: abcpass  #redis password
    tx_capacity: 1000000000   #support max transaction capacity
    fp_rate: 0.000000001      #false postive rate

  # RWC config
  enable_rwc: true   #default false

  # suggest
  # if block_tx_capacity < 10000,
  # set rolling_window_cache_capacity greater than block_tx_capacity*1.1 and less than block_tx_capacity*2
  # if block_tx_capacity > 10000,  set rolling_window_cache_capacity 20000
  rolling_window_cache_capacity: 200

  # Symmetric encryption key:16 bytes key
  # If pkcs11 is enabled, it is the keyID
  # encrypt_key: "1234567890123456"
  write_block_type: 0  # 0 common write,1 quick write
  disable_state_cache: false # default false
  state_cache_config:
    life_window: 3000000000000   #key/value ttl time, ns
    clean_window: 1000000000
    max_entry_size: 500
    hard_max_cache_size: 10240   #cache size MB
  # Block db config
  blockdb_config:
    # Event db only support sql
    provider: sql
    # Sql db config
    sqldb_config:
      # Event db only support mysql
      sqldb_type: mysql
      # Mysql connection info, such as:  root:admin@tcp(127.0.0.1:3306)/
      dsn: root:root@tcp(192.168.0.201:3306)/

    # Example for sql provider
    # Databases type support leveldb, sql, badgerdb, tikvdb
    # provider: sql # [*]
    # If provider is sql, sqldb_config should not be null.
    # sqldb_config:
      # Sql db type, can be mysql, sqlite. sqlite only for test
      # sqldb_type: mysql # # [*]
      # Mysql connection info, the database name is not required. such as:  root:admin@tcp(127.0.0.1:3306)/
      # dsn: root:password@tcp(127.0.0.1:3306)/

    # Example for badgerdb provider
    # Databases type support leveldb, sql, badgerdb, tikvdb
    # provider: badgerdb
    # If provider is badgerdb, badgerdb_config should not be null.
    # badgerdb_config:
      # BadgerDb store path
      # store_path: ../data/wx-org1.chainmaker.org/history
      # Whether compression is enabled for stored data, default is 0: disabled
      # compression: 0
      # Key and value are stored separately when value is greater than this byte, default is 1024 * 10
      # value_threshold: 256
      # Number of key value pairs written in batch. default is 128
      # write_batch_size: 1024

    # Example for tikv provider
    # provider: tikvdb
    # If provider is tikvdb, tikvdb_config should not be null.
    # tikvdb_config:
      # db_prefix: "node1_" #default is ""
      # endpoints: "127.0.0.1:2379" # tikv pd server url,support multi url, example :"192.168.1.2:2379,192.168.1.3:2379"
      # max_batch_count: 128  # max tikv commit batch size, default: 128
      # grpc_connection_count: 16 # chainmaker and tikv connect count, default: 4
      # grpc_keep_alive_time: 10 # keep connnet alive count, default: 10
      # grpc_keep_alive_timeout: 3  # keep connnect alive time, default: 3
      # write_batch_size: 128 # commit tikv bacth size each time, default: 128
  # State db config
  statedb_config:
    # Event db only support sql
    provider: sql
    # Sql db config
    sqldb_config:
      # Event db only support mysql
      sqldb_type: mysql
      # Mysql connection info, such as:  root:admin@tcp(127.0.0.1:3306)/
      dsn: root:root@tcp(192.168.0.202:3306)/

  # History db config
  historydb_config:
    provider: sql
    disable_key_history: false
    disable_contract_history: true
    disable_account_history: true
    # Sql db config
    sqldb_config:
      # Event db only support mysql
      sqldb_type: mysql
      # Mysql connection info, such as:  root:admin@tcp(127.0.0.1:3306)/
      dsn: root:root@tcp(192.168.0.203:3306)/

  # Result db config
  resultdb_config:
    # Event db only support sql
    provider: sql
    # Sql db config
    sqldb_config:
      # Event db only support mysql
      sqldb_type: mysql
      # Mysql connection info, such as:  root:admin@tcp(127.0.0.1:3306)/
      dsn: root:root@tcp(192.168.0.204:3306)/

  # Disable contract event database or not. If it is false, contract_eventdb_config must be mysql
  disable_contract_eventdb: true
  # Contract event db config
  contract_eventdb_config:
    # Event db only support sql
    provider: sql
    # Sql db config
    sqldb_config:
      # Event db only support mysql
      sqldb_type: mysql
      # Mysql connection info, such as:  root:admin@tcp(127.0.0.1:3306)/
      dsn: root:root@tcp(192.168.0.205:3306)/

注意事项

  1. mysql数据库需要提前部署且每个节点都必须部署一套mysql环境,不可多个节点共用同一个mysql数据库。
  2. 每个节点都需要修改chainmaker.yml配置文件中的storage部分。
  3. 旧链或者已经有数据的链最好不要改数据存储方式,否则会导致链不可用。
  4. 示例中的dsn: root:root@tcp(192.168.0.205:3306)/,roo为数据库账号和密码,192.168.0.205:3306为数据库IP和端口,请根据自己的实际环境修改替换。
  5. mysql数据库部署方式参考:
docker run -p 3306:3306 --name mysql  -v /mydata/mysql/log:/var/log/mysql -v /mydata/mysql/data:/var/lib/mysql -v /mydata/mysql/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

     6. 如何是中途将leveldb环境切换成mysql则需要清理各节点的data和log目录,然后重启节点,否则会出现mysql数据库表创建不成功的情况。

     7.如果需要将所有节点都链接同一个数据库,则需要把前缀db_prefix: org1_打开,并配置不同的前缀,位置在:

storage:
  # Default store path
  store_path: ../data/ljh-org1.qianjinlian.com/ledgerData1 # [*]

  # Prefix for mysql db name
  db_prefix: org1_

猜你喜欢

转载自blog.csdn.net/h363659487/article/details/125445686