Fabric Gossip实验教程

Gossip在Hyperledger Fabric中发挥着重要的作用。在这个教程中, 我们将分阶段考察Fabric网络启动时gossip的运行机制,学习Fabric 中的一些核心概念,例如主导节点/leader、锚节点/anchor等,理解 gossip是如何帮助Hyperledger Fabric成为一个可伸缩的联盟链平台。

1、Fabric Gossip概述

我们大多数都是从Hyperledger Fabric自带的演示网络例如First Network 开始学习并尝试Fabric区块链的。First Network提供了一个脚本byfn.sh 向我们展示了启动一个Fabric网络的典型流程:

  • 生成密码学资料和通道配置数据
  • 启动网络组件,例如排序节点/orderers、对等节点/peers…
  • 将对等节点加入通道
  • 更新锚节点

经过以上操作,Fabric网络就准备好了,接下来通常就是部署包含业务逻辑的链码。

在上述流程中有些藏在后台的过程很有意思。在这个教程中我们主要 考察gossip的作用,了解它是如何帮助实现一个可伸缩的解决方案的。 Hyperledger Fabric采用gossip作为点对点通信机制。为了优化整个 信息流转过程,Fabric实现了gossip数据扩散协议以达成可伸缩的网络部署 和运营。

Hyperledger Fabric官方文档中的gossip 提供了一个总体上的描述。在这里我们将抽取相关的信息并通过演示来看看 gossip在实际运作中的表现。

2、Fabric Gossip的引导节点配置

Gossip引导节点配置需要在每个对等节点/peer上进行,该配置包含了同一机构中的一个或 一组对等节点。当一个peer启动运行后,它就会联络列表中的其他peer节点进行消息 的gossip传播。

在经典的First Network配置中,在每个机构中有两个peer节点,因此一个合理的 设置就是将另一个peer节点作为gossip的引导节点,这也是我们在配置文件(base/docker-compose-base.yaml) 中观察到的。下面只显示了Org1的peer节点的信息,不过我们可以在Org2的peer节点 配置中观察到类似的信息:

当peer节点启动后,它会先查找用于gossip通信的引导节点。后续我们 也会看一下如果没有定义引导节点会发生什么情况。

3、Fabric Gossip的主导节点/leader peer

一个机构中的主导节点/leader负责从排序服务接收区块并分发给同一机构 中的其他peer节点。请记住在一个fabric网络中,所有的peer节点都需要从 排序服务接收新区块。leader节点的引入优化了新区块同步到所有peer节点 的流程,因为排序服务只需要向每个机构的leader节点发送新区块就可以了, 接下来由leader节点负责同步到其他peer节点。

每个机构都有自己的leader节点。在演示中我们将看到这一点。每个通道 也都有自己的leader节点。在peer节点加入一个通道之前,它是没有leader 这个概念的,只有当它加入通道之后,才涉及leader节点的问题。

在一个机构中,leader节点可以静态配置或者动态选举。在First Network 中的默认设置是通过选举决定,该配置在base/peer-base.yaml中:

4、Fabric Gossip的锚节点/anchor peer

在一个网络中需要锚节点/anchor peer来获取其他机构的通道成员信息。 如果没有锚节点的化,那么对通道成员的了解将局限在当前机构内。例如, 当没有锚节点时,在Org1中的peer节点只了解Org1内部的其他peer节点 是通道成员,但是没法了解Org2机构内的peer节点也是通道成员。在一个 通道中至少需要一个锚节点以打破这种信息的割裂。

锚节点的配置需要对通道进行更新操作。首先使用configtxgen创建一个 更新交易,签名该交易并发送给排序服务,排序服务就会生成一个新的 配置区块,其中包含了这个用于更新锚节点配置的交易。当这个区块 到达通道中所有的peer节点并被各节点提交后,所有的peer节点也就都 了解哪个是锚节点了,并进而通过彼此的gossip传播实现了对整个通道 成员的信息了解,即包括机构内成员,也包括机构外成员。

在后面部分我们将看到配置锚节点前后的不同运行情况。

5、Fabric First Network概述

我们使用的是First Ntwork,其中包含两个机构Org1和Org2,每个机构 包含两个peer节点(peer0和peer1),定义了通道mychannel并将所有 4个peer节点加入该通道,两个机构中的peer0均被配置为锚节点。

当执行byfn.sh时,该脚本执行以下任务:

  • 生成密码学资料和通道配置数据(Step 1)
  • 用docker-composer启动所有网络组件(容器)(Step 2-5)
  • 创建mychannel通道的genesis区块(block#0)(Step 6)
  • 将全部4个peer节点加入mychannel(Step 7-10)
  • 更新两个机构的anchor peer配置信息(Step 11-12)

网络已经就绪,每个peer节点都了解通道中的其他节点。下面是 执行脚本后的结果(使用-n选项是告诉byfn脚本不要部署链码):

在下面的演示中我们基本遵循上述流程。为了更好地观察实验结果, 我们将逐个分解peer节点的docker-compose配置,之后也会修改 配置文件或者重新安排先后顺序并观察不同的结果。

6、Fabric Gossip实验STEP 0 :准备

从first-network/直接拷贝一个新目录:

1
2
cd fabric-samples
cp -r first-network kc-first-network

我们将在这个目录上进行后续操作:kc-first-network/

同时,原始的CLI容器依赖于所有启动的网络组件。由于我们将逐个 启动网络组件,因此先注释掉依赖关系。

7、Fabric Gossip实验Step 1:生成密码学资料和通道配置数据

我们利用byfn.sh来生成Fabric网络所需的密码学资料和通道配置数据。

1
2
cd kc-first-network
./byfn.sh generate

8、Fabric Gossip实验Step 2:启动Orderer和CLI容器

1
docker-compose -f docker-compose-cli.yaml up -d orderer.example.com cli

9、Fabric Gossip实验Step 3:启动peer0.org1节点

1
docker-compose -f docker-compose-cli.yaml up -d peer0.org1.example.com

打开终端查看peer0.org1.example.com的日志:

1
docker logs -f peer0.org1.example.com

让我们重点关注gossip相关的活动。从日志中我们可以了解gossip的初始化过程 以及gossip实例的启动过程。

然而,由于配置了gossip的引导节点,peer0.org1.example.com 会联络peer1.org1.example.com, 但是peer1目前还没有运行。

10、Fabric Gossip实验Step 4:启动peer1.org1

1
docker-compose -f docker-compose-cli.yaml up -d peer1.org1.example.com

我们没有看到和peer0类似的无法访问gossip引导节点的问题。实际上peer1.org1.example.com 也配置了peer0.org1.example.com作为其gossip引导节点,并且在启动时会尝试链落peer0.org1.example.com。 由于peer0已经启动了,因此从日志中可以看到peer1成功联络到peer0(grpc.method=Ping, grpc.code=OK)。

几乎在peer1.org1.example.com启动的同时,peer0.org1.example.com也会 联络peer1.org1.example.com。可以看到时间戳是吻合的。

  • gossip instance of peer1.org1.example.com started in 06:39:05.878 (above)
  • peer0.org1.example.com reached peer1.org1.example.com in 06:39:05.892 (below)

这表示两个peer节点在gossip层已经连接上了。注意目前还没有通道相关 的角色例如leader节点或anchor节点,只有加入通道后才会涉及这些概念。

11、Fabric Gossip实验Step 5:启动Org2的peer节点

为了遵循byfn.sh脚本的演示流程,我们也启动peer0.org2.example.com 和 peer1.org2.example.com 。 可以观察到类似的行为:

1
docker-compose -f docker-compose-cli.yaml up -d peer0.org2.example.com peer1.org2.example.com

由于两个节点几乎同时启动,因此我们没有看到之前在step3出现的peer0连接gossip引导 节点的问题。

12、Fabric Gossip实验Step 6:为mychannel通道准备创世区块

1
2
3
docker exec cli peer channel create -o orderer.example.com:7050 --tls \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-c mychannel -f ./channel-artifacts/channel.tx

结果genesis区块文件mychannel.block保存在CLI容器内,该文件用于将peer 节点加入通道mychannel。

13、Fabric Gossip实验Step 7:将peer0.org1加入通道mychannel

注意CLI容器的默认设置是以Org1的Admin身份连接peer0.org1.example.com。

1
docker exec cli peer channel join -b mychannel.block

从日志中可以观察到以下内容:

  • 使用genesis区块创建通道mychannel的账本
  • 提交block#0
  • mychannel加入gossip网络
  • 还没有找到两个机构的锚节点配置信息
  • 成为主导节点,被选举为主导节点

14、Fabric Gossip实验Step 8:将peer1.org1加入通道mychannel

1
2
3
4
docker exec \
-e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 \
-e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt \
cli peer channel join -b mychannel.block

可以观察到和peer0.org1.example.com的日志类似的内容,除了主导节点的选举部分。

因此,从通道角度看,peer0.org1.example.com是Org1的主导节点,负责从排序服务接收 新区块并发送给Org1中的其他peer节点。

15、Fabric Gossip实验Step 9:Org1的peer节点了解通道成员信息

当一个机构内peer节点的主导关系确定后,我们立即可以从两个 节点的日志中看到它们已经了解了通道中的成员信息。

  • peer0.org1.example.com: now know peer1.org1.example.com as channel member

  • peer1.org1.example.com: now know peer0.org1.example.com as channel member

16、Fabric Gossip实验Step 10:将Org2的peer节点加入mychannel通道

1
2
3
4
5
6
7
8
9
10
11
12
13
docker exec \
-e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \
-e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \
-e CORE_PEER_LOCALMSPID="Org2MSP" \
-e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
cli peer channel join -b mychannel.block

docker exec \
-e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \
-e CORE_PEER_ADDRESS=peer1.org2.example.com:10051 \
-e CORE_PEER_LOCALMSPID="Org2MSP" \
-e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt \
cli peer channel join -b mychannel.block

和之前Org1的情况类似,我们可以看到:

  • peer0.org2.example.com: as a leader, and also know peer1.org2.example.com as channel member

  • peer1.org2.example.com: see someone as leader, and also know peer0.org2.example.com as channel member

现在我们知道gossip已经在单一机构内工作正,因为peer节点彼此都 了解对方的存在了。不过这还没结束,因为peer节点还需要了解其他 机构中的peer节点,这需要配置锚节点/anchor peer。

17、Fabric Gossip实验Step 11:更新Org1的锚节点

1
2
3
docker exec cli peer channel update -o orderer.example.com:7050 --tls \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-c mychannel -f ./channel-artifacts/Org1MSPanchors.tx

我们首先看到生成了一个新的区块block#1并且被Org1和Org2的所有peer节点接收 并提交。让我们研究一下。

首先,我们看一下新的区块是如何到达各peer节点的。我们知道新区块是orderer 生成的。从tcpdump的trace中我们只看到orderer.example.com在与peer0.org1.example.com 和peer0.org2.example.com通信,而没有与两个机构中的peer1节点通信。这是因为 两个机构中的peer0是主导节点,orderer只需要把新区块发给主导节点。

注意这里只显示了两个包,实际上有一系列的包从orderer发送给两个机构的 peer0节点。不给过我们没有看到发给peer1的包。

另外,通过捕捉每个peer节点上的接收block#1的日志,我们可以断定:

  • peer0.org1.example.com (timestamp: 07:01:34.583)

  • peer1.org1.example.com (timestamp: 07:01:34.588)

  • peer0.org2.example.com (timestamp: 07:01:34.631)

  • peer1.org2.example.com (timestamp: 07:01:34.637)

我们看到两个机构中的peer1接收到block#1都要比peer0晚一点。虽然 这不是充分的中举,至少它符合我们所说的由主导节点负责转发新区块 的理论。这就是伸缩性实现的机制,通过引入主导节点并将新区块的 广播拆分为两层。

接下来我们将考察每个peer节点将区块提交给账本之后会发生什么情况。 一旦了解到锚节点的存在,这些peer节点都会执行gossip操作。经过几轮 gossip扩散,我们可以看到通道的成员信息:

  • peer0.org1.example.com

  • peer1.org1.example.com

  • peer0.org2.example.com

  • peer1.org2.example.com

现在每个peer节点都已经掌握了完整的成员映射表。作为额外的福利, 我们也看到Org2的peer节点是如何在后续的gossip过程中了解到peer1.org1.example.com 这个节点的。

现在通道中的每个peer节点都已经知晓彼此的存在,无论在同一机构 还是不同机构,网络已经就绪了。

18、Fabric Gossip实验Step 12:更新Org2的锚节点

我们看到在一个通道中只需要一个锚节点就可以让网络正常工作。不过 还是推荐每个机构都设置一个锚节点。

1
2
3
4
5
6
7
8
docker exec \
-e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \
-e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \
-e CORE_PEER_LOCALMSPID="Org2MSP" \
-e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
cli peer channel update -o orderer.example.com:7050 --tls \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-c mychannel -f ./channel-artifacts/Org2MSPanchors.tx

我们现在可以看到通道成员视图的变化。

19、Fabric Gossip实验:从peer的配置中移除Gossip引导节点

Gossip的引导节点配置在 base/docker-compose-base.yaml中。注释掉 每个peer节点的CORE_PEER_GOSSIP_BOOTSTRAP 变量。从日志中的主要发现如下:

在step 3和4之后,我们可以看到Org1的两个peer节点在gossip层面不再通信。 在Step 5之后,Org2的两个节点也存在类似的情况。

当所有peer节点都加入mychannel通道后,我们观察到所有的peer节点都被 选举为主导节点。

  • peer0.org1.example.com

  • peer1.org1.example.com

  • peer0.org2.example.com

  • peer1.org2.example.com

这是由于在机构内部缺乏gossip沟通。不过这有什么问题吗? 让我们看看在更新锚节点(Step 11)之后会怎么样。

  • peer0.org1.example.com

  • peer1.org1.example.com

  • peer0.org2.example.com

  • peer1.org2.example.com

经过gossip过程,通道中所有的peer节点都掌握了正确的通道成员信息。 同时我们还观察到有些peer节点已经不再做主导节点了。

  • peer0.org1.example.com

  • peer0.org2.example.com

我们的观察表明,在没有配置peer节点的gossip引导节点时,一个机构 内的主导节点选举是失控的,因为每个peer都会选自己做主导节点。无论 如何这不是期望的情况,因为orderer需要和每个主导节点通信。当更新 锚节点配置后,所有的peer节点最终都掌握了通道成员信息,同时有些 节点也不再是主导节点,这是我们所期望的。因此最终的结果是可行的, 即使我们在开始时没有设置每个peer节点的gossip引导节点。


原文链接:Exploring Gossip when Starting a Fabric Network

汇智网翻译整理,转载请标明出处