WeBankBlockchain-Data 技术文档

重要

FISCO-BCOS 2.0与3.0对比、JDK版本、WeBank-Data及其他子系统的 兼容版本说明

什么是 WeBankBlockchain-Data

WeBankBlockchain-Data 是一套稳定、高效、安全的区块链数据治理组件解决方案,可无缝适配FISCO BCOS区块链底层平台。 它由数据导出组件(Data-Export)、数据仓库组件(Data-Stash)、数据对账组件(Data-Reconcile)这三款相互独立、可插拔、可灵活组装的组件所组成,开箱即用,灵活便捷,易于二次开发。

这三个组件分别从底层数据存储层、智能合约数据解析层和应用层三个方面,提供了区块链数据挖掘、裁剪、扩容、可信存储、抽取、分析、审计、对账、监管等数据治理方面的关键能力。 WeBankBlockchain-Data已在金融、公益、农牧产品溯源、司法存证、零售等多个行业落地和使用。

设计目标

在区块链底层和区块链生产应用之间,横亘着一条区块链技术、业务和产品的鸿沟。

区块链数据治理的成本较高。首先,区块链节点的数据一般以Key-Value的形式存储于文件数据库,通常只能通过智能合约的接口来获取和调用,较难抽取、分析和处理。 同时,区块链节点的数据还存在着扩容瓶颈,冷热数据切分困难。最后,区块链链上的数据需要经过多方共识,链上计算和处理的开销巨大。 而区块链生产应用的开发者从了解区块链到完成开发,需要经历陡峭的学习曲线,花费较多的时间和精力。

WeBankBlockchain-Data 定位为区块链数据治理组件,旨在通过关注区块链数据的计算和存储的不变,抓住数据治理的本质,使得区块链生产应用的开发者即便在不了解区块链的细节的场景下,也可以轻松、顺畅地管理、使用区块链数据,提供开箱即用和一站式的友好体验。

组件简介

  • WeBankBlockchain-Data-Stash 数据仓库组件

提供FISCO BCOS节点数据扩容、备份和裁剪的能力。 可基于binlog协议同步区块链底层节点数据,支持断点续传,数据可信验证,并提供快速同步机制。 请参考 Github地址 Gitee地址 文档 快速开始

  • WeBankBlockchain-Data-Export 数据导出组件

支持将链上数据导出到MySQL等结构化存储中,解决区块链数据复杂查询、分析和处理的问题。 只需简单配置、无需开发、即可实时导出个性化的业务数据,实现将裸数据转化为标准化、结构化、有序化、可视化的高价值数据。 请参考 Github地址 Gitee地址 文档 快速开始

  • WeBankBlockchain-Data-Reconcile 数据对账组件

提供区块链数据的对账解决方案。 灵活配置、无需开发,支持自定义对账数据和对账格式,支持定时对账和触发对账,对账处理模块可插拔可扩展。 请参考 Github地址 Gitee地址 文档 快速开始

总体设计

下图是数据治理组件使用的全景图。

_images/data-comp-design.png

使用场景

企业级区块链应用存在多元化角色参与,诸如业务角色、运营人员、开发角色、运维角色等。针对区块链数据,每一个特定的角色都有着不同的数据治理诉求。WeBankBlockchain-Data分别从区块链底层节点数据维护、应用数据处理和业务数据应用三个维度,抽象、设计了对应的组件来满足不同角色的对数据治理的需求。

  • 场景1:节点数据维护

数据仓库组件Data-Stash是一款针对区块链节点数据处理的轻量化、高安全、高可用组件,主要面向运维人员和开发人员。

数据备份:Data-Stash可以通过Binlog协议对区块链节点数据进行准实时全量备份,区块链节点可以根据实际情况进行冷热数据裁剪和分离,在确保数据安全可信的基础上,解决节点扩容问题,降低开发和硬件成本。在解决节点扩容问题的同时,可以使得节点“轻装上阵”,不仅能够减少节点空间的开销,而且能够有效提升节点执行交易的性能。

数据同步:对于加入区块链网络的新节点,可以通过Data-Stash,在Fisco Sync工具的配合下,快速同步区块链网络的数据,确保节点以最快的速度参与到区块链网络的“工作”中,降低新节点因等待数据同步而造成的时间浪费。

  • 场景2:应用数据处理

数据导出组件Data-Export 提供了导出的区块链标准数据、自动基于智能合约代码智能分析而生成的定制数据,存储到MySQL和ElasticSearch等存储介质中,主要面向开发人员。

复杂查询与分析:现有区块链对查询功能不太友好,且链上计算非常宝贵,Data-Export支持将链上存储的区块链数据导出到链下的分布式存储系统中。开发者可以基于已导出的区块链系统基础数据,智能合约部署合约账户、事件和函数等数据,进行二次开发,定制复杂查询和数据分析的逻辑,快速实现业务需求。例如,开发者可对交易明细根据业务逻辑进行统计和关联查询分析,开发各类反洗钱和审计监管报表等等。

区块链数据可视化:Data-Export会自动生成Grafana的配置文件,无需开发,即可实现区块链数据可视化。区块链数据可视化不仅能够作为区块链数据大盘、数据查看、运营分析的工具,同时也可以运用在应用开发、调试、测试阶段,以可见即可得的方式提升研发体验和效率。此外,Data-Export还提供了Restful API供外部系统集成。运维人员可以通过Grafana实时监控业务系统的状态,业务人员可以在集成后的业务后台系统上获得该业务的实时进展。

区块链中间件平台WeBASE的数据导出子系统已经整合了Data-Export,同时,Data-Export也可以独立与区块链底层集成,以灵活地支持业务需求,迄今已在数十个生产系统中稳定、安全运行。

如今,Data-Export作为区块链数据治理的关键组件,以开源形式发布,由社区伙伴通力完善,以适应更多的使用场景、打造更多的功能。

  • 场景3:业务数据应用

在业务层,数据对账是区块链交易系统中最常见的场景之一。基于数个区块链DAPP应用的开发和实践经验,我们封装和开发了数据对账组件Data-Reconcile,提供基于区块链智能合约账本的通用化数据对账解决方案,并提供了一套可动态延展的对账框架,支持定制化开发,主要面向开发人员,为业务人员提供服务。

企业内部对账:Data-Reconcile支持企业内部系统之间的对账,例如区块链链上数据与链下业务系统之间的对账。开发人员可以利用Data-Reconcile快速进行二次开发,将业务系统数据和链上数据进行核算比对,保证了企业内部业务系统数据的可靠和运行安全。

企业间对账:Data-Reconcile可以帮助开发者快速构建跨机构间的对账应用系统。例如,在结算时,A企业定期将自身业务系统交易数据导出为对账文件,发送至与文件存储中心。B企业可借助Data-Reconcile定期拉取A企业对账文件,配合Data-Export,与企业内部的链上数据进行对账处理。Data-Reconcile在保证对账结果可信的同时提升了对账的效率,可实现准实时对账。

数据仓库组件

https://img.shields.io/badge/license-Apache%202-4EB1BA.svgLicense

简介

Data-Stash是基于FISCO-BCOS的数据仓库组件,通过解析节点的binlog日志,生成该节点的全量备份,从而使节点能够实现冷热数据分离、快速同步成为可能。除了生成全量备份外,还支持binlog校验、断点续传等功能。

_images/Data-Stash.png

主要特性

  • 节点账本全量备份
  • 多维度binlog校验
  • 备份数据的可信存储
  • 支持断点续传
  • 轻量级接入
  • 数据裁剪和同步

组件介绍

随着区块链业务不断运行,累积的海量链上数据会对区块链节点乃至网络的运维带来许多挑战。

从磁盘容量来看,由于节点的容量有限,持续膨胀的数据要求磁盘需要不断扩容。

从交易性能来看,过多的数据会带来交易执行性能的衰减。

从节点迁移来看,大量的数据同步会引起网络带宽被侵占、同步速度缓慢等问题。

针对以上挑战,微众银行区块链研发并开源了数据仓库组件Data-Stash,通过为节点在外部生成全量数据备份,解决海量数据治理的难题。

首先,节点通过数据裁剪实现冷热数据分离,链上仅保留热数据,冷数据则通过全量备份获取,如此可大量节省节点空间。同时,冷热数据分离后,交易的验证、执行仅依赖于链上热数据,从而提升交易执行性能。最后,对于新节点加入网络后数据的同步,只需要从全量备份拉取数据,实现数据高效迁移,其间不占用区块链网络带宽,免去冗长的同步过程,减少节点数据同步的等待时间,使得节点可以快速加入区块链网络并正常工作。

关键特性

节点账本全量备份

Data-Stash通过解析节点生成的Binlog,可以在节点外生成链上数据的全量备份。随后,节点运维人员可对链上数据进行裁剪,达到节省空间、提升性能的效果。对于裁剪后缺失的冷数据,节点会通过amdb从全量备份读取。节点还可以通过fisco-sync工具,将数据重新导回到节点,恢复完整的节点,而不必从区块链网络拉取数据。

_images/backup.png

多维度账本校验

数据仓库组件在读取某节点日志后,会进行多重校验,以防出现节点账本信息被损害、被篡改、共识系统异常等情况。 校验是多维度的,整体可分为对比校验和区块链校验。对比校验是指Data-Stash会拉取多个节点的账本进行对比,确认账本内容一致后才可以入库;区块链校验是指验证区块链本身,包括哈希检查、签名检查、状态根检查等。

_images/verify.png

备份数据可信存储

Data-Stash每处理完一个区块,都会为此时的全量备份生成一个哈希值作为检查点。该检查点会为存储增信,适用于全量备份库之间的校验等场景。例如,不同机构生成了各自的全量备份,现在想比对各自备份数据是否一致,各机构只需要提取出最新区块高度的检查点进行比对,如一致,则表示备份内容完全相同。

断点续传

在实际运行中,FISCO BCOS会生成许多binlog,这些binlog无论是大小、数量,都具有相当规模,如果每一次运行都重复下载、解析,会造成极大的性能浪费。为此,我们设计了断点续传机制,我们会持续记录解析的进度,每一次运行的时候都会从上一次断点处运行,而不会重新开始。

易于使用

使用者只需要做少量的配置,就可以运行。可以通过jar包直接运行,也可以通过bash脚本启动。

使用场景

冷热数据分离

随着时间推移,节点会积累越来越多的账本数据,如果节点体积不受控制的增长,最终会将节点服务器侵蚀殆尽,造成不良影响。对此,开发者可以使用数据仓库服务来实现冷热数据分离。

  • 确保节点已经开启Binlog,如果节点未开启Binlog并已在运行,可先停止节点,删除群组数据、开启Binlog后再重启节点,节点即可重新同步并生成Binlog。 准备好一个第三方数据库,启动Data-Stash服务,将节点Binlog持续导入到该数据库中,实现全量备份备份。
  • 开发者可对链上数据做一定的划分,可将节点上不常用数据删除,特别是对于存证这样关联性较弱的业务,可仅保留近期数据。
  • 为了让节点运行不受影响,用户需要保证启用amdb(https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/data_governance.html#amdb-proxy),这样缺失的冷数据会自动从数据仓库读取,完成节点瘦身。
实现节点高效迁移

在区块链业务运行时,经常有节点迁移或升级的需求。例如,服务器因为某些故障需要被下线回收,或者需要更换磁盘,此时需要对服务器或磁盘数据进行迁移,重新运行节点需要从区块链网络里同步数据,若待同步数据很大,例如几十G、几百G,就会使得数据恢复时间冗长,而且还会占满区块链的网络带宽,使得整个系统长时间停滞。开发者可通过Data-Stash组件,实现节点迁移。

  • 开发者需要通过Data-Stash生成全量数据备份。
  • 当需要节点迁移时,开发者可以通过FISCO BCOS项目下的fisco sync数据迁移工具(https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/data_governance.html#fisco-sync),将数据仓库导回到节点。这一过程不依赖于任何其他节点,所以迁移不会占用区块链的网络资源。
监管、审计、追溯

对于监管方而言,要求账本数据完整、可查询,但区块链自身的账本数据库不一定满足该需求。例如出于节点瘦身、数据分片等需求,节点上可能仅存储部分账本数据;出于写性能的需要,区块链会选择rocksdb等数据库,但这类数据库在读性能上不具备优势。

此时,监管方可以对某个节点运行数据仓库服务导出完整的全量备份;同时由于我们采用了关系型数据库,易于查询;此外,在全量备份过程中,我们采用的多维度校验机制具有易于验证的优势,可防止节点运维恶意修改账本信息欺骗监管方,更好地满足监管需求。

快速开始

注解

本指引主要介绍如何通过Data-Stash为节点生成全量备份。全量备份是节点冷热分离、快速同步的基础。并提供数据裁剪和同步的使用方式。

数据仓库启动

前置依赖

在使用本组件前,请确认系统环境已安装相关依赖软件,清单如下:

依赖软件 说明 备注
FISCO-BCOS >= 2.7.1 需要为节点开启binlog选项
MySQL >= mysql-community-server[5.7]
Nginx >= nginx[1.17.3]
Java JDK[1.8]
Git 下载安装包需要使用Git

如果您还未安装这些依赖,请参考附录

重要

FISCO-BCOS 2.0与3.0对比、JDK版本、WeBank-Data及其他子系统的 兼容版本说明

基础设置
FISCO BCOS节点配置

由于数据仓库组件用于生成节点的全量备份,所以要求节点拥有包括第一个区块在内的完整binlog日志,故需要确保该节点加入FISCO BCOS网络前就开启binlog生成选项。如果您的节点已经在运行中,请先停止该节点,并删除对应群组(以group1为例)的数据。例如:

[work@instance-zw7wgjv0 node0]$ bash stop.sh
 stop node0 success.
[work@instance-zw7wgjv0 node0]$ rm -rf data/group1

配置文件位于节点的conf/group.1.ini,请设置binary_log=true:

binary_log=true

配置完成后启动节点,使其加入FISCO BCOS网络:

[work@instance-zw7wgjv0 node0]$ bash start.sh
 node0 start successfully

启动成功后,即可在节点的data/group1/BinaryLogs目录下看到binlog,示例:

[work@instance-zw7wgjv0 node0]$ cd data/group1/BinaryLogs/
[work@instance-zw7wgjv0 BinaryLogs]$ ls
0.binlog
Nginx配置

FISCO BCOS节点的binlog日志存放在节点文件目录中,为了让外界能够访问这些binlog,现需要在节点所在服务器安装nginx并配置端口映射,这样外界即可根据该端口访问binlog。

若您还未安装nginx,请参考附录来安装nginx。

nginx配置文件位于/usr/local/nginx/conf/nginx.conf。需要在http模块内新增加一个server模块。在下面的模板中,请将端口号、服务器地址、binlog日志替换为实际的内容:

    server {
        listen       [端口号];
        server_name  [服务器地址];

        charset utf-8;
        location / {
            root   [binlog目录位置];
            index  index.html index.htm;
            autoindex on;
            autoindex_exact_size on;
            autoindex_localtime on;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

下面示例中,将5299端口映射到BinaryLogs目录:

    server {
        listen       5299;
        server_name  myhost.com;

        charset utf-8;
        location / {
            root   /home/work/fisco-bcos/nodes/127.0.0.1/node0/data/group1/BinaryLogs;
            index  index.html index.htm;
            autoindex on;
            autoindex_exact_size on;
            autoindex_localtime on;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

配置完成后,重启nginx使配置生效:

/usr/local/nginx/sbin/nginx -s stop
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx -s reopen 

这些操作完成后,可以通过浏览器访问该端口,出现类似下述响应即表示成功:

_images/nginx_success.png

运行数据仓库组件
下载源码

通过git 下载源码.

git clone https://github.com/WeBankBlockchain/Data-Stash.git

注解

编译源码
cd Data-Stash/tools

tools目录如下:

├── tools
│   ├── config
│   │   ├── application.properties
│   ├── start.sh
│   └── stop.sh
启动配置

在启动之间还需要进行配置,主要包括:

  • binlog获取端口
  • 数据库连接配置

需要在dist/config/application.properties中进行配置,示例如下:

### 配置nginx服务的binlog地址,如果连接多个节点的话,使用逗号分隔
system.binlogAddress=http://www.example.com:5299/,http://www.example.com:5300/

### 数据库连接配置
#### 禁用分库分表
spring.shardingsphere.enabled=false 
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/stash?autoReconnect=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2b8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driverClassName=com.mysql.jdbc.Driver

注解

  • Data-Stash并不会自动创建数据库,所以请预先建好数据库。
  • 若您的链是国密链,请配置system.encryptType=1. DataStash需要验证区块中的签名。
运行程序

可以通过bash启动程序:

chmod +x *sh
bash start.sh

如果日志出现下述字样,则表示运行成功:

2020-10-29 17:42:34.404  INFO 15044 --- [main] com.webank.blockchain.data.stash.DataStashApplication   : Starting DataStashApplication on aaronchu-nb with PID 15044 (E:\gitee\Data-Stash\dist\Data-Stash.jar started by aaronchu in E:\gitee\Data-Stash\dist)
2020-10-29 17:42:34.411  INFO 15044 --- [main] com.webank.blockchain.data.stash.DataStashApplication   : No active profile set, falling back to default profiles: default
2020-10-29 17:42:36.984  INFO 15044 --- [main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-10-29 17:42:36.992  WARN 15044 --- [main] com.zaxxer.hikari.util.DriverDataSource  : Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
2020-10-29 17:42:37.645  INFO 15044 --- [main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-10-29 17:42:41.420  INFO 15044 --- [main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
2020-10-29 17:42:41.473  INFO 15044 --- [main] com.webank.blockchain.data.stash.DataStashApplication   : Started DataStashApplication in 7.489 seconds (JVM running for 8.368)
2020-10-29 17:42:41.901  INFO 15044 --- [main] com.webank.blockchain.data.stash.manager.DownloadManager   : Scan remote item 0, size: 1
2020-10-29 17:42:41.944  INFO 15044 --- [main] com.webank.blockchain.data.stash.manager.DownloadManager   : Download start from last task: 0
........

注意事项

  • 除非重新建了链,否则不要删除binlog的本地目录,也不要修改此目录下的binlog文件,否则会导致程序运行异常。
  • binlog目录下的binlog文件,建议在人工归档备份后再删除,以便于后续的维护和审计等工作。
  • 删除binlog的工作建议在服务停止的时候执行,以避免影响服务的正常运行。
  • 程序在运行失败后会自动退出,运维人员需要详细查看日志报错的原因,并人工介入。对不确定的问题,请联系并咨询开发人员。

数据裁剪查询

使用步骤
配置工程
配置文件设置

修改application.properties文件中数据裁剪相关配置:

data.query.enable=true
data.query.certPath=./config
data.query.groupId=1
data.query.nodeStr=127.0.0.1:20200
data.query.topic=DB
配置证书文件

连接链节点时,需配置证书或证书路径。

将链SDK证书拷贝到配置的证书路径下,如 ./config下,SDK证书目录位于nodes/${ip}/sdk/目录下

# 假设SDK证书位于~/fisco/nodes/127.0.0.1/sdk/目录
cp -r ~/fisco/nodes/127.0.0.1/sdk/* ./config/
运行程序

修改配置后,重新启动项目

bash stop.sh
bash start.sh
节点数据裁剪
节点配置

FISCO BCOS节点在配置scalable存储模式时,对于本地经裁剪后缺少的数据,将通过Data-Stash访问数据源进行获取。

模式启用
  • 设置群组的ini配置文件中[storage].type=scalable来选择链的存储模式为scalable
  • 设置群组的ini配置文件中[storage].binary_log=true来启用binlog。如用户使用build_chain脚本搭链,并选择scalable存储模式,配置文件会自动开启binlog。
文件组织

节点使用scalable存储模式后,其数据目录内容如下:

  • nodeX/data/groupX/block/Scalable/blocksDB/下分文件夹存储区块数据。每个文件夹为独立的DB实例,用DB记录的首个块高来进行文件夹命名。用户在配置了数据仓库实现数据备份归档后,较旧(较低块高)的子文件夹允许删除
  • nodeX/data/groupX/block/Scalable/state存储整体的状态数据,该文件夹不可删除
binlog

binlog文件记录了每个区块的每个交易对区块链状态的修改结果。binlog机制的作用在于:

  1. 提供了区块维度的数据操作结果的记录;
  2. 节点可通过binlog文件而非通过原有的拉取区块重放交易的方式来恢复数据;
  3. binlog文件为“数据仓库”的快照构建提供数据来源。

用户可通过设置群组的ini配置文件中[storage].binary_log=true来启用binlog(binlog默认关)。开启binlog后,nodeX/data/groupX/BinaryLogs/的目录如下。每个binlog文件以其记录的首个区块内容进行命名,且按从小到大的顺序来记录区块。如下图中,文件18.binlog记录的区块为块高18到块高29。

├── 0.binlog
├── 18.binlog
├── 30.binlog
└── 32.binlog
节点启动

停止节点,在对节点数据进行上述裁剪后,启动节点

数据快速同步

请在要同步数据的节点上执行以下步骤,同步前新节点保持在未启动状态,并清空节点data目录。

扩容新节点参考扩容节点

获取启动脚本和配置文件
curl -#LO https://github.com/WeBankBlockchain/Data-Stash/releases/download/V1.2.0/data-sync-bash.tar.gz

注解

解压文件包至当前目录

tar -zxvf data-sync-bash.tar.gz && cd data-sync-bash && chmod -x data_sync.sh

data-sync目录如下:

├── data-sync
│   ├── config.conf
│   └── data_sync.sh

注解

  • config.conf为配置文件,数据仓库数据源配置。
  • data_sync.sh为启动脚本
配置文件

修改config.conf文件:该文件包含了所有的配置信息。以下配置信息是必须要配置的:

[stash]
stash.ip=127.0.0.1
stash.port=3306
stash.dbname=stash
stash.username=root
stash.password=123456

[node]
#要导出的群组ID,会根据配置读取节点目录conf/下指定group.id.ini配置,进行数据同步
node.groupId=1
#节点路径,若选择在fisco对应节点目录下(如~/fisco/nodes/127.0.0.1/node0)执行下述步骤,则无需配置节点路径,默认即可。
node.path=./

[more]
#同步截止区块号,如默认为10000,则同步0-9999号区块至新节点,后续区块将从其他节点同步拉取
sync.endBlockNumber=10000

更多配置参照数据同步配置

启动脚本
bash data_sync.sh

注解

  • 上述脚本会自动拉取对应系统的data-sync包,并自动读取节点群组的配置,同步数据到对应的节点存储源中,节点存储模式包括rocksdb/mysql/scalable三种。
  • rocksdb/mysql模式同步数据包括区块和状态数据。
  • scalable模式下,只同步状态数据,区块数据需要通过数据仓库获取,参考数据裁剪查询

看到如下日志,则表示执行成功:

... ...
[2021-04-29 15:08:24][1/34] processing _sys_tables_
[2021-04-29 15:08:24.287430] [0x00000001056c45c0] [trace]   [STORAGE]conversion end!
[2021-04-29 15:08:24.296431] [0x00000001056c45c0] [debug]   [STORAGE][RocksDB][Commit]Write to db,encodeTimeCost=1,writeDBTimeCost=8,totalTimeCost=9
[2021-04-29 15:08:24][1/34] _sys_tables_ downloaded items : 34 done.
[2021-04-29 15:08:24][2/34] processing _sys_hash_2_block_
[2021-04-29 15:08:24.322570] [0x00000001056c45c0] [trace]   [STORAGE]conversion table data,table name=_sys_hash_2_block_,new entry count=50,dirty entry count=0
[2021-04-29 15:08:24.325145] [0x00000001056c45c0] [trace]   [STORAGE]conversion end!
[2021-04-29 15:08:24.330759] [0x00000001056c45c0] [debug]   [STORAGE][RocksDB][Commit]Write to db,encodeTimeCost=4,writeDBTimeCost=1,totalTimeCost=5
... ...

如节点群组1的配置为RocksDB模式,则同步后的数据可在节点data/group1/block/RocksDB/路径下看到,如下文件:

ls data/
000006.log      000007.sst      CURRENT         IDENTITY        LOCK            LOG             MANIFEST-000008 OPTIONS-000005

详细配置

数据仓库

数据仓库组件的完整配置选项如下:

配置项 说明 是否必需 说明
system.binlogAddress nginx服务的binlog地址,如果连接多个节点的话,使用逗号分隔 必选 示例:system.binlogAddress=http://www.example.com:5299/, http://www.example.com:5300/
spring.datasource.url 数据库连接URL。请确保数据库已预先建立。 示例:jdbc:mysql://127.0.0.1:3306/stash?autoReconnect=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2b8
spring.datasource.username 用户名 示例:root
spring.datasource.password 密码 示例:123456
spring.datasource.driverClassName JDBC驱动 示例:com.mysql.cj.jdbc.Driver
system.encryptType 0-非国密,1-国密。binlog中签名验证时需要使用与链一致的哈希。 默认非国密
system.localBinlogPath binlog的下载位置,支持相对地址和绝对地址 示例:~/binlogs
system.batchCount 数据库批量插入条数 默认为50
system.ledgerThreads 账本表插入线程池大小 默认为10
system.ledgerQueueSize 账本表插入队列大小 默认为10
system.stateThreads 状态表插入线程池大小 默认为10
system.stateQueueSize 状态表插入队列大小 默认10
system.binlogVerify 1-开启binlog校验,0-不开启 默认关闭
read.blocks 每下载多少文件开始执行入库 默认为5
read.clean yes-入库完成后清理文件。no-不清理 默认清理

数据同步

数据同步模块完整配置选项如下:

配置项 说明 是否必需 默认
stash.ip 数据仓库数据库IP地址 必选 127.0.0.1
stash.port 数据仓库数据库端口 必选 3306
stash.dbname 数据仓库数据库名 必选 stash
stash.username 数据仓库数据库用户名 必选 root
stash.password 数据仓库数据库密码 必选 123456
node.groupId 待同步群组id 必选 1
node.path 节点路径 必选 默认当前路径
sync.endBlockNumber 指定同步截止区块号,后续区块从其他节点拉取 非必选 默认:10000
sync.pageCount 指定除表_sys_hash_2_block_和表_sys_block_2_nonces_之外其他表的分页拉取行数,默认为1000行每页; 非必选 1000
sync.bigTablePageCount 指定表_sys_hash_2_block_和表_sys_block_2_nonces_的分页拉取行数,默认为1000行每页 非必选 1000

高级配置

分库分表配置

随着链上数据不断增大,对应的全量数据仓库的存储压力也增大。当数据量大到一定程度的时候,单库的存储、内存等资源已不足以支撑相关业务的需求,因此需要进行分库分表。通常,当单库压力达到1TB,单表数据达10G的时候,推荐进行分库分表。

分库建议

建议优先对账本表进行分库分表,通常账本表占据了系统存储容量的99%以上,可以通过类似下述sql查询各表数据量:

select table_schema, table_name, concat(truncate(data_length/1024/1024,2),' mb') as data_size,
concat(truncate(index_length/1024/1024,2),' mb') as index_size
from information_schema.tables where table_schema ='stash'
order by data_length desc;

通常,根据表的数据量,推荐按照下述策略进行分库分表。

表类型 功能 分片建议 说明
账本表 区块信息 建议分片 主要是_sys_hash_2_block_, _sys_tx_hash_2_block_比较大
账本表detail 区块变更历史 建议分片 主要是_sys_hash_2_block_d_, _sys_tx_hash_2_block_d_比较大
状态表 区块信息 不用分片
状态表detail 区块粒度的状态变更历史 不用分片
进度控制表 控制进度 不用分片,或者广播表

因此,建议对_sys_hash_2_block_, _sys_tx_hash_2_block_及相关detail表做分库,即可满足多数场景。

配置示例

在application.properties中,注释原先spring.datasource相关配置,然后添加下述配置:

### 配置nginx服务的binlog地址,如果连接多个节点的话,使用逗号分隔
system.binlogAddress=http://127.0.0.1:5299/

### 分库分表配置
#### 打开开关
spring.shardingsphere.enabled=true
#### 定义数据源
spring.shardingsphere.datasource.names = stash1,stash2
spring.shardingsphere.datasource.stash1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.stash1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.stash1.jdbcUrl=jdbc:mysql://localhost:3306/stash1?autoReconnect=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2b8
spring.shardingsphere.datasource.stash1.username=root
spring.shardingsphere.datasource.stash1.password=123456

spring.shardingsphere.datasource.stash2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.stash2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.stash2.jdbcUrl=jdbc:mysql://localhost:3306/stash2?autoReconnect=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2b8
spring.shardingsphere.datasource.stash2.username=root
spring.shardingsphere.datasource.stash2.password=123456

#### 不做分片的表,默认存储到stash1
spring.shardingsphere.sharding.default-data-source-name=stash1

#### 需分片的表,路由目标
spring.shardingsphere.sharding.tables._sys_hash_2_block_.actual‐data‐nodes = stash$->{1..3}._sys_hash_2_block_
spring.shardingsphere.sharding.tables._sys_hash_2_block_d_.actual‐data‐nodes = stash$->{1..3}._sys_hash_2_block_d_
spring.shardingsphere.sharding.tables._sys_tx_hash_2_block_.actual‐data‐nodes = stash$->{1..3}._sys_tx_hash_2_block_
spring.shardingsphere.sharding.tables._sys_tx_hash_2_block_d_.actual‐data‐nodes = stash$->{1..3}._sys_tx_hash_2_block_d_

#### 需分片的表,分片策略
spring.shardingsphere.sharding.default-database-strategy.standard.sharding-column= _num_
spring.shardingsphere.sharding.default-database-strategy.standard.precise-algorithm-class-name=com.webank.blockchain.data.stash.db.sharding.BlockShardingAlgorithm
spring.shardingsphere.sharding.default-database-strategy.standard.range-algorithm-class-name=com.webank.blockchain.data.stash.db.sharding.BlockShardingAlgorithm
#spring.shardingsphere.props.sql.show = false



### logback配置
logging.file=./logs/stash.log
logging.level.com.webank=INFO

运行原理

整体架构

_images/architecture.png

整个体系分为如下部分:

节点服务器

节点服务器相关的组件包括:

FISCO BCOS节点

FISCO BCOS节点的变化会被记录到binlog中。binlog目录被放在data/groupX/BinaryLogs目录下,x表示群组号。

Nginx

FISCO BCOS节点本身并不会暴露binlog,如果希望外界读取到binlog,需要借助nginx。通过在nginx中配置端口和binlog目录的映射,外界就可以通过该端口访问到binlog。

数据仓库组件

数据仓库组件自身由如下几个部分构成:

下载服务Fetcher Server

下载服务会持续轮询nginx端口,下载最新binlog日志到本地目录中。

解析服务Binlog Parser

解析服务持续读取未解析binlog日志,将每个区块对应的mysql变动条目都解析出来。

校验服务Binlog verifier

校验服务用于保证数据的可信性。校验服务会从其他节点拉取binlog进行对比,保证内容的一致性。同时,还会对数据本身进行校验,例如对于区块哈希校验、区块签名校验、交易根校验等。

存储服务Data Storage

存储服务按照binlog的变动,会将其内容应用到数据库中,使数据库形成节点状态的一致、全量的冷数据库。

检查点服务Checkpoint Handler

每一个区块数据的入库存储,都会生成一个检查点数据,该检查点包含了前置所有区块数据的哈希,用于额外对存储进行增信。

Binlog结构

一个Binlog记录了各区块对数据的信息。Binlog文件会包含起始区块高度,例如”4.binlog”表示该日志的首个区块为4。 FISCO BCOS采用了Binlog内部记录了每个区块导致哪些系统表被改变。数据的变动按照表(table)-行(entry)-列(fields)的结构组织。 Binlog的结构如下:

_images/binlog.png

存储模型

数据仓库包含节点的全量备份:

表作用 字段 字段说明
_sys_config_ 存储需要共识的群组配置项 name,value,enable_num 配置名称,配置值,该条记录生效块高
_sys_cns_ 存储合约名到地址的映射关系 name,version,address,abi 合约名,合约版本,合约地址,合约ABI
_sys_committee_votes_ 存储投票信息 key,value,origin,block_limit 投票项,投票值,源起,区块限制
_sys_consensus_ 存储共识节点和观察节点的列表 name,type,node_id,enable_num 用于全量查询的标记,节点类型,节点ID,该条记录生效块高
_sys_current_state_ 存储链最新的状态 key,value 状态项(目前有current_number/total_transaction_count),状态值
_sys_table_access_ 存储每个表的具有写权限的外部账户地址 table_name,address,enable_num 表明,账号地址,该条记录生效块高
_sys_tables_ 存储所有表的结构 table_name,key_field,value_field 表名,表主key的列名,表其他列的列名
_sys_tx_hash_2_block_ 存储交易hash到区块号的映射 hash,value,index 交易hash,交易所在的区块号,区块中第几条交易
_sys_number_2_hash_ 存储区块号到区块hash的映射 number,value 区块号,区块hash
_sys_block_2_nonces_ 存储区块中交易的nonces number,value 区块号,该区块中的nonce列表
_sys_hash_2_block_ 存储区块hash到区块数据的映射 key,value 区块hash,区块序列化数据
_sys_hash_2_header_ 存储区块哈希对应的区块头数据 hash,value,sigs 区块hash,区块头序列号数据,签名列表
c_[合约地址] 存储外部账户信息 key,value 记录项(目前有balance/nonce/code/codeHash/alive),记录值
cp_[合约地址] 存储并行合约信息 key,value 记录项(目前有balance/nonce/code/codeHash/alive),记录值

数据检查逻辑

数据仓库组件会对binlog进行校验。校验分为两类:

  • 对比校验
  • 区块链校验
对比校验

数据仓库组件会从多个节点拉取binlog,并对这些binlog进行对比。针对每一个区块,校验内容包括:

  • 区块高度相同
  • 变动的表相同,包括表的数量和表名
  • 每个表中的每一条记录(EntryInfo)都相同,包括检查每条行(ColumnInfo)都相同
区块链校验

数据仓库组件还会检测区块链数据本身,包括:

  • blockHash:根据区块计算hash,看是否一致
  • parentHash:区块能否链接到上一个区块
  • sigList: 验证区块打包者的签名是否正确
  • blockNumber:校验区块高度
  • timestamp:校验区块时间
  • transaction:根据blockLimit,判断是否超时
  • stateRoot校验:transactions的stateRoot是否与header中一致

常见问题

我是否需要建表?

不需要手动建表,如果表不存在,数据仓库组件会自动建表。

当我得到全量数据后,如何使用?

通过Data-Stash得到全量数据后,若想把该数据导入到某节点实现快速同步等功能,需要使用fisco-sync工具,见这里

附录

重要

FISCO-BCOS 2.0与3.0对比、JDK版本、WeBank-Data及其他子系统的 兼容版本说明

Nginx的安装

下载nginx依赖

在安装nginx前首先要确认系统中安装了gcc、pcre-devel、zlib-devel、openssl-devel。如果没有,请执行命令 yum -y install gcc pcre-devel zlib-devel openssl openssl-devel

执行命令时注意权限问题,如遇到,请加上sudo

nginx安装

wget https://nginx.org/download/nginx-1.17.3.tar.gz

tar xvfz nginx-1.17.3.tar.gz

cd  nginx-1.17.3

./configure --prefix=/usr/local/nginx

make
make install

测试是否安装成功 使用命令: /usr/local/nginx/sbin/nginx -t

正常情况的信息输出:

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

MySql的安装

此处以Centos安装MariaDB为例。MariaDB数据库是 MySQL 的一个分支,主要由开源社区在维护,采用 GPL 授权许可。MariaDB完全兼容 MySQL,包括API和命令行。其他安装方式请参考MySQL官网

(1)安装MariaDB

  • 安装命令
sudo yum install -y mariadb*

(2)启停

启动:sudo systemctl start mariadb.service
停止:sudo systemctl stop  mariadb.service

(3)设置开机启动

sudo systemctl enable mariadb.service

(4)初始化root用户

执行以下命令:
sudo mysql_secure_installation
以下根据提示输入:
Enter current password for root (enter for none):<–初次运行直接回车
Set root password? [Y/n] <– 是否设置root用户密码,输入y并回车或直接回车
New password: <– 设置root用户的密码
Re-enter new password: <– 再输入一次你设置的密码
Remove anonymous users? [Y/n] <– 是否删除匿名用户,回车
Disallow root login remotely? [Y/n] <–是否禁止root远程登录,回车
Remove test database and access to it? [Y/n] <– 是否删除test数据库,回车
Reload privilege tables now? [Y/n] <– 是否重新加载权限表,回车
  • 使用root用户登录,密码为初始化设置的密码
mysql -uroot -p -h localhost -P 3306
  • 授权root用户远程访问

    注意,以下语句仅适用于开发环境,不能直接在实际生产中使用!!! 以下操作仅供参考,请勿直接拷贝,请自定义设置复杂密码。

mysql > GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql > flush PRIVILEGES;

安全温馨提示:

  • 例子中给出的数据库密码(123456)仅为样例,强烈建议设置成复杂密码
  • 例子中root用户的远程授权设置会使数据库在所有网络上都可以访问,请按具体的网络拓扑和权限控制情况,设置网络和权限帐号

(5)创建test用户并授权本地访问

mysql > GRANT ALL PRIVILEGES ON *.* TO 'test'@localhost IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql > flush PRIVILEGES;

(6)测试是否成功

  • 登录数据库
mysql -utest -p123456 -h localhost -P 3306
  • 创建数据库
mysql > create database datastash;
mysql > use datastash;

以上语句仅适用于开发环境,不能直接在实际生产中使用!!!以上设置会使数据库在所有网络上都可以访问,请按具体的网络拓扑和权限控制情况,设置网络和权限帐号

Java安装

Ubuntu环境安装Java
# 安装默认Java版本(Java 8或以上)
sudo apt install -y default-jdk
# 查询Java版本
java -version 
CentOS环境安装Java
# 查询centos原有的Java版本
$ rpm -qa|grep java
# 删除查询到的Java版本
$ rpm -e --nodeps java版本
# 查询Java版本,没有出现版本号则删除完毕
$ java -version
# 创建新的文件夹,安装Java 8或以上的版本,将下载的jdk放在software目录
# 从openJDK官网(https://jdk.java.net/java-se-ri/8)或Oracle官网(https://www.oracle.com/technetwork/java/javase/downloads/index.html)选择Java 8或以上的版本下载,例如下载jdk-8u201-linux-x64.tar.gz
$ mkdir /software
# 解压jdk 
$ tar -zxvf jdk-8u201-linux-x64.tar.gz
# 配置Java环境,编辑/etc/profile文件 
$ vim /etc/profile 
# 打开以后将下面三句输入到文件里面并退出
export JAVA_HOME=/software/jdk-8u201-linux-x64.tar.gz
export PATH=$JAVA_HOME/bin:$PATH 
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 生效profile
$ source /etc/profile 
# 查询Java版本,出现的版本是自己下载的版本,则安装成功。
java -version 

Git安装

git:用于拉取最新代码

centos:

sudo yum -y install git

ubuntu:

sudo apt install git

数据导出系统

https://img.shields.io/badge/license-Apache%202-4EB1BA.svgLicense

简介

区块链节点计算能力稀缺和KV存储的数据结构等技术特点决定了区块链上不适合进行复杂的数据查询、数据分析和数据计算等工作,上述工作更适合在链下完成。除了导出区块链的通用基础数据,例如区块高度、区块Hash、区块共识节点等,由于智能合约的不同,每个区块链项目都需要开发能够导出基于自身合约业务数据的应用,存在着大量工程、时间的重复和浪费。因此,我们致力于提供一个通用化、智能化、标准化的数据导出组件。

WeBankBlockchain-Data-Export是一款基于FISCO BCOS平台的数据导出工具,旨在降低区块链数据开发的门槛,提升研发效率。研发人员几乎不需要编写任何代码,只需要进行简单配置,就可以把非结构化的链上数据导出到关系型数据库或ES等数据源中存储,便于后续的业务分析和处理。此外,WeBankBlockchain-Data-Export还支持了多活部署、数据分库分表、导出数据可视化、应用监控等功能,适应各类复杂的业务场景,满足了业务开发中各项需求,提升了使用体验。

WeBankBlockchain-Data-Export的前身是WeBASE-Codegen-Monkey和WeBASE-Collect-Bee,迄今已知在十多家公司数十个生产系统中稳定、安全运行。作为区块链数据治理的关键一环,WeBankBlockchain-Data-Export基于此进行了整合和优化,并作为WeBankBlockchain-Data重要组件正式发布。后续的社区和支持会转移到WeBankBlockchain-Data。欢迎大家一起多多反馈并参与到建设中来。

WeBankBlockchain-Data-Export提供服务和SDK调用两种使用方式,通过jar包依赖可以集成到用户项目中,使用更加灵活便捷。

_images/Data-Export.png

主要特性

  • 支持Channel方式导出数据
  • 使用方式支持通过服务启动和通过SDK调用
  • 自动基于智能合约代码分析和生成导出代码
  • 支持自定义导出数据内容
  • 支持多数据源,如MySQL、ElasticSearch
  • 海量数据导出,支持分库分表
  • 支持多活部署,多节点自动导出
  • 支持区块重置导出
  • 支持可视化的监控页面

组件介绍

组件介绍

WeBankBlockchain-Data-Export 是一个基于FISCO-BCOS Gitee地址平台的数据导出工具。

数据导出组件WeBankBlockchain-Data-Export的目的在于降低获取区块链数据的开发门槛,提升研发效率。研发人员几乎不需要编写任何代码,只需要进行简单配置,就可以把数据导出到Mysql或ES等数据库。

WeBankBlockchain-Data-Export可以导出区块链上的基础数据,如当前块高、交易总量等。如果正确配置了FISCO-BCOS上运行的所有合约,也可以导出区块链上这些合约的业务数据,包括event、构造函数、合约地址、执行函数的信息等。

WeBankBlockchain-Data-Export支持多数据源、分库分表、分布式部署,支持ES存储。

WeBankBlockchain-Data-Export还提供SDK调用方式,通过jar包依赖可以集成到用户项目中,使用更加灵活便捷。

WeBankBlockchain-Data-Export支持多种方式获取区块数据并导出,包括Channel方式、JSON-RPC方式、数据仓库方式。

使用场景和解决方案

区块链的数据存储在区块链上,需要使用智能合约暴露的接口来进行调用。由于智能合约暴露的接口的限制,区块链上不适合进行复杂的数据查询、大数据分析和数据可视化等工作。因此,我们致力于提供一种智能化、自动化的数据导出和备份的解决方案。

案例 数据可视化后台系统
  • 背景

某互联网小贷公司基于FISCO-BCOS开发了区块链借条业务系统,客户之间的借贷合同信息和证明材料都会在脱敏后保存到区块链上。该公司的运营人员需要获得当前业务进展的实时信息和摘要信息。

  • 解决方案

该公司使用了WeBankBlockchain-Data-Export Gitee地址,并根据实际需求进行了定制化开发,在一天之内投入到线上使用。导出到db的数据接入到了该公司的统一监控平台,该公司PM可以在业务后台系统上获得该业务的实时进展,该公司运维人员可以在公司运维监控室的大屏幕实时监控业务系统的状态。

案例 区块链业务数据对账系统
  • 背景

某公司基于FISCO-BCOS开发了区块链的业务系统,需要将本地数据与链上的数据进行对账。

  • 解决方案

该公司使用WeBankBlockchain-Data-Export Gitee地址,并根据实际需求进行了定制化开发。通过在智能合约中设计的各类event,相关的业务数据都被导出到数据库中;从而实现轻松对账的需求。

案例 区块链业务数据查询系统
  • 背景

某互联网公司基于FISCO-BCOS开发了区块链的业务系统,但是发现智能合约对业务报表的支持不佳。但是,公司的一线业务部门要求实时查看各类复杂的业务报表。

  • 解决方案

该公司使用WeBankBlockchain-Data-Export Gitee地址,并根据实际需求进行了定制化开发,区块链上的数据可以实时导出到数据库中。利用WeBankBlockchain-Data-Export Gitee地址 自带的Restful API,该公司的报表系统实现了和区块链数据的对接,可以获得准实时的各类业务报表。

特性介绍

支持多种方式获取链上数据

支持多种方式获取区块数据并导出,包括节点Channel方式、JSON-RPC方式、数据仓库方式。

支持灵活的存储策略

导出数据支持mysql和ES存储,对于mysql存储来说集成sharding-jdbc组件支持多数据源、分库分表、读写分离,同时只需简单配置即可引入ES存储,方便海量数据的存储和查询

支持集群部署和分布式任务调度

集成elstic-job开源组件,支持灵活的分布式部署和任务调度

可定制化的数据导出策略

提供灵活的可配置的区块、交易、事件、账户等数据导出功能,过滤不需要的数据

支持可视化的监控页面

WeBankBlockchain-Data-Export可与grafana深度集成,支持自动生成dashboard实例,让您的链上数据了如指掌。

快速开始

简介

WeBankBlockchain-Data-Export支持docker、服务和SDK三种使用方式。 服务方式根据配置文件方式启动,为独立进程,用户只需进行相关配置即可完成启动,无需代码调用和依赖集成。 SDK方式可通过jar包方式集成到其它项目中,其本身去除了spring等三方依赖,更加轻量化,使用灵活便捷,以应对不同场景的定制化需求,开发者可直接集成到自身项目中使用。

服务方式启动(对应链3.x版本)

前置依赖

在使用本组件前,请确认系统环境已安装相关依赖软件,清单如下:

依赖软件 说明 备注
FISCO-BCOS 3.x版本
Bash 需支持Bash(理论上来说支持所有ksh、zsh等其他unix shell,但未测试)
Java JDK[1.8]
Git 下载的安装包使用Git
MySQL >= mysql-community-server[5.7]
ElasticSearch >= elasticsearch [7.0] 只有在需要ES存储时安装
zookeeper >= zookeeper[3.4] 只有在进行集群部署的时候需要安装

重要

FISCO-BCOS 2.0与3.0对比、JDK版本、WeBank-Data及其他子系统的 兼容版本说明

部署步骤
获取工程
代码拉取
git clone https://github.com/WeBankBlockchain/Data-Export.git
cd Data-Export
git checkout V3

注解

得到工程代码,WeBankBlockchain-Data-Export的工程使用gradle进行构建。

├── ChangeLog.md
├── LICENSE
├── README.md
├── tools
├── WeBankBlockchain-Data-Export-service
├── WeBankBlockchain-Data-Export-sdk
├── build.gradle
├── gradle
├── gradlew
├── gradlew.bat
└── settings.gradle

其中各个子工程的说明如下:

WeBankBlockchain-Data-Export-service 数据导出服务

WeBankBlockchain-Data-Export-sdk 数据导出SDK

tools中包括了服务方式启动所需配置文件和启动脚本。

进入安装路径
cd tools

tools目录如下:

├── tools
│   ├── config
│   │   ├── application.properties
│   ├── start.sh
│   └── stop.sh

注解

  • config为配置文件目录,使用channel方式连接区块链时,可将证书放至该目录。
  • config包括了abi和bin两个文件夹,用于配置合约信息。
  • 运行生成的sql脚本data_export.sql和可视化脚本default_dashboard.json会保存在config目录下。
  • 运行日志保存在./tools/log目录下
配置工程
配置文件设置

修改application.properties文件:该文件包含了所有的配置信息。以下配置信息是必须要配置的:

### 数据导出支持以下方式:
### 1, Channel

# Channel方式启动,与java sdk一致,需配置证书
## GROUP_ID必须与FISCO-BCOS中配置的groupId一致, 多群组以,分隔,如1,2
system.groupId=group0
##IP为节点运行的IP,PORT为节点运行的channel_port,默认为20200
system.nodeStr=127.0.0.1:20200
# ecc-0 sm-1
system.cryptoTypeConfig=0

其中多群组数据导出,参照多群组数据导出

配置证书文件(channel方式启动)

选择channel方式连接链节点时,需配置证书或证书路径。

将链SDK证书拷贝到 ./tools/config下,SDK证书目录位于nodes/${ip}/sdk/目录下

# 假设SDK证书位于~/fisco/nodes/127.0.0.1/sdk/目录
cp -r ~/fisco/nodes/127.0.0.1/sdk/* ./config/

如果是在要连接的链节点上部署数据导出,也可直接配置证书路径,无需上述复制操作,配置证书路径取绝对路径,配置例子如下:

system.certPath=/root/fisco/nodes/127.0.0.1/sdk
配置合约
  • 将要编译的合约拷贝到config/solidity目录下,目录中包含了一个HelloWorld合约示例文件,使用时请按需删除。也可直接配置合约文件所在目录的路径, 默认配置为./config/solidity,可按需修改
  • 按需配置编译器版本号,支持版本(0.4.25.1, 0.5.2.0, 0.6.10.0,0.8.11.0),默认为0.4.25.1。
  • 2.x版本支持0.8.11.0,默认配置为0.8.11.0

配置如下:

system.solPath=./config/solidity
system.solcVersion=0.8.11.0

注解

如果正确配置了合约文件及编译版本号,但出现合约方法和事件数据没有导出的情况,可删除config/solidity/下已配置的未成功导出数据的合约,并将config/solidity/bin/(非国密目录/ecc/、国密目录为/sm/)下bin文件的内容替换为合约部署位置(如WeBase)编译得到的binary,然后清理数据库表重新启动即可。

可视化配置

在application.properties中将grafana打开时,将在config目录下生成可视化脚本,默认关闭,打开配置如下:

system.grafanaEnable=true
创建数据库

参考连接和创建数据库

运行程序

注解

本工程默认使用gradle wrapper来实施构建。在必要时,可在start.sh时添加-c的编译选项,指定使用本机的gradle来进行代码编译。

  • 如果运行程序以后无法正常下载gradle wrapper,可自行安装gradle软件,可参考 官网安装教程
  • 如果本机已经安装了符合要求的gradle软件,则可以使用`./start.sh -c gradle`选项来指定编译方式,使用本机安装的gradle来实施构建。
chmod +x start.sh
bash start.sh

重要

请务必按照以上命令操作,请勿使用sudo命令来操作,否则会导致Gradlew没有权限,导致导出数据失败。

更多运行方式参照运行方式说明

检查运行状态及退出
检查程序进程是否正常运行
ps -ef |grep Data-Export

如果看到如下信息,则代表进程执行正常:

app   21980 24843  0 15:23 pts/3    00:00:44 java -jar Data-Export*.jar
检查程序是否已经正常执行

当你看到程序运行,并在最后出现以下字样时,则代表运行成功:

select blockheigh0_.pk_id as pk_id1_2_, blockheigh0_.block_height as block_he2_2_, blockheigh0_.event_name as event_na3_2_, blockheigh0_.depot_updatetime as depot_up4_2_ from block_height_info blockheigh0_ where blockheigh0_.event_name=?
select blockheigh0_.pk_id as pk_id1_2_, blockheigh0_.block_height as block_he2_2_, blockheigh0_.event_name as event_na3_2_, blockheigh0_.depot_updatetime as depot_up4_2_ from block_height_info blockheigh0_ where blockheigh0_.event_name=?
select blockheigh0_.pk_id as pk_id1_2_, blockheigh0_.block_height as block_he2_2_, blockheigh0_.event_name as event_na3_2_, blockheigh0_.depot_updatetime as depot_up4_2_ from block_height_info blockheigh0_ where blockheigh0_.event_name=?

还可以通过以下命令来查看区块的同步状态:

tail -f data-export.log | grep "sync block"

当看到以下滚动的日志时,则代表区块同步状态正常,开始执行下载任务。

 $ tail -f data-export.log | grep "sync block"
2019-05-05 14:41:07.348  INFO 60538 --- [main] c.w.w.c.service.CommonCrawlerService     : Try to sync block number 0 to 90 of 90
2019-05-05 14:41:07.358  INFO 60538 --- [main] c.w.w.c.service.BlockTaskPoolService     : Begin to prepare sync blocks from 0 to 90
2019-05-05 14:41:17.142  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 0 of 90 sync block succeed.
2019-05-05 14:41:17.391  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 1 of 90 sync block succeed.
2019-05-05 14:41:17.618  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 2 of 90 sync block succeed.
2019-05-05 14:41:18.072  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 3 of 90 sync block succeed.
2019-05-05 14:41:18.395  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 4 of 90 sync block succeed.
2019-05-05 14:41:18.796  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 5 of 90 sync block succeed.
2019-05-05 14:41:19.008  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 6 of 90 sync block succeed.
2019-05-05 14:41:19.439  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 7 of 90 sync block succeed.
2019-05-05 14:41:20.303  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 8 of 90 sync block succeed.
2019-05-05 14:41:20.512  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 9 of 90 sync block succeed.
2019-05-05 14:41:20.738  INFO 60538 --- [main] c.w.w.crawler.service.BlockSyncService   : Block 10 of 90 sync block succeed.
……
检查数据是否已经正常产生

DB数据检查

你也可以通过DB来检查,登录你之前配置的数据库,看到自动创建完表的信息,以及表内开始出现数据内容,则代表一切进展顺利。如你可以执行以下命令:

# 请用你的配置信息替换掉[]里的配置,并记得删除[]
mysql -u[用户名] -p[密码] -e "use [数据库名]; select count(*) from block_detail_info"

如果查询结果非空,出现类似的如下记录,则代表导出数据已经开始运行:

+----------+
| count(*) |
+----------+
|      633 |
+----------+

停止导入程序

bash stop.sh

恭喜您,到以上步骤,您已经完成了数据导出组件的安装和部署。如果您还需要额外获得可视化的监控页面,请参考下述可视化安装和部署。

SDK方式调用(对应链3.x版本)

前置依赖

在使用本组件前,请确认系统环境已安装相关依赖软件,清单如下:

依赖软件 说明 备注
FISCO-BCOS 3.x版本
Java JDK[1.8]
MySQL >= mysql-community-server[5.7]
ElasticSearch >= elasticsearch [7.0] 只有在需要ES存储时安装
zookeeper >= zookeeper[3.4] 只有在进行集群部署的时候需要安装
部署步骤
引入数据导出SDK依赖
建立依赖
dependencies {
    compile 'com.webank:data-export-sdk:2.0.0'
}
SDK调用
单库基础数据导出使用例子如下(默认导出配置):
//数据库配置信息
MysqlDataSource mysqlDataSourc = MysqlDataSource.builder()
        .jdbcUrl("jdbc:mysql://[ip]:[port]/[database]?autoReconnect=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8")
        .user("username")
        .pass("password")
        .build();
//mysql数据库列表
List<MysqlDataSource> mysqlDataSourceList = new ArrayList<>();
//mysql数据库添加
mysqlDataSourceList.add(mysqlDataSourc);
//导出数据源配置
ExportDataSource dataSource = ExportDataSource.builder()
        //设置mysql源
        .mysqlDataSources(mysqlDataSourceList)
        //自动建表开启
        .autoCreateTable(true) 
        .build();
//channel通道的数据导出执行器构建
DataExportExecutor exportExecutor = ExportDataSDK.create(dataSource, ChainInfo.builder()
        //链节点连接信息
        .nodeStr("[ip]:[port]")
        //链连接证书位置
        .certPath("config")
        //群组id
        .groupId("group0")
        .build());
//数据导出执行启动
ExportDataSDK.start(exportExecutor);
//休眠一定时间,因导出执行为线程池执行,测试时主线程需阻塞
Thread.sleep(60 *1000L);
//数据导出执行关闭
//ExportDataSDK.stop(exportExecutor);
分库分表基础数据导出使用例子如下(默认导出配置):
//数据库配置信息
MysqlDataSource mysqlDataSourc = MysqlDataSource.builder()
        .jdbcUrl("jdbc:mysql://[ip]:[port]/[database]?autoReconnect=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8")
        .user("username")
        .pass("password")
        .build();
//数据库配置信息
MysqlDataSource mysqlDataSourc1 = MysqlDataSource.builder()
        .jdbcUrl("jdbc:mysql://[ip]:[port]/[database]?autoReconnect=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8")
        .user("username")
        .pass("password")
        .build();
//mysql数据库列表
List<MysqlDataSource> mysqlDataSourceList = new ArrayList<>();
mysqlDataSourceList.add(mysqlDataSourc);
mysqlDataSourceList.add(mysqlDataSourc1);
//导出数据源配置
ExportDataSource dataSource = ExportDataSource.builder()
        //设置mysql源
        .mysqlDataSources(mysqlDataSourceList)
        //自动建表开启
        .autoCreateTable(true)
        //分库分表开启
        .sharding(true)
        //分片数设置
        .shardingNumberPerDatasource(2)
        .build();
//channel通道的数据导出执行器构建
DataExportExecutor exportExecutor = ExportDataSDK.create(dataSource, ChainInfo.builder()
        //链节点连接信息
        .nodeStr("[ip]:[port]")
        //链连接证书位置
        .certPath("config")
        //群组id
        .groupId("group0")
        .build());
//数据导出执行启动
ExportDataSDK.start(exportExecutor);
//休眠一定时间,因导出执行为线程池执行,测试时主线程需阻塞
Thread.sleep(60 *1000L);
//数据导出执行关闭
//ExportDataSDK.stop(exportExecutor);
SDK-Demo

项目提供使用demo,详情见Data-Export-SDK-Demo

注解

配置手册

简介

本章详细阐述WeBankBlockchain-Data-Export两种调用方式的高阶配置使用

服务配置说明

配置参数说明

组件中配置文件只有一个:./tools/config/resources/application.properties。该配置文件覆盖了数据导出组件所需的所有配置,并提供了详细的说明和样例,开发者可根据需求进行灵活配置。

Springboot服务配置
配置项 是否必须 说明 举例 默认值
server.port N 启动WeBankBlockchain-Data-Export组件实例的服务端口 8082 5200
FISCO-BCOS节点配置

FISCO-BCOS节点配置用于配置服务连接的区块链节点,使得WeBankBlockchain-Data-Export服务能够访问连接节点,并通过该节点获取区块链网络上的数据。 连接区块链节点包括两种方式:channel和JSON-RPC方式

channel方式配置说明如下:
配置项 是否必须 说明 举例 默认值
system.nodeStr Y 连接区块链节点的nodeStr,nodeName@[IP]:[PORT], 其中prot为channel port - -
system.groupId Y 群组id,多群组以,分隔 - 1
system.certPath Y 证书路径 - ./config
JSON-RPC方式配置说明如下:
配置项 是否必须 说明 举例 默认值
system.rpcUrl Y 连接区块链节点的rpc url, http://[IP]:[PORT], 其中prot为rpc port http://localhost:8546 -
system.groupId Y 群组id,多群组以,分隔 1 1
system.cryptoTypeConfig Y 链密钥类型 0-ECDSA,1-gm 0
数据仓库连接配置
配置项 是否必须 说明 举例 默认值
system.jdbcUrl Y 数据仓库jdbc连接配置,格式:jdbc:mysql://[ip]:[port]/[database] http://localhost:3306/stash -
system.user Y 用户名 - -
system.password Y 密码 - -
system.cryptoTypeConfig Y 链密钥类型 0-ECDSA,1-gm 0
数据库配置

数据导出组件最终会把区块链网络上的数据导出到数据存储介质中,支持MySQL,所以需要进行数据库配置。

配置项 是否必须 说明 举例 默认值
system.db0.dbUrl Y 访问数据的URL jdbc:mysql://[IP]:[PORT]/[DB]?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8 -
system.db0.dbUser Y 数据库用户名 admin -
system.db0.dbPassword Y 数据库密码 123456 -
system.namePrefix N 合约导出表字段前缀设置,只针对method、event表中变量字段,字段名长度应小于64个字符 -
system.namePostfix N 合约导出表字段后缀设置,只针对method、event表中变量字段,字段名长度应小于64个字符 -
system.tablePrefix N 数据导出表名前缀设置,表名长度应小于64个字符 -
system.tablePostfix N 数据导出表名后缀设置,表名长度应小于64个字符 -
system.db.autoCreateTable N 自动建表 - true
system.db.sharding N 开启分库分表 - false
system.db.shardingNumberPerDatasource N 分表数目 - 0
system.paramSQLType N 指定数据表字段类型,针对事件或方法字段,多个配置已竖杠字符分隔,contractName.methodName/eventName.paramName.sqlType - HelloWorld.set.name.text

上述配置system.paramSQLType中,指定字段不包括块和交易等基础字段,基础字段参考存储模型

合约配置

数据导出组件最终会把区块链网络上的数据导出到数据存储介质中,支持MySQL,所以需要进行数据库配置。

配置项 是否必须 说明 举例 默认值
system.abiPath Y 合约abi地址 - ./config/abi
system.binPath Y 合约bin地址 - ./config/bin
工程配置
配置项 是否必须 说明 举例 默认值
system.frequency N 所有method和event的抓取频率,默认几秒轮询一次 10 5
system.crawlBatchUnit N 一次任务执行完成的区块数 100 500
system.startBlockHeight N 开始区块高度 - 0
system.startDate N 从大于指定时间开始导出,注意本地utc时间应为当前时区时间 2021-03-04 -

注解

上述 system.startBlockHeightsystem.startDate 同时配置将优先读取前者指定块高,后者会不生效。

集群多活配置

在集群多活部署的方案中,必须设置集群多活的配置。集群必须通过zookeeper进行服务注册和任务分发。

配置项 是否必须 说明 类型 默认值
system.multiLiving Y 启动多活开关 boolean false
regcenter.serverList N 注册中心服务器列表 [ip1:2181;ip2:2181] -
regcenter.namespace N 注册中心命名空间 wecredit_bee -
zookeeperServiceLists N zk服务节点列表(,分隔),格式:[IP]:[port],[IP]:[port] string null
zookeeperNamespace N zk命名空间(,分隔) string null
prepareTaskJobCron N 任务准备job定时配置 ,主要用于读取当前区块链块高,将未抓取过的块高存储到数据库中 string "0/"+ frequency + " * * ?"
dataFlowJobCron N 任务分片执行job定时配置,主要用于执行区块下载任务 string "0/"+ frequency + " * * ?"
dataFlowJobItemParameters N 分片序列号和参数用等号分隔,多个键值对用逗号分隔,分片序列号从0开始,不可大于或等于作业分片总数 string 如 "0=A,1=B,2=C,3=D,4=E,5=F,6=G,7=H"
dataFlowJobShardingTotalCount N 任务分片数目 int 8
可视化配置

开启可视化配置会生成grafana可视化json脚本,可在启动grafana后导入该脚本,即可完成可视化。

配置项 是否必须 说明 举例 默认值
system.grafanaEnable N 是否开启可视化 true false
其他高级配置
配置项 是否必须 说明 举例 默认值
system.generatedOffStr N 指定事件或方法不导出,多个以竖杠字符分隔分隔,[contractName.methodName/eventName,methodName or eventName,...] HelloWorld.set -
system.ignoreParam N 指定事件或方法中字段不导出,多个以竖杠字符分隔分隔,[contractName.methodName/eventName.paramName1,paramName2] HelloWorld.set.n -
system.dataTypeBlackList N 指定数据类型表不导出,多个以,分隔(docker方式启动目前不支持该配置) block_detail_info,block_raw_data, -
system.ignoreBasicDataTableParams N 原始数据表指定字段导出过滤,多表之间以竖杠字符分隔,(docker方式启动目前不支持该配置) tx_raw_data.from,to -

system.dataTypeBlackList配置支持以下数据类型配置:

block_detail_info
block_raw_data
block_tx_detail_info
tx_raw_data
tx_receipt_raw_data
deployed_account_info
contract_info
event
method

配置例子如:system.dataTypeBlackLists=block_detail_info,block_tx_detail_info

上述中system.ignoreBasicDataTableParams配置支持以下基础数据表配置:

block_raw_data表支持以下字段过滤:
db_hash,extra_data,gas_limit,gas_used,logs_bloom,parent_hash,receipts_root,sealer,sealer_list,signature_list,state_root,transaction_list,transactions_root

tx_raw_data表支持以下字段过滤:
from,gas,gas_price,input,nonce,value,to

tx_receipt_raw_data表支持以下字段过滤:
from,gas_used,logs,input,message,output,logs_bloom,root,to,tx_index,tx_proof,receipt_proof

配置例子如:system.ignoreBasicDataTableParams=tx_raw_data.from,to|block_raw_data.db_hash,gas_limit
配置操作说明
多群组数据导出

首先,请配置FISCO BCOS的多群组,详情可参考FISCO BCOS多群组部署

其次,修改application.properties文件。多个群组使用,分隔。例如,假如存在1和2两个群组。

多群组将导出到相同的库中,表名将以群组id做前缀来区分,格式为:g1_tableName

配置如下:

system.groupId=1,2
分库分表配置

数据源配置中,在分库分表时可配置多个,以db0、db1..区分,如system.db0.dbUrl、system.db1.dbUrl…按组递增排列

数据库路由规则为: block_height(区块高度) % 配置数据库数目

表路由规则为: block_height(区块高度) % 表分片数目(shardingNumberPerDatasource)

分库分表所需配置如下:

system.db0.dbUrl=jdbc:mysql://[ip]:[port]/[db]?autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
system.db0.user=
system.db0.password=

system.db1.dbUrl=jdbc:mysql://[ip]:[port]/[db]?autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
system.db1.user=
system.db1.password=

system.db2.dbUrl=jdbc:mysql://[ip]:[port]/[db]?autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
system.db2.user=
system.db2.password=

system.db.sharding=true
system.db.shardingNumberPerDatasource=3
运行方式
选择一:直接在本机运行
chmod +x start.sh
bash start.sh

重要

请务必按照以上命令操作,请勿使用sudo命令来操作,否则会导致Gradlew没有权限,导致导出数据失败。

选择二:本机编译,复制执行包到其他服务器上运行
chmod +x start.sh
bash start.sh

请将此工程下的./WeBankBlockchain-Data-Export-service/dist 文件夹复制到其他服务器上,并执行:

chmod +x *.sh
bash start.sh
tail -f *.log
选择三:本机编译,复制执行包到其他服务器,使用supervisor来启动。

使用supervisor来守护和管理进程,supervisor能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。 它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。 supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程。

使用supervisor来安装与部署的步骤请参阅附录6

ES部署配置

需要ES存储时,需先安装ES,安装ES可通过docker和官网方式安装

docker安装
//创建数据挂载目录
mkdir -p /mydata/elasticsearch/data
chmod -R 777 /mydata/elasticsearch/
//拉取es镜像
docker pull elasticsearch:7.8.0
//启动es容器
docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms128m -Xmx128m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300  -v  /mydata/elasticsearch/data:/usr/share/elasticsearch/data -d  elasticsearch:7.8.0
参考官网安装

可参考官网ES 7.X版本部署

因ElasticSearch相关开源协议变更,相关服务用于商用场景时需自行去ElasticSearch官网下载或采购。该行为与微众区块链无关。

安装完成后,可通过以下命令查看ES安装信息

curl 127.0.0.1:9200/

结果如下:

{
  "name" : "78a052fcba87",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "cJoABrm_RaicXPXQKEYNdw",
  "version" : {
    "number" : "7.8.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
    "build_date" : "2020-06-14T19:35:50.234439Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

配置参考ES配置

启动成功后ES数据检查

可以通过url查询索引建立情况,http://ip:9200/_cat/indices?v,结果类似如下:

health status index                            uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   helloworldsetnamemethod          hvYse4rKTJuSskQPh9ac7Q   1   1          0            0       208b           208b
yellow open   blockrawdata                     ZV6vNxfRSyGDnm_R0aR-tg   1   1         65            7      504kb          504kb
yellow open   blockdetailinfo                  Vbv9dtdCTrK1U5p9okeCfA   1   1         65            7     33.6kb         33.6kb
yellow open   blocktxdetailinfo                1seHyG6CQk6x8AKeqPsLqQ   1   1         35            0     43.3kb         43.3kb
yellow open   blockrawdatabo                   hNl3wUSsQoG2h2AHdgV-NQ   1   1          0            0       208b           208b
yellow open   txreceiptrawdata                 v-bMu_khQ8OI2TyDEhakkA   1   1         35            0    155.3kb        155.3kb
yellow open   contractinfo                     DolSTxR9ToSMLzJ3OJU31w   1   1         27            0    162.4kb        162.4kb
yellow open   deployaccountinfo                ET0VMMahRyqAuSHNLTVEhg   1   1         21            0     15.9kb         15.9kb

更多查询,参考ES数据查询

可视化配置

开启可视化

在application.properties中将grafana打开时,系统将会生成可视化json脚本 default_dashboard.json 文件,位于config目录下。

如果是docker方式启动,将在docker中自动部署grafana,通过[ip]:3000即可完成访问,无需手动安装,配置如下:

system.grafanaEnable=true

当采用服务方式启动时,需手动安装,安装方式如下:

安装软件

首先,请安装docker,docker的安装可参考docker安装手册 等docker安装成功后,请下载grafana:

docker pull grafana/grafana

如果你是使用sudo用户安装了docker,可能会提示『permission denied』的错误,建议执行:

sudo docker pull grafana/grafana
启动grafana
docker run   -d   -p 3000:3000   --name=grafana   -e "GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource"   grafana/grafana

grafana将自动绑定3000端口并自动安装时钟和Json的插件。

可视化展示配置

grafana安装并启动成功,通过访问[ip]:3000(本机则为localhost:3000)即可看到如下界面:

_images/grafana_start.png

输入账密admin/admin, 现在跳过即可进入主界面,添加导出数据库的mysql信息,如下位置:

_images/grafana_index.png

如果是docker安装的mysql,添加mysql的host信息时,需先查询本机对外ip,方法见 常见问题

添加mysql成功后,可通过如下方式导入系统生成的config/default_dashboard.json文件,如下位置:

_images/grafana_json.png

导入成功后即可看到链的数据可视化情况,如下:

_images/grafana_view.png

更多关于Grafana的自定义配置和开发文档,可参考Grafana官方文档

SDK Java API

接口说明
//创建数据导出执行器DataExportExecutor,导出配置采用默认配置,从链上导出数据
DataExportExecutor create(ExportDataSource dataSource, ChainInfo chainInfo);

//创建数据导出执行器DataExportExecutor, 配置导出配置,从链上导出数据
DataExportExecutor create(ExportDataSource dataSource, ChainInfo chainInfo, ExportConfig config)

//创建Stash数据导出执行器DataExportExecutor,导出配置采用默认配置,从数据仓库中导出数据
DataExportExecutor create(ExportDataSource dataSource, StashInfo stashInfo);

//创建Stash数据导出执行器DataExportExecutor, 配置导出配置,从数据仓库中导出数据
DataExportExecutor create(ExportDataSource dataSource, StashInfo stashInfo, ExportConfig config)

//DataExportExecutor启动
start(DataExportExecutor exportExecutor)

//DataExportExecutor关闭
stop(DataExportExecutor exportExecutor)
参数说明

参数ExportDataSource为数据源配置,参数如下:

参数 说明 类型 默认值
autoCreateTable 是否自动建表 boolean false
sharding 是否多数据源,采用分库分表 boolean false
shardingNumberPerDatasource 单库表分片数,用于路由和建表 int 0
mysqlDataSources mysql数据源配置,支持多数据源 List null
esDataSource es数据源配置 ESDataSource null


数据源参数支持了mysql和es,包括MysqlDataSource, ESDataSource,参数如下:

MysqlDataSource(必须),参数如下:

参数 说明 类型 默认值
jdbcUrl jdbc连接配置,格式:jdbc:mysql://[ip]:[port]/[database] string null
user 用户名 string null
pass 密码 string null


ESDataSource(非必须),参数如下:

参数 说明 类型 默认值
enable es存储开关 boolean false
clusterName 集群名称 string null
ip IP地址 string null
port 端口号 int null


ChainInfo为链参数配置,支持RPC通道和Channel通道两种配置方式,参数如下:

参数 说明 类型 默认值
groupId 分组id (必配) string null
nodeStr 链节点ip和端口port,格式:[ip]:[port] (channel通道连接时设置) string null
certPath 链节点连接所需证书路径 (channel通道连接时设置) string null
rpcUrl rpc连接url,格式:http://[ip]:[port],如:http://127.0.0.1:8546;(使用rpc连接时设置) string null
cryptoTypeConfig 链密钥类型,0-ECDSA,1-SM(国密),(使用rpc连接时设置) int 0

注解

  • 链上证书默认位于链节点 ~/fisco/nodes/127.0.0.1/sdk目录中,如果为国密链直接将sdk下gm文件夹拷贝到certPath配置的目录中。
  • channel通道和rpc通道同时设置时,将使用rpc方式连接。


StashInfo为数据仓库源mysql配置,与ChainInfo同时设置后,优先该方式,参数如下:

参数 说明 类型 默认值
jdbcUrl 数据仓库jdbc连接配置,格式:jdbc:mysql://[ip]:[port]/[database] string null
user 用户名 string null
pass 密码 string null
cryptoTypeConfig 链密钥类型,0-ECDSA,1-SM(国密) int 0


ExportConfig为数据导出任务配置(非必须),参数如下:

参数 说明 类型 默认值
crawlBatchUnit 链上导出任务每批次数目 int 1000
frequency 任务间隔时间 int 5s
startBlockHeight 开始区块高度 int 0
startDate 开始时间 Date null
ContractInfoList 合约信息,包括合约名称,abi,binary信息(基础数据无需填充) List null
dataTypeBlackList 导出数据表黑名单,默认全部导出,可根据DataType枚举设置 List null
multiLiving 是否开启多活job boolean false
zookeeperServiceLists zk服务节点列表(,分隔),格式:[IP]:[port],[IP]:[port] string null
zookeeperNamespace zk命名空间(,分隔) string null
prepareTaskJobCron 任务准备job定时配置 string "0/"+ frequency + " * * ?"
dataFlowJobCron 任务分片执行job定时配置 string "0/"+ frequency + " * * ?"
dataFlowJobItemParameters 任务分片执行job参数 string 如 "0=A,1=B,2=C,3=D,4=E,5=F,6=G,7=H"
dataFlowJobShardingTotalCount 任务分片数目 int 8
generatedOff 合约事件或函数导出过滤,如: Map<合约名, 方法名/事件名> Map empty map
ignoreParam 合约函数指定字段导出过滤,如: Map<合约名, Map<方法名/事件名, List<字段名>>> Map empty map
paramSQLType 合约函数指定字段导出sql类型,如: Map<合约名, Map<方法名/事件名, Map<字段名,sql类型>>> Map empty map
tablePrefix 数据导出表名前缀设置 String
tablePostfix 数据导出表名前缀设置 String
namePrefix 合约导出表字段前缀设置,只针对method、event表中变量字段 String
namePostfix 合约导出表字段后缀设置,只针对method、event表中变量字段 String
ignoreBasicDataTableParam 原始数据表指定字段导出过滤,如: Map<表名, List<字段名>> Map empty map
topicRegistry 自定义处理逻辑,支持区块、交易、交易回执、函数、事件 SubscriberInterface empty

ignoreBasicDataTableParam 参考例子如下,支持过滤表和字段参考 IgnoreBasicDataParam 枚举类:

    ExportConfig config = new ExportConfig();
    List<String> params = new ArrayList<>();
    params.add(IgnoreBasicDataParam.BlockRawDataParams.EXTRA_DATA.name());
    params.add(IgnoreBasicDataParam.BlockRawDataParams.LOGS_BLOOM.name());
    params.add(IgnoreBasicDataParam.BlockRawDataParams.RECEIPTS_ROOT.name());
    params.add(IgnoreBasicDataParam.BlockRawDataParams.TRANSACTION_LIST.name());
    params.add(IgnoreBasicDataParam.BlockRawDataParams.GAS_USED.name());
    //添加block_raw_data表字段过滤配置
    config.getIgnoreBasicDataTableParam()
          .put(IgnoreBasicDataParam.IgnoreBasicDataTable.BLOCK_RAW_DATA_TABLE.name(), params);

自定义事件处理逻辑示例

    ExportConfig config = new ExportConfig();
    //添加区块自定义处理逻辑
    exportConfig.getTopicRegistry().getBlockTopic().addSubscriber(new SubscriberInterface<BlockInfoBO>() {
        @Override
        public boolean shouldProcess(BlockInfoBO blockInfoBO, Object context) {
            return blockInfoBO.getBlockDetailInfo().getBlockHeight() >= 10;
        }

        @Override
        public void process(BlockInfoBO blockInfoBO) {
            System.out.println(blockInfoBO.getBlockDetailInfo().getBlockHash());
        }
    });
功能说明
  • 本版本为SDK版本,去Spring等框架依赖,更好地支持第三方以jar形式引入
  • 支持分库分表和分布式调度
  • 增加导出启停的API接口
  • 支持导出数据类型可选功能
  • 支持多链多群组调用
  • 支持数据库和ES存储
  • 暂不支持指定合约分表数目配置功能,如需使用可使用服务方式配置启动

存储模型

数据导出中间件会自动将数据导出到存储介质中,每一类数据都有特定的存储格式和模型,包括四类数据:区块数据、账户数据、事件数据和交易数据,Mysql和ES存储采用类似的存储模型

区块数据存储模型

区块原始数据模型包括三个数据存储模型,分别为区块原始数据模型、交易原始数据模型、交易回执数据模型

区块原始数据表 block_raw_data

区块原始数据表⽤于存储每个区块的详细信息。⼀般通过RPC接⼝调⽤getBlockByNumber或 getBlockByHash接⼝来获得相应的区块数据。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_height bigint(20) 块高
block_hash varchar(255) 块哈希
block_timestamp datetime(6) 时间
dbHash varchar(255) DB哈希
extraData longtext 附加数据
gasLimit varchar(255) 区块中允许的gas最大值
gasUsed varchar(255) 区块所有交易消耗的gas
logsBloom longtext log的布隆过滤器值
parentHash varchar(255) 父区块哈希
receiptsRoot varchar(255) 回执根哈希
sealer varchar(255) 共识节点序号
sealerList longtext 共识节点列表
signatureList longtext 签名列表
stateRoot varchar(255) 状态根哈希
transactionsRoot varchar(255) 交易根哈希
transactionList longtext 交易列表
depot_updatetime datetime 系统时间 记录插入/更新时间

对应ES索引名为 blockrawdata

交易原始数据表 tx_raw_data

区块原始数据表⽤于存储每个区块的详细信息。⼀般通过RPC接⼝调⽤getBlockByNumber或 getBlockByHash接⼝来获得相应的区块数据。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_height bigint(20) 块高
block_hash varchar(255) 块哈希
block_timestamp datetime(6) 时间
from varchar(255) 发送者地址
gasPrice longtext 发送者提供的gas价格
gas varchar(255) 发送者提供的gas
input longtext 交易的输入
nonce varchar(255) 交易的nonce值
to varchar(255) 接收者地址
tx_hash varchar(255) 交易哈希
tx_index varchar(255) 交易序号
value longtext 转移的值
depot_updatetime datetime 系统时间 记录插入/更新时间

对应ES索引名为 txrawdata

交易回执原始数据表 tx_receipt_raw_data

交易原始数据表⽤于存储每笔交易的回执数据。⼀般通过RPC接⼝调⽤getTransactionReceipt等接⼝来 获得相应的交易数据。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_height bigint(20) 块高
block_hash varchar(255) 块哈希
block_timestamp datetime(6) 时间
contractAddress varchar(255) 发送者地址
gasUsed longtext 交易消耗的gas
logsBloom longtext log的布隆过滤器值
logs longtext 交易产生的日志
message varchar(255) 交易哈希
output longtext 交易的输出
receiptProof longtext 回执证明
root varchar(255) 状态根
txProof longtext 交易根哈希
status varchar(255) 交易的状态值
input longtext 交易的输入
to varchar(255) 接收者地址
tx_hash varchar(255) 交易哈希
tx_index varchar(255) 交易序号
depot_updatetime datetime 系统时间 记录插入/更新时间

对应ES索引名为 txreceiptrawdata

解析后的区块数据存储模型

区块数据存储模型包括三个数据存储模型,分别为区块基本数据存储模型、区块详细数据存储模型及区块交易数据存储模型。

区块详细数据存储模型 block_detail_info

区块详细数据存储模型用于存储每个区块的详细数据,包括区块哈希、块高、出块时间、块上交易量,对应的数据库表名为block_detail_info,如下表所示。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_hash varchar(255) Unique key & Index 区块哈希
block_height bigint(20) 区块高度
block_tiemstamp datetime index 出块时间
tx_count int(11) 当前区块交易量
depot_updatetime datetime 系统时间 记录插入/更新时间
status int(11) 区块状态 0-初始化 1-成功 2-失败

对应ES索引名为 blockdetailinfo

区块交易数据存储模型 block_tx_detail_info

区块交易数据存储模型用于存储每个区块中每个交易的基本信息,包括区块哈希、块高、出块时间、合约名称、方法名称、交易哈希、交易发起方地址、交易接收方地址,对应的数据库表名为block_tx_detail_info。如下表所示。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_hash varchar(255) Unique key & Index 区块哈希
block_height bigint(20) 区块高度
block_tiemstamp datetime index 出块时间
contract_name varchar(255) 该笔交易的合约名称
method_name varchar(255) 该笔交易调用的function名称
tx_hash varchar(255) 交易哈希
tx_from varchar(255) 交易发起方地址
tx_to varchar(255) 交易接收方地址
depot_updatetime datetime 系统时间 记录插入/更新时间

对应ES索引名为 blocktxdetailinfo

合约信息存储模型

合约信息表 contract_info

合约信息表包含了⽤户的合约相关的信息。 包括合约编译后abi,bin信息,合约的版本号,合约名等信 息。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
abi_hash varchar(255) Unique key & Index abi哈希值
contract_abi longtext 合约ABI
contract_binary longtext 合约Bin信息
contract_name varchar(255) 合约名称
version varchar(255) 版本号
depot_updatetime datetime 系统时间 记录插入/更新时间

对应ES索引名为 contractinfo

已部署合约详情信息表 deployed_account_info

已部署账户数据存储模型⽤于存储区块链⽹络中所有账户信息,包括账户创建时所在块⾼、账户所在块的 出块时间、账户地址(合约地址)、合约名称。对应的数据库表名为deployed_account_info。如下表所 示。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
abi_hash varchar(255) abi哈希值
contract_address longtext 合约地址
block_height longtext 块高
contract_name varchar(255) 合约名称
block_timestamp datetime 出块时间
depot_updatetime datetime 系统时间 记录插入/更新时间

对应ES索引名为 deployaccountinfo

事件数据存储模型

事件数据存储模型是根据合约中的事件(Event)自动生成的。一个合约中有多少个事件就会生成多少个对应的事件数据存储表。

事件数据存储命名规则

由于事件数据存储模型是自动生成的,所以事件数据存储表名和表结构及字段命名采用统一的规则。以如下合约作为示例。

pragma solidity ^0.4.7;
contract UserInfo {
    bytes32 _userName;
    uint8 _sex;
    
    function UserInfo(bytes32 userName, uint8 sex) public {
        _userName = userName;
        _sex = sex;
    }
    
    event modifyUserNameEvent(bytes32 userName,uint8 sex);
    
    function modifyUserName(bytes32 userName) public returns(bytes32){
        _userName = userName;
        modifyUserNameEvent(_userName,_sex);
        return _userName;
    }
}
事件表命名规则

mysql事件表命名规则为:合约名称_事件名称,并将合约名称和事件名称中的驼峰命名转化为小写加下划线方式。比如上述合约中合约名称为UserInfo,事件名称为modifyUserNameEvent,则表名称为user_info_modify_user_name_event。

ES事件索引命名规则:合约名称+事件名称+event

事件字段命名规则

事件字段命名规则:事件字段驼峰命名转化为小写加下划线方式。仍以上述合约中modifyUserNameEvent为例,包含字段userName,则在user_info_modify_user_name_event表中对应的字段为user_name。

事件数据存储模型

事件数据存储模型除过存储该事件的相关信息外,还会存储和该事件相关的块和交易信息,如下表所示。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_height bigint(20) index 区块高度
block_tiemstamp datetime index 出块时间
event-paralist 事件字段列表
tx_hash varchar(255) index 交易哈希
depot_updatetime datetime 系统时间 记录插入/更新时间

以上述智能合约为例,对应的 如下:

字段 类型 字段设置 默认值 说明
user_name varchar(255) 用户名
sex int 性别

交易数据存储模型

交易数据存储模型同事件数据存储模型类似,是根据合约中的方法(Function)自动生成的。一个合约中有多少个方法就会生成多少个对应的方法数据存储表。该方法指的是实际产生交易的方法(含构造方法),不包含事件(Event)方法和查询方法(constant关键字标注)。

交易数据存储命名规则

交易数据存储表名、表结构及字段命名规则同事件数据存储模型类似。

交易表命名规则

mysql交易表命名规则为:合约名称_方法名称,并将合约名称和方法名称中的驼峰命名转化为小写加下划线方式。比如上述合约中合约名称为UserInfo,方法名称为modifyUserName,则表名称为user_info_modify_user_name_method;构造方法名称为UserInfo,那么对应的表名为user_info_user_info_method。 ES事件索引命名规则:合约名称+方法名称+method

交易字段命名规则

交易字段命名规则也是将交易参数字段驼峰命名转化为小写加下划线,不再赘述。需要指出的是,对于一些没有参数的方法,交易数据存储模型没有办法存储,即通过无参方法产生的交易明细将无法通过数据导出工具获取到。

交易数据存储模型

交易数据存储模型除过存储该方法的相关信息外,还会存储和该方法相关的块和交易信息,如下表所示。

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_height bigint(20) index 区块高度
block_tiemstamp datetime index 出块时间
tx_hash varchar(255) 合约地址
function-paralist 方法字段列表
tx_hash varchar(255) index 交易哈希
depot_updatetime datetime 系统时间 记录插入/更新时间

3.1中的合约为例,对应的 如下:

字段 类型 字段设置 默认值 说明
user_name varchar(255) 用户名
sex int 性别

导出任务控制

区块下载任务明细表 block_task_pool

存储了所有区块的状态信息和下载情况,对应数据库表名称为block_task_pool,如下所示:

字段 类型 字段设置 默认值 说明
pk_id bigint(20) Primary key & NOT NULL 自增 主键Id
block_height bigint(20) 块高
certainty int(11) 是否可能分叉 0- 是; 1-否
handle_item int(11) 处理分片序号,默认为0
sync_status int 2 0-待处理;1-处理中;2-已成功;3-处理失败;4-超时
depot_updatetime datetime 系统时间 记录插入/更新时间

常见问题

为啥我的数据里自动生成的表里,只有block_detail_info、block_raw_data、block_task_pool、contract_info表有数据?

  1. 区块链刚完成初始化,块高为0;
  2. 数据导出合约Java文件的binary与上链文件的binary不一致,导致数据导出程序无法识别上链的合约数据。解决办法是,找到上链的代码,保证和数据导出里的bianry一致。例如,如果是通过java sdk来发送上链的,则将sdk中的合约java文件复制到数据导出工程中;如果是通过WeBASE-Front来发送的,则从WeBASE-Front中导出Java文件,并复制到数据导出工程中。然后,重新使用脚本重启即可。

我已成功启动和部署服务,也看到Mysql里生成了各个函数的表,但是只有event表里有数据,函数表里没有?

A:同上一个问题。数据导出合约binary与上链文件的binary不一致,导致数据导出程序无法识别上链的合约数据。解决办法是,找到上链的代码,保证和数据导出里的bianry一致。例如,如果是通过java sdk来发送上链的,则将sdk中的合约java文件复制到数据导出工程中;如果是通过WeBASE-Front来发送的,则从WeBASE-Front中获取对应binary信息,并复制到数据导出工程中。然后,重新使用脚本重启即可。

数据导出按文档配置好后,本机运行报错,报错信息如下图,请问怎么办?

_images/web3sdk_error.png报错信息

A:如果报错信息中含有web3sdk字样,这是因为使用了web3sdk编译Java代码。请更新控制台,使用2.6+控制台进行代码编译

数据导出的时候报错,”Could not find xxx.jar”,无法正常运行,错误信息参考如下:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':WeBankBlockchain-Data-Export-common:compileJava'.
> Could not resolve all files for configuration ':WeBankBlockchain-Data-Export-common:compileClasspath'.
   > Could not find java-sdk-2.6.1.jar (org.fisco-bcos.java-sdk:java-sdk:2.6.1).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/org/fisco-bcos/java-sdk/java-sdk/2.6.1/java-sdk-2.6.1.jar

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org
A:下载jar包失败。请首先检查报错的链接能否正常打开下载。如果正常,在项目根目录下执行下 bash gradlew clean bootJar --refresh-dependencies 强制重新刷新依赖。

数据导出的时候报错,”Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. “,无法创建表,错误信息参考如下:

2021-12-21 12:00:19.779 [pool-2-thread-1] ERROR c.w.b.d.export.tools.DataSourceUtils - export data table create failed, reason is : 
java.sql.SQLSyntaxErrorException: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeLarge
A:这通常是因为创建表的时候,单行的容量超过了mysql限制,例如在一个函数具有很大string类型参数,而数据导出中string类型默认对应varchar(2048),因此一行数据总体上便超出了mysql对单行容量的限制。 解决方法是在配置文件中指定每个字段对应的类型,可参考数据库配置中的system.paramSQLType配置项。例如下面示例中,HelloWorld有set和set2两个函数,它们的参数都是string,希望均按text类型存入mysql:
system.paramSQLType=HelloWorld.set.n.text|HelloWorld.set2.n.text

假如我的合约升级了怎么办,能否导出历史和更新后的合约数据?

A:可以。但是会被作为两个数据库表来进行存储,因为合约的数据结构等可能会改变。 操作方法:你也猜到了,我们建议建立版本号,将升级的合约与旧版本的合约Java文件,使用不同的命名,保存到配置文件下面。

是否支持合约函数和事件的重载?

A:暂不支持,建议修改命名。

是否支持多群组的数据导出?

A:支持 操作方法: 多群组数据导出

脚本没权限,执行shell脚本报错误”permission denied”或格式错误?

## 赋权限
chmod + *.sh
## 转格式
dos2unix *.sh

docker与数据库或链在一台机器上,docker无法访问宿主机

如果链或者数据库为本地安装,需查询本机ip,替换上述配置中的localhost 或者 127.0.0.1 地址。

启动脚本中已对本地ip进行了查询并替换,如果失败,可以按照下列命令查询并手动替换。

查询ip命令为:

   ifconfig | grep "inet " | grep -v 127.0.0.1

其中inet后的ip地址,即为本机ip

docker默认采用docker0桥接模式,需开启对应宿主机端口访问权限。

centos启动脚本报yum更新失败

错误如:

yum更新失败:rpmdb: BDB0113 Thread/process 2673/140126198814528 failed: BDB1507 Thread died...

解决方式如下:

cd /var/lib/rpm
rm -rf __db*
rpm --rebuilddb

附录

Java安装

Ubuntu环境安装Java
# 安装默认Java版本(Java 8或以上)
sudo apt install -y default-jdk
# 查询Java版本
java -version 
CentOS环境安装Java
# 查询centos原有的Java版本
$ rpm -qa|grep java
# 删除查询到的Java版本
$ rpm -e --nodeps java版本
# 查询Java版本,没有出现版本号则删除完毕
$ java -version
# 创建新的文件夹,安装Java 8或以上的版本,将下载的jdk放在software目录
# 从openJDK官网(https://jdk.java.net/java-se-ri/8)或Oracle官网(https://www.oracle.com/technetwork/java/javase/downloads/index.html)选择Java 8或以上的版本下载,例如下载jdk-8u201-linux-x64.tar.gz
$ mkdir /software
# 解压jdk 
$ tar -zxvf jdk-8u201-linux-x64.tar.gz
# 配置Java环境,编辑/etc/profile文件 
$ vim /etc/profile 
# 打开以后将下面三句输入到文件里面并退出
export JAVA_HOME=/software/jdk-8u201-linux-x64.tar.gz
export PATH=$JAVA_HOME/bin:$PATH 
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 生效profile
$ source /etc/profile 
# 查询Java版本,出现的版本是自己下载的版本,则安装成功。
java -version 

Git安装

git:用于拉取最新代码

centos:

sudo yum -y install git

ubuntu:

sudo apt install git

Mysql安装

此处以Centos安装MariaDB为例。MariaDB数据库是 MySQL 的一个分支,主要由开源社区在维护,采用 GPL 授权许可。MariaDB完全兼容 MySQL,包括API和命令行。其他安装方式请参考MySQL官网

(1)安装MariaDB

  • 安装命令
sudo yum install -y mariadb*

(2)启停

启动:sudo systemctl start mariadb.service
停止:sudo systemctl stop  mariadb.service

(3)设置开机启动

sudo systemctl enable mariadb.service

(4)初始化root用户

执行以下命令:
sudo mysql_secure_installation
以下根据提示输入:
Enter current password for root (enter for none):<–初次运行直接回车
Set root password? [Y/n] <– 是否设置root用户密码,输入y并回车或直接回车
New password: <– 设置root用户的密码
Re-enter new password: <– 再输入一次你设置的密码
Remove anonymous users? [Y/n] <– 是否删除匿名用户,回车
Disallow root login remotely? [Y/n] <–是否禁止root远程登录,回车
Remove test database and access to it? [Y/n] <– 是否删除test数据库,回车
Reload privilege tables now? [Y/n] <– 是否重新加载权限表,回车
  • 使用root用户登录,密码为初始化设置的密码
mysql -uroot -p -h localhost -P 3306
  • 授权root用户远程访问

    注意,以下语句仅适用于开发环境,不能直接在实际生产中使用!!! 以下操作仅供参考,请勿直接拷贝,请自定义设置复杂密码。

mysql > GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql > flush PRIVILEGES;

安全温馨提示:

  • 例子中给出的数据库密码(123456)仅为样例,强烈建议设置成复杂密码
  • 例子中root用户的远程授权设置会使数据库在所有网络上都可以访问,请按具体的网络拓扑和权限控制情况,设置网络和权限帐号

(5)创建test用户并授权本地访问

mysql > GRANT ALL PRIVILEGES ON *.* TO 'test'@localhost IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql > flush PRIVILEGES;

(6)测试是否成功

  • 登录数据库
mysql -utest -p123456 -h localhost -P 3306
  • 创建数据库
mysql > create database databee;
mysql > use databee;

以上语句仅适用于开发环境,不能直接在实际生产中使用!!!以上设置会使数据库在所有网络上都可以访问,请按具体的网络拓扑和权限控制情况,设置网络和权限帐号

Elasticsearch 安装

ES部署

zookeeper 安装

zookeeper 支持单机和集群部署,推荐使用集群部署的方式,请参考zookeeper官网的说明:

集群部署

单机部署

supervisor安装与部署

安装脚本
sudo yum -y install supervisor

会生成默认配置/etc/supervisord.conf和目录/etc/supervisord.d,如果没有则自行创建。

配置脚本

cd /etc/supervisord.d 修改/etc/supervisord.conf的[include]部分:

[include]
files = supervisord.d/*.ini
[supervisord]

在/etc/supervisord.d目录下配置以下启动配置文件databee_config1.ini(请注意配置文件里需要包含databee,否则会导致关闭任务命令失效),注意修改相关的路径。

[program:supervisor_databee]
directory =【你的程序路径】/WeBankBlockchain-Data-Export-core/dist ; 程序的启动目录
command = nohup java -jar 【你的安装包名,如WeBankBlockchain-Data-Export-core0.3.0-SNAPSHOT.jar】 & ; 启动命令,与命令行启动的命令是一样的
autostart = true     ;  supervisord 启动的时候也自动启动
startsecs = 15        ; 启动 15 秒后没有异常退出,就当作已经正常启动了
autorestart = true   ; 程序异常退出后自动重启
startretries = 3     ; 启动失败自动重试次数,默认是 3
user = app          ; 用哪个用户启动
redirect_stderr = true  ;  stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 150MB  ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20     ; stdout 日志文件备份数
stderr_logfile=【你的日志路径】/WeBankBlockchain-Data-Export-core/dist/log/data_bee_error.log
stdout_logfile = 【你的日志路径】/WeBankBlockchain-Data-Export-core/dist/log/data_bee_out.log  ;日志统一放在log目录下
[supervisord]
启动任务

supervisor支持supervisorctl和supervisord启动,可通过systemctl实现开机自启动。 我们建议采用supervisord的方式启动:

supervisord -c /etc/supervisord.d/databee_config1.ini
关闭任务
ps -ef|grep supervisord|grep databee| awk '{print $2}'|xargs kill -9
ps -ef|grep WeBankBlockchain-Data-Export|grep -v grep| awk '{print $2}'|xargs kill -9

数据对账组件

https://img.shields.io/badge/license-Apache%202-4EB1BA.svgLicense

简介

传统企业间的对账,依赖于对账双方的中心化账本。中心化账本在对账期间如果出现账不平的情况,排查非常耗时耗力。区块链作为信任的机器,具有不可篡改、分布式账本等特性,基于区块链的对账能够在对账不一致的情况下,找到一个可信的客观依据,从而减少因对账不平造成的排查成本。

WeBankBlockchain-Data-Reconcile是一款基于区块链的对账组件,提供基于区块链智能合约账本的通用化数据对账解决方案,并提供了一套可动态扩展的对账框架,支持定制化开发。

_images/Data-Reconcile.png

主要特性

  • 支持自定义对账数据结构
  • 支持自定义对账规则
  • 支持多种对账文件格式
  • 支持自定义对账任务和方式
  • 支持多种对账文件托管方式
  • 可定制化开发的对账处理流程

组件介绍

组件介绍

传统企业间的对账,依赖于对账双方的中心化账本。中心化账本在对账期间如果出现账不平的情况,排查非常耗时耗力。区块链作为信任的机器,具有不可篡改、分布式账本等特性,基于区块链的对账能够在对账不一致的情况下,找到一个可信的客观依据,从而减少因对账不平造成的排查成本。 WeBankBlockchain-Data-Reconcile是一款基于区块链的对账组件,提供基于区块链智能合约账本的通用化数据对账解决方案,并提供了一套可动态扩展的对账框架,支持定制化开发。

使用场景

企业间对账

企业A和企业B之间作为合作者,存在转账交易等数据交互行为,两者通过FISCO-BCOS搭建了区块链,并将各自的交易数据上传到链上,在结算时,A企业定期将自身业务系统交易数据导出为对账文件,发送至与文件资源托管中心,B企业并通过数据导出组件WeBankBlockchain-Data-Export导出链上数据至数据库中,并借助WeBankBlockchain-Data-Reconcile对账组件定期拉取A企业对账文件,与导出的链上数据进行对账处理,同时通过扩展接口对组件进行定制化开发,以满足不同对账需求。企业之间通过使用WeBankBlockchain-Data-Reconcile在保证对账结果可信的同时提升了对账的效率。

_images/out_reconcile.png

企业内部对账

企业内部通过FISCO-BCOS搭建了区块链,业务数据不仅保存在业务系统内部,同时也上传到链上,保证数据的不可篡改,由于业务系统可能存在人为篡改或数据故障等情况出现,需定期对业务系统数据进行核算检查,借助WeBankBlockchain-Data-Reconcile将业务系统数据和链上数据进行核算比对,保证企业内部业务系统数据的可靠和运行安全。

_images/in_reconcile.png

特性介绍

WeBankBlockchain-Data-Reconcile是一个具备轻量化,高性能,强扩展性的功能性中间件,配置方便,并从技术层面确保性能,如文件读写的异步处理、多线程处理等,并在处理流程中提供多接口,用于功能扩展,可插拔,同时支持外部集成封装,可根据不同场景定制开发。WeBankBlockchain-Data-Reconcile具备以下关键特性

支持自定义对账数据结构

对账数据格式可根据需求进行自定义设置

支持自定义对账规则

字段映射结构、对账处理等逻辑可动态扩展

支持多种对账文件格式

如txt、json等,同时提供了扩展接口,可定制开发支持更多格式

支持自定义对账任务和方式

调用方式包括手动或自动,任务频次、时间可配置

支持多种对账文件托管方式

默认支持FTP,同时提供传输接口,可扩展更多托管方式

对账处理流程可定制化开发

提供扩展接口,易于动态扩展和定制开发

快速开始

环境准备

在使用本组件前,请确认系统环境已安装相关依赖软件,清单如下:

依赖软件 说明 备注
FISCO-BCOS >= 2.0
Bash 需支持Bash(理论上来说支持所有ksh、zsh等其他unix shell,但未测试)
Java >= JDK[1.8]
Git 下载的安装包使用Git
MySQL >= mysql-community-server[5.7]
FTP 需要时安装

.. important:: FISCO-BCOS 2.0与3.0对比、JDK版本、WeBank-Data及其他子系统的 兼容版本说明 <https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/compatibility.html>_

项目准备

下载代码:
git clone https://github.com/WeBankBlockchain/Data-Reconcile.git
cd Data-Reconcile

注解

项目打包
./gradlew build

项目jar包在dist目录下,dist目录如下:

├── dist
│   ├── config
│   │   ├── application.properties
│   │   └── datasource.properties
│   │   └── filetransfer.properties
│   │   └── reconcile.properties
│   ├── start.sh
│   ├── stop.sh
│   └── Data-Reconcile-1.0.0-SNAPSHOT.jar
项目配置

配置文件位于dist/config目录下

├── dist
│   ├── config
│   │   ├── application.properties
│   │   └── datasource.properties
│   │   └── filetransfer.properties
│   │   └── reconcile.properties
数据库配置

关于数据库的连接配置在datasource.properties下,将链上导出数据所在的数据库参数配置到这里,链上数据需要借助数据导出组件WeBankBlockchain-Data-Export对链上数据进行导出,数据导出组件使用:WeBankBlockchain-Data-Export

必配项如下:

## data export DB config
spring.datasource.url=jdbc:mysql://[IP]:[PORT]/[database]?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=[user_name]
spring.datasource.password=[password]

##生产环境下需关闭以下自动建表配置,手动建表
spring.jpa.hibernate.ddl-auto=update

重要

上述自动建表配置关闭时,需将下述sql在以上配置的数据库中执行,否则默认开启自动建表,无需执行该sql。 对账任务表记录了对账任务的生命周期和流转状态

CREATE TABLE `task_info` (
  `pk_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `node_id` varchar(255) NOT NULL DEFAULT '""',
  `task_id` varchar(255) NOT NULL DEFAULT '""',
  `status` tinyint(4) NOT NULL,
  `triggered` tinyint(4) NOT NULL,
  `business_file_name` varchar(255) DEFAULT NULL,
  `business_file_path` varchar(255) DEFAULT NULL,
  `bc_file_path` varchar(255) DEFAULT NULL,
  `result_file_path` varchar(255) DEFAULT NULL,
  `last_execute_starttime` timestamp NULL DEFAULT NULL,
  `last_execute_endtime` timestamp NULL DEFAULT NULL,
  `data_range_begintime` timestamp NULL DEFAULT NULL,
  `data_range_endtime` timestamp NULL DEFAULT NULL,
  `retry_count` int(11) DEFAULT 0,
  `createtime` timestamp NOT NULL DEFAULT '2019-05-21 00:00:00',
  `updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`pk_id`),
  UNIQUE KEY `task_id` (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
对账配置

对账配置reconcile.properties,包括对账任务调度配置和对账数据规则配置

对账任务调度配置

对账任务配置及说明如下,配置项如下,其中必配项做了标记(Must),可采用默认配置

#定时对账开关
reconcile.task.timer.enable=true
#定时对账数据时间范围(单位:天),如设置为1天,则对账数据时间范围为对账任务触发时间起过去一天数据
reconcile.task.time.range.days=1
#定时对账时间规则(对账时间点设置)
#Online build/parse: http://cron.qqe2.com/
#Commonly used: second, minute, hour, day, month, year
#默认配置为每隔1分钟执行一次,可根据实际场景按需配置
reconcile.task.time.rule=0 0/1 * * * ?

#对账任务超时时间(ms)
reconcile.task.timeout=600000
#对账任务失败重试间隔时间(ms)
reconcile.task.retry.interval.time=60000
#对账失败任务重试次数,若配置为0则关闭任务重试
reconcile.task.retry.count=0
#对账状态补偿时间规则(执行中)
reconcile.executing.compensate.rule=0 0/1 * * * ?
#对账状态补偿时间规则(失败)
reconcile.failed.compensate.rule=0 0/1 * * * ?

对账任务相关详情参考基础模块中任务管理

对账数据规则配置

对账数据规则配置及说明如下,配置项如下,其中必配项做了标记(Must)

#业务数据提供方机构名 (Must)
reconcile.business.name=webank

##数据导出sql配置,包含查询sql和时间参数字段配置 (Must)
#链上数据导出库表查询语句,格式:select * from table where ... and 1=1(不需要添加数据时间范围和分页条件)
#以数据导出库表block_tx_detail_info为例:select block_height,tx_from,tx_to from block_tx_detail_info where 1=1
reconcile.bc.reconcileQuerySql=select [field...] from [table] where 1=1
#以数据导出库表block_tx_detail_info为例:select count(1) from block_tx_detail_info where 1=1
reconcile.bc.reconcileCountSql=select count(1) from [table] where 1=1

#数据导出库表数据查询时间范围字段 (Must)
#数据导出表的时间字段名,如果涉及多个表操作,请指出该字段属于哪个表,即添加字段前缀,如block_tx_detail_info.block_timestamp
reconcile.bc.QueryTimeField=block_timestamp

##默认对账模式配置:
#通用对账模式开关
reconcile.general.enabled=true
#业务数据文件格式, json or txt
reconcile.file.type=txt
#业务数据唯一键 (Must)
#唯一键用来匹配数据
reconcile.field.business.uniqueColumn=busId
#数据导出数据唯一键,与业务唯一键对应 (Must)
reconcile.field.bc.uniqueColumn=block_height
#两方数据字段匹配规则 (Must)
#格式以reconcile.fieldMapping作为前缀,reconcile.fieldMapping.业务方字段名=数据导出表字段名(唯一键映射无需再配),如下
#reconcile.fieldMapping.busId=block_height
#reconcile.fieldMapping.busFrom=tx_from
#reconcile.fieldMapping.busTo=tx_to

重要

开启默认对账后,对账字段映射规则字段为必配,业务对账文件中字段名和数据导出的字段名要对应。

对账配置更多说明参考配置介绍

文件传输配置

文件传输中心现支持本地或远程FTP两种模式,任选其一,默认配置为本地模式,可通过filetransfer.properties配置文件进行配置

文件中心配置

将filetransfer.properties中local.enabled配置为true即可,ftp保持关闭

#localfile switch
local.enabled=true
#FTP switch
ftp.enabled=false
FTP配置

ftp配置在 filetransfer.properties中,local.enabled设置为false,基本配置项如下:

#localfile switch
local.enabled=false

#FTP switch
ftp.enabled=true
ftp.host=127.0.0.1
ftp.port=21
ftp.userName=ftptest
ftp.passWord=123456
ftp.workDir=/home/upload

需自行搭建,推荐vsftp,参考链接:ftp安装

对账数据准备
业务方数据准备

如采用本地模式,需要预先将业务数据文件放至dist目录下; 如采用远程FTP模式,需要将业务数据文件推送至filetransfer.properties中配置的工作目录下(ftp.workDir配置目录)

业务对账文件命名规则为:业务数据提供方机构名_对账数据查询起始日期(如:webank_2020-11-19),机构名为对账配置reconcile.properties中的机构名,如webank。

测试时,为简化操作,可自建对账文件,文件名根据reconcile.properties配置中reconcile.task.time.range.days天数计算得到,如当前日期为2020-11-20,reconcile.task.time.range.days配置为1,则对账文件命名为:webank_2020-11-19

业务对账文件支持txt和json格式

txt文件格式如下:

block_height#_#tx_from#_#tx_to#_#
1#_#..#_#...#_#
2#_#..#_#...#_#
3#_#..#_#...#_#

格式说明:首行不可为空行,首行为对账字段,要与对账配置reconcile.properties中reconcile.fieldMapping设置字段对应,字段分隔符为#_#。

同时,也可自行通过代码定义字段和数据,组件提供txt格式文件的生成方法,在src/mian/java/com/webank/blockchain/data/reconcile/utils/FileUtills工具类中, 如下:

//数据写入新文件中
public static <T> File exportDataByTxtFormat(List<T> dataList, String filePath)

//append为true时,数据追加到文件末尾
public static <T> File exportDataByTxtFormat(List<T> dataList, String filePath,
boolean append) 

可以根据不同需求通过上述工具方法,定义业务对账文件字段和数据,并导出为文件,同时定义数据对象时,应实现toString()方法

以数据导出库表block_tx_detail_info为例,业务数据字段可定义如下:

    public void exportDataUtilTest() throws Exception {
        List<ExportData> dataList = new ArrayList<>();
        ExportData data1 = new ExportData(1, "..", "...");
        ExportData data2 = new ExportData(2, "..", "...");
        dataList.add(data1);
        dataList.add(data2);
        FileUtils.exportDataByTxtFormat(dataList,"out/export.txt");
    }

    static class ExportData{
        long busId;
        String busFrom;
        String busTo;
        public ExportData(long busId, String busFrom, String busTo) {
            this.busId = busId;
            this.busFrom = busFrom;
            this.busTo = busTo;
        }
    }

json格式文件如下:

[{"busId":"2","busFrom":"10","busTo":"sjj"},{"busId":"3","busFrom":"10","busTo":"sjj"}]

格式说明:json采用通过格式,可通过Jackson等工具包生成,这里不再赘述。

以上为业务方数据准备。

项目启动

项目启动

执行dist/目录下的start脚本

cd dist && bash start.sh

启动成功日志如下:

_images/runsuccess.png

对账执行结果文件保存在dist/out/result/下,如开启远程FTP模式,则将结果文件推送到远程FTP。

执行日志如下:

_images/log.png

执行结果本地保存在/dist/out/result目录中:

├── out
│   ├── bc
│   │   ├── BC_yyyy-MM-dd.txt
│   ├── business
│   │   ├── company_yyyy-MM-dd.txt
│   ├── result
│   │   ├── result_company_yyyy-MM-dd.txt

执行日志保存在logs目录下

项目扩展

支持业务根据自身需求对组件进行扩展,组件核心流程位于src/main/java/com/webank/blockchain/data/reconcile/handler目录下,如下:

├── handler
│   ├── executor
│   │   ├── DefaultReconcileExecuteHandler.java
│   │   └── ReconcileExecuteHandler.java
│   ├── filesource
│   │   ├── DefaultReconcileFileObtainHandler.java
│   │   └── ReconcileFileObtainHandler.java
│   ├── finish
│   │   ├── DefaultReconcileResultHandler.java
│   │   └── ReconcileResultHandler.java
│   ├── task
│   │   └── ReconcileTaskHandler.java
│   ├── Handler.java
│   ├── InvocationHandler.java
│   └── ReconcileHandlerFactory.java

对账流程默认分为四步:

1.任务管理,为执行责任链的首端,负责对账任务调度管理,任务模块由组件负责管理。

2.对账文件获取,分为业务对账文件和链上数据文件获取,提供两个扩展接口,如下,并提供默认实现,使用者可根据自身需要对接口进行实现

//链上数据导出,默认提供txt,json实现
public interface BCDataExportService{
    File exportData(String filePath, Date dataRangeBeginTime, Date dataRangeEndTime);
}
//业务对账文件获取,默认提供FTP文件获取实现
public interface FileTransferService {
    String sendFile(File file) throws Exception;
    File obtainFile(String fileName, String localFilePath) throws IOException;
}

3.对账执行,分为文件解析和数据对账处理,提供两个扩展接口,如下,并提供默认实现

//文件解析,默认提供txt,json实现
public interface FileParser {
    void parseAndTransfer(File businessReconFile, File bcReconFile, ReconcileTransfer transfer) throws ReconcileException;
}
//对账处理,提供通用对账逻辑实现
public interface ReconcileExecutor{
    ReconcileResult execute(ReconcileExecuteData executeData);
}

4.结果处理,包括结果导出和推送,提供扩展接口如下,并提供默认实现

//结果导出文件,默认提供txt,json实现
public interface ResultDataExportService {
    File exportResultData(String filePath, List<Future<ReconcileResult>> reconcileResults);
}

以上是对账核心流程。

另外,也可对核心流程功能进行增删扩展,提供流程处理扩展接口如下:

public interface Handler {
    void invoke(ReconcileContext context, InvocationHandler handler) throws Exception;
}

流程管理在ReconcileHandlerFactory类中,可在该类中对流程步骤进行扩展管理。

组件设计

整体架构

区块链对账组件整体架构如下图所示。主要包括:基础模块、对账数据传输模块、对账消息模块、对账执行模块。

_images/reconcile_framework.png

各模块功能概要如下:

  1. 基础模块负责对上层业务模块的技术支持,提供了网络传输、任务管理、配置管理、文件管理等能力。
  2. 对账数据传输模块负责业务和链上数据的获取和对账文件的推送。
  3. 对账消息模块负责与业务方的通信,包含了对账请求和对账结果通知等功能。
  4. 对账模块负责对账的具体执行和处理,包含文件解析、数据提取、对账处理、结果导出等功能。

业务流程

业务方将对账文件发送给对账方,对账方可以通过定时任务或者主动调用的方式开启对账任务,其中主动调用分两种方式:一种是对账方手动调用,另一种是业务方发送对账请求。任务首先会先从文件资源中心(如FTP)拉取业务方对账文件,然后将链上数据导出为文件,进行对账,并将对账结果生成文件推送给业务方,任务完成。

对账时序图如下:

_images/reconcile_timecall.png

流程图如下图所示

_images/reconcile_process.png

对账方和业务方关系如下,该组件服务为对账方使用。

_images/reconcile_deployment.png

模块设计

对账组件各功能模块采用责任链模式连接,可插拔,可扩展。

接口关系如下:

_images/reconcile_interface.png

调用时序如下:

_images/reconcile_call.png

基础模块

基础模块提供网络传输、任务管理、配置管理、文件管理等能力。

配置管理

配置管理负责对于对账方配置文件的读取管理。

DB配置

DB配置位于resource目录下datasource.properties文件,用于数据库的连接配置,主要包括了对账方数据库url、username、password、database等配置,其中还有用于数据导出文件的sql配置。

具体配置如下:

## data export DB config
spring.datasource.url=jdbc:mysql://[IP]:[PORT]/[database]?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=[user_name]
spring.datasource.password=[password]
传输配置

传输配置包含了文件传输和消息传输中间件的配置,这里默认支持本地和远程ftp来完成文件的传输,配置位于resource目录下filetransfer.properties文件,用于FTP的连接配置,主要包括ip地址、端口号、username、password等配置。

配置如下:

#localfile switch
local.enabled=true

#FTP switch
ftp.enabled=false
ftp.host=127.0.0.1
ftp.port=21
ftp.userName=
##ftp.userName=ftptest
ftp.passWord=
ftp.workDir=/home/upload
ftp.encoding=UTF-8
ftp.maxTotal=100
ftp.minIdel=2
ftp.maxIdle=5
ftp.maxWaitMillis=3000

PS:消息中间件可按需增加配置。

对账配置

对账配置位于resource目录下reconlie.properties文件,提供对账任务和对账规则映射配置。

配置如下:

#定时对账开关
reconcile.task.timer.enable=true
#定时对账数据时间范围(单位:天)
reconcile.task.time.range.days=0
#定时对账时间规则
#Online build/parse: http://cron.qqe2.com/
#Commonly used: second, minute, hour, day, month, year
reconcile.task.time.rule=0 0 1 * * ?

#对账任务超时时间(ms)
reconcile.task.timeout=600000
#对账任务失败重试间隔时间(ms)
reconcile.task.retry.interval.time=60000
#对账失败任务重试次数
reconcile.task.retry.count=2
#对账状态补偿时间规则(执行中)
reconcile.executing.compensate.rule=0 0/1 * * * ?
#对账状态补偿时间规则(失败)
reconcile.failed.compensate.rule=0 0/1 * * * ?

#业务数据提供方机构名 (Must)
reconcile.business.name=webank

##数据导出sql配置,包含查询sql和时间参数字段配置 (Must)
#链上数据导出库表查询语句,格式:select * from table where ... and 1=1(不需要添加数据时间范围和分页条件)
#以数据导出库表block_tx_detail_info为例:select block_height,tx_from,tx_to from block_tx_detail_info where 1=1
reconcile.bc.reconcileQuerySql=select [field...] from [table] where 1=1

#数据导出库表数据查询时间范围字段 (Must)
#数据导出表的时间字段名,如果涉及多个表操作,请指出该字段属于哪个表,即添加字段前缀,如block_tx_detail_info.block_timestamp
reconcile.bc.QueryTimeField=block_timestamp

##默认对账模式配置:
#通用对账模式开关
reconcile.general.enabled=true
#业务数据文件格式, json or txt
reconcile.file.type=txt
#业务数据唯一键 (Must)
#唯一键用来匹配数据
reconcile.field.business.uniqueColumn=busId
#数据导出数据唯一键,与业务唯一键对应 (Must)
reconcile.field.bc.uniqueColumn=block_height
#两方数据字段匹配规则 (Must)
#格式以reconcile.fieldMapping作为前缀,reconcile.fieldMapping.业务方字段名=数据导出表字段名,如下
#reconcile.fieldMapping.busId=block_height
#reconcile.fieldMapping.busFrom=tx_from
#reconcile.fieldMapping.busTo=tx_to
3.1.1.4 系统配置

系统配置位于resource目录下application.properties文件,用于组件的基础配置,包括项目名称,日志等设置。配置如下:

system.name=
logs...
网络传输

网络传输提供文件和消息的传输功能。

文件传输

文件传输负责业务对账文件和对账方对账结果的传输,核心接口如下:

public interface FileTransferService {

    String sendFile(File file) throws Exception;
    File obtainFile(String fileName, String localFilePath);

}

这里提供默认实现,采用FTP来作为文件资源存储中心,来实现对账方和业务方的文件传输。实现类如下:

public class FtpServiceImpl implements FileTransferService {
    @Autowired
    FTPConfig config;
    @Autowired
    FtpPool pool;
    ...
    ...
}
消息传输

消息传输负责与业务方的消息通信,提供两种方式,这里默认采用HTTP交互,另外提供mq的消息处理接口,可扩展,接口如下:

public interface NoticeService <T,S>{

    void  receiveMsg(T t);

    void  sendMsg(S s);

}
文件管理

文件管理提供对于对账文件的管理和读写。

文件读写

提供对于对账文件的读写能力,文件格式通过对账配置可获得,包括了业务对账文件的读取、对账结果文件和BC数据导出文件的写入功能。

文件存储

网络下载的文件和对账结果文件的保存,统一保存在/out目录下,并通过FileManager来完成文件的管理。

任务管理

任务管理负责对账任务的调度执行,包括了定时任务和手动触发模式,另外还有对于任务的失败补偿。

任务表预先在对账方DB中创建,任务信息表(task_info)结构如下:

字段名 类型 comment
pkId bigInte(20) 主键id
task_id varchar(255) 任务序列Id,唯一键
node_id varchar(255) 任务节点标识
triggered thinint(4) 触发方式,1-定时任务 2-手动
business_file_name varchar(255) 对账文件名
business_file_path varchar(255) 业务对账文件路径
bc_file_path varchar(255) BC对账文件路径
result_file_path varchar(255) 对账结果文件路径
status thinint(4) 0-待执行;1-执行中;2-已完成;3-执行失败; 4-终止
last_execute_starttime timestamp 末次执行开始时间
last_execute_endtime timestamp 末次执行结束时间
retry_count thinint(4) 重试次数
createtime timestamp 创建时间
updatetime timestamp 更新时间

任务状态对应场景:

待执行-0(初始态) 任务创建时
执行中-1 (中间态) 流程开始时
已完成-2(终态) 对账完成时
执行失败-3(中间态) 异常
结束终止-4(终态) 任务超时、重试次数达到上限

状态流转:

1.INIT -> EXECUTING -> SUCCESS
2.INIT -> EXECUTING -> FAILURE -> SUCCESS
3.INIT -> EXECUTING -> FAILURE -> TERMINATE
定时任务

根据对账中任务配置来开启定时任务,创建任务开始对账流程。定时任务类如下:

public class ReconcileTaskTimer {
   @Scheduled(cron = "${task.time.rule}")
   public void execute() {
       ...
    }   
}
任务补偿

对账任务中间态的补偿,这里包含了任务的超时时间和重试次数的限制,可配置,单独开启线程扫描失败任务,进行重试。任务补偿类如下,包含对执行失败状态执行中的两种中间态补偿

public class TaskCompensate {
    public void executingStateCompensate(){}
    public void failedStateCompensate(){}
}

失败状态的补偿流程如下:

_images/reconcile_taskcomp.png

执行中任务的补偿如下:

_images/reconcile_taskcomp2.png

对账数据模块

对账数据模块负责对账方和业务方的对账数据传输。

其中对账源文件的获取通过以下抽象类实现:

public abstract class ReconcileFileObtainHandler implements Handler {

    @Override
    public void invoke(ReconcileContext context, InvocationHandler handler) throws Exception {
       ....
       ....
    }

    abstract File getBCReconcileFile(TaskInfo taskInfo) throws Exception;

    abstract File getBusinessReconcileFile(TaskInfo taskInfo) throws Exception;

}
业务对账文件获取

这里会每次开启任务都会到文件资源中心(如FTP)中获取业务对账文件,对账文件的命名规则为:业务方机构名称_对账数据启示日期(提供以天为单位的实现),业务机构名可在对账配置中读取。格式如下:

webank_2020-05-22

实现方法如下:

 abstract File getBusinessReconcileFile(TaskInfo taskInfo)

文件格式默认支持txt,json。

对于数据导出txt文件,提供了数据导出的工具类,在utils/FileUtils下。

//数据写入新文件中
public static <T> File exportDataByTxtFormat(List<T> dataList, String filePath)

//append为true时,数据追加到文件末尾
public static <T> File exportDataByTxtFormat(List<T> dataList, String filePath,
boolean append) 
BC数据导出

数据按配置sql取链上数据,导出为文件,格式为txt,查询范围根据业务对账文件名中时间范围类取数据。

实现方法如下:

abstract File getBCReconcileFile(TaskInfo taskInfo)
对账结果处理

对账方将对账结果导出为文件,并发给业务方。

核心接口如下:

public class ReconcileResultHandler implements Handler {
    @Override
    public void invoke(ReconcileContext context, Handler handler) {}
    abstract File exportData(Map<String,ReconcileResult> reconcileResults) throws Exception;

    abstract void transferResultFile(File file) throws Exception;
}

导出文件提供了扩展接口如下,并提供json和txt的默认实现

public interface ResultDataExportService {

    File exportResultData(String filePath, Map<String, ReconcileResult> reconcileResults) throws IOException;
}
对账消息模块

对账消息模块负责业务方与对账方的消息交互,业务方可主动发起对账,并查询对账结果

默认采用HTTP实现,接口如下:

@RequestMapping("reconcile/")
public class ReconcileController {

    @RequestMapping(value = "getReconcileResult")
    public void getReconcileResult(@RequestParam(name =         "fileName") String fileName){}

    @RequestMapping("requestReconcile")
    public void requestReconcile(@RequestParam(name = "fileName") String fileName){}
}

可以通过NoticeService 扩展接口实现mq消息传输,该功能可根据具体业务场景选择。

对账请求

业务方可主动发起对账请求,通过上述requestReconcile接口可实现业务方触发对账功能。

结果通知/查询

业务方可通过getReconcileResult查询对账任务执行结果,返回对账结果文件路径等结果信息。

对账模块

对账模块负责对账文件的解析、数据提取配对、对账执行、对账结果处理等功能。

核心接口:

public class ReconcileExecuteHandler implements Handler {
    @Override
    public void invoke(
    ReconcileContext context, Handler handler) {
    }
    abstract Map<String,ReconcileResult>     parseAndExecute(File businessReconFile, File bcReconFile) throws ReconcileException;

}
文件解析

文件解析负责对账文件的解析处理。调用模板方法:

  abstract Map<String,ReconcileResult> parseAndExecute(File businessReconFile, File bcReconFile) 

并发解析两方对账文件,并调用数据提取的接口,获得数据。文件解析接口关系图如下:

_images/reconcile_fileinterface.png

这里提供两种默认实现Json和txt,其中txt内容格式如下,字段之间#_#

间隔,数据按行\n区分,每行为一条对账数据。

#_#pk_id#_#block_height#_#certainty#_#
#_#5330#_#12329#_#1#_#
#_#5329#_#12328#_#1#_#
#_#5328#_#12327#_#1#_#

Json文件格式:

{"id":"123","success":true,"failReason":null}
数据转发

将解析配对后的数据交给执行器处理,实现解析和执行的解耦

接口如下:

public interface ReconcileTransfer {

    void transferToExecutor(List<ReconcileExecuteData> executeData);

    Map<String,ReconcileResult> getReconcileResult();

}
对账执行

根据对账规则进行对账处理,并将结果缓存。

核心接口:

public interface ReconcileExecutor{

    void execute(List<ReconcileExecuteData> executeData, Map<String,ReconcileResult> resultMap);

}

组件扩展

流程扩展接口:

Handler 对账流程处理接口,默认分为四步
InvocationHandler 处理链调用接口

当前默认流程中提供了一些可扩展的接口,扩展接口列表如下:

FileTransferService 文件传输接口,提供ftp的默认实现
NoticeService 消息传输接口,用于mq消息传输
FileParser 文件解析接口,提供txt、json的默认实现
ReconcileExecutor 对账执行接口,提供默认实现
ResultDataExportService 对账结果导出接口,提供txt、json实现

附录

MySql的安装

此处以Centos安装MariaDB为例。MariaDB数据库是 MySQL 的一个分支,主要由开源社区在维护,采用 GPL 授权许可。MariaDB完全兼容 MySQL,包括API和命令行。其他安装方式请参考MySQL官网

(1)安装MariaDB

  • 安装命令
sudo yum install -y mariadb*

(2)启停

启动:sudo systemctl start mariadb.service
停止:sudo systemctl stop  mariadb.service

(3)设置开机启动

sudo systemctl enable mariadb.service

(4)初始化root用户

执行以下命令:
sudo mysql_secure_installation
以下根据提示输入:
Enter current password for root (enter for none):<–初次运行直接回车
Set root password? [Y/n] <– 是否设置root用户密码,输入y并回车或直接回车
New password: <– 设置root用户的密码
Re-enter new password: <– 再输入一次你设置的密码
Remove anonymous users? [Y/n] <– 是否删除匿名用户,回车
Disallow root login remotely? [Y/n] <–是否禁止root远程登录,回车
Remove test database and access to it? [Y/n] <– 是否删除test数据库,回车
Reload privilege tables now? [Y/n] <– 是否重新加载权限表,回车
  • 使用root用户登录,密码为初始化设置的密码
mysql -uroot -p -h localhost -P 3306
  • 授权root用户远程访问

    注意,以下语句仅适用于开发环境,不能直接在实际生产中使用!!! 以下操作仅供参考,请勿直接拷贝,请自定义设置复杂密码。

mysql > GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql > flush PRIVILEGES;

重要

安全温馨提示:
例子中给出的数据库密码(123456)仅为样例,强烈建议设置成复杂密码 例子中root用户的远程授权设置会使数据库在所有网络上都可以访问,请按具体的网络拓扑和权限控制情况,设置网络和权限帐号

(5)创建test用户并授权本地访问

mysql > GRANT ALL PRIVILEGES ON *.* TO 'test'@localhost IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql > flush PRIVILEGES;

(6)测试是否成功

  • 登录数据库
mysql -utest -p123456 -h localhost -P 3306
  • 创建数据库
mysql > create database webasebee;
mysql > use webasebee;

重要

以上语句仅适用于开发环境,不能直接在实际生产中使用!!!以上设置会使数据库在所有网络上都可以访问,请按具体的网络拓扑和权限控制情况,设置网络和权限帐号

Java安装

Ubuntu环境安装Java
# 安装默认Java版本(Java 8或以上)
sudo apt install -y default-jdk
# 查询Java版本
java -version 
CentOS环境安装Java
# 查询centos原有的Java版本
$ rpm -qa|grep java
# 删除查询到的Java版本
$ rpm -e --nodeps java版本
# 查询Java版本,没有出现版本号则删除完毕
$ java -version
# 创建新的文件夹,安装Java 8或以上的版本,将下载的jdk放在software目录
# 从openJDK官网(https://jdk.java.net/java-se-ri/8)或Oracle官网(https://www.oracle.com/technetwork/java/javase/downloads/index.html)选择Java 8或以上的版本下载,例如下载jdk-8u201-linux-x64.tar.gz
$ mkdir /software
# 解压jdk 
$ tar -zxvf jdk-8u201-linux-x64.tar.gz
# 配置Java环境,编辑/etc/profile文件 
$ vim /etc/profile 
# 打开以后将下面三句输入到文件里面并退出
export JAVA_HOME=/software/jdk-8u201-linux-x64.tar.gz
export PATH=$JAVA_HOME/bin:$PATH 
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 生效profile
$ source /etc/profile 
# 查询Java版本,出现的版本是自己下载的版本,则安装成功。
java -version 

Git安装

git:用于拉取最新代码

centos:

sudo yum -y install git

ubuntu:

sudo apt install git

FTP安装

ftp:用于文件托管

centos:

搭建vsftp服务器
# 安装vsftpd
yum -y install vsftpd
# 配置vsftp
vim /etc/vsftpd/vsftpd.conf
修改其中: anonymous_enable=NO  禁止匿名登录
取消chroot_list_enable=YES,chroot_list_file=/etc/vsftpd/chroot_list的注释  
在最后一行新增 allow_writeable_chroot=YES
然后保存退出
增加访问ftp的用户
# 编辑账户文件,输入账户名,多个用户名以空格隔开
vim /etc/vsftpd/chroot_list
# 设置上传目录
mkdir -p /home/upload
# 新增用户,配置主文件夹
useradd -d /home/upload -s /sbin/nologin ftptest
# 将用户放置ftp组
usermod -aG ftp ftptest
# 将文件夹分配给用户
chown ftptest /home/upload
# 设置密码
passwd ftptest
修改firewall使之允许ftp功能
systemctl start firewalld.service
firewall-cmd --permanent --zone=public --add-service=ftp
firewall-cmd --reload
修改firewall使之允许ftp功能
# 启动ftp
systemctl start vsftpd
# 查看ftp状态
systemctl status vsftpd
# 设置开机自启动
chkconfig vsftpd on
安装问题
ftp无法正常连接

安装完成后可通过以下命令测试ftp是否可以正常登录

ftp localhost

如果无法登录,可在/etc/shells文件中,增加配置:/sbin/nologin 保存后重启ftp,尝试登录

ftp无法下载上传文件

ftp配置目录需赋予相应的读写权限,如

chmod 777 xxxx

更多开源项目

更多项目

重要

FISCO-BCOS 2.0与3.0对比、JDK版本、WeBank-Data及其他子系统的 兼容版本说明