走读代码 | WeBASE-Node-Manager的NodeService如何判断节点状态是否正常

    登录WeBASE管理管理平台,点击“链管理”下的“节点管理”,显示节点的各项信息,其中包括状态,这次走读代码的内容,就是“节点列表”中的“状态”是如何判断的。

一、请求路径

    在页面上点击右键选择“检查”,或者按F12键,打开浏览器的调试工具,点击“Network”选项卡,查看请求后端请求的地址为:WeBASE-Node-Manager/node/nodeList/1/1/100。

    然后查看后端WeBASE-Node-Manager的源代码,在全局java文件中搜索nodeList,在NodeController中找到请求方法为:

@GetMapping(value = "/nodeList/{groupId}/{pageNumber}/{pageSize}")
public BasePageResponse queryNodeList(@PathVariable("groupId") Integer groupId,
        @PathVariable("pageNumber") Integer pageNumber,
        @PathVariable("pageSize") Integer pageSize,
        @RequestParam(value = "nodeName", required = false) String nodeName)
        throws NodeMgrException

    其中第1个参数是groupId群组ID,第2和第3个是分页参数,第4个非必填项是节点名称,表示也可以根据节点名称进行查询。

二、判断节点状态并更新到数据库

    在NodeController中代码如下:

try{
nodeService.checkAndUpdateNodeStatus(groupId);
  }catch (Exception e) {
    log.error("queryNodeList checkAndUpdateNodeStatus groupId:{}, error: []", groupId, e);
        }

    在NodeService代码中提供了一个根据groupId检查和更新节点状态的方法:

public void checkAndUpdateNodeStatus(int groupId)

第一步:根据groupId获取保存在数据库的本地节点列表(这个数据库是WeBASE-Node-Manager的本地数据库)。

List<TbNode> nodeList = queryByGroupId(groupId);

第二步:根据groupId获取共识节点列表(从区块链上)。

List<PeerOfConsensusStatus> consensusList = getPeerOfConsensusStatus(groupId);

    其中在getPeerOfConsensusStatus方法中:

    首先用http请求工具RestTemplate调用了web3/consensusStatus接口,返回指定群组内的共识状态信息。

ConsensusInfo consensusInfo = frontInterface.getConsensusStatus(groupId);

    然后判断共识状态信息如果为空,返回null,提示节点状态检查失败。否则获取共识状态信息里的viewInfos信息,读取每个节点的view数量填充到节点共识列表里返回。

List<PeerOfConsensusStatus> dataIsList = new ArrayList<>();
List<ViewInfo> viewInfos = consensusInfo.getViewInfos();
for (ViewInfo viewInfo : viewInfos) {
dataIsList.add(
new PeerOfConsensusStatus(viewInfo.getNodeId(), new BigInteger(viewInfo.getView())));
        }
return dataIsList;

第三步:根据groupId获取获取群组内观察节点列表(从区块链上)。

List<String> observerList = frontInterface.getObserverList(groupId);

    调用了web3/observerList接口,返回指定群组内的观察节点列表。

第四步:遍历本地节点nodeList:

1、判断是否在检查间隔内

    求每个本地节点的修改时间modifyTime到当前时间间隔duration的毫秒数subTime。 如果:

    (1)subTime小于(共识节点和观察节点相加的总数nodeCount乘以1000+3500);

    (2)并且 本地节点的创建时间createTime在修改时间之前modifyTime。 那么跳过检查,否则继续向下执行。

2、判断每个本地节点的类型

    遍历观察节点,如果本地节点的ID和观察节点ID相同,赋值nodeType为1(观察节点),否则为0(共识节点)。

3、根据群组ID和本地节点ID获取群组内同步状态信息里最新的块高latestNumber。

BigInteger latestNumber = getBlockNumberOfNodeOnChain(groupId, nodeId);

    调用了web3/syncStatus接口,获取群组内同步状态信息。

    如果本地节点ID和同步状态信息里的nodeId相同,直接获取块高blockNumber;否则就遍历同步状态信息里的节点列表,找到和本地节点ID相同的节点取对应的块高,没有找到的话设置块高为0。

4、根据本地节点ID从共识列表consensusList中获取view数量latestView。

BigInteger latestView = consensusList.stream()
.filter(cl -> nodeId.equals(cl.getNodeId())).map(PeerOfConsensusStatus::getView).findFirst()
.orElse(BigInteger.ZERO);

5、如果本地节点被判断为共识节点:

    如果:

    (1)本地节点的块高localBlockNumber和最新的块高latestNumber相同;

    (2)并且本地节点的localPbftView和最新的latestView相同。

    那么:

        设置此节点的nodeActive为INVALID值2。

    否则:

        设置此节点块高为latestNumber,PbftView为latestView。

        设置此节点的nodeActive为NORMAL值1。

6、如果本地节点被判断为观察节点:

    根据群组ID调用web3/blockNumber接口,获取群组最新块高。

    如果:

        最新的块高latestNumber和群组的最新块高不相同,并且本地节点的块高localBlockNumber和最新的块高latestNumber相同,

    那么:

        设置此节点的nodeActive为INVALID值2。

    否则:

        设置此节点块高为latestNumber,PbftView为latestView。

        设置此节点的nodeActive为NORMAL值1。

7、更新节点状态及其它参数

    设置本地节点的修改时间,并将块高blockNumber、pbftView、nodeActive等更新保存到本地数据库。

8、如果是手动部署或者区块链的状态是运行:

    根据本地节点ID获取前置节点,如果本地节点的状态是NORMAL,那么前置节点的状态为RUNNING;如果本地节点的状态是INVALID,那么前置节点的状态为STOPPED。

    把前置节点的状态更新保存到本地数据库。

三、查询保存在数据库的本地节点列表。

    回到NodeController代码中,根据groupId和nodeName查询保存在数据库的本地节点列表:

List<TbNode> listOfnode = nodeService.queryNodeList(queryParam);

返回给前端页面。