本文基于 Fabric v2.0.1
一、Gossip 简介
参见 Gossip 协议
二、Gossip 在 Fabric 中的应用
Fabric 使用 Gossip 作为 Peer 间的数据共享网络。在其上划分 Channel 进行消息交换,主要用于 Fabric 网络成员发现、组织内区块数据交换、私有数据的分发、及同步 Peer Channel 当前状态等。
Peer 间建立连接时握手过程会交换彼此的证书、并使用对方的证书进行身份认证。
Gossip 中交换的消息类型见 message.proto
oneof content {
// Membership
AliveMessage alive_msg = 5;
MembershipRequest mem_req = 6;
MembershipResponse mem_res = 7;
// Contains a ledger block
DataMessage data_msg = 8;
// Used for push&pull
GossipHello hello = 9;
DataDigest data_dig = 10;
DataRequest data_req = 11;
DataUpdate data_update = 12;
// Empty message, used for pinging
Empty empty = 13;
// ConnEstablish, used for establishing a connection
ConnEstablish conn = 14;
// Used for relaying information
// about state
StateInfo state_info = 15;
// Used for sending sets of StateInfo messages
StateInfoSnapshot state_snapshot = 16;
// Used for asking for StateInfoSnapshots
StateInfoPullRequest state_info_pull_req = 17;
// Used to ask from a remote peer a set of blocks
RemoteStateRequest state_request = 18;
// Used to send a set of blocks to a remote peer
RemoteStateResponse state_response = 19;
// Used to indicate intent of peer to become leader
LeadershipMessage leadership_msg = 20;
// Used to learn of a peer's certificate
PeerIdentity peer_identity = 21;
Acknowledgement ack = 22;
// Used to request private data
RemotePvtDataRequest privateReq = 23;
// Used to respond to private data requests
RemotePvtDataResponse privateRes = 24;
// Encapsulates private data used to distribute
// private rwset after the endorsement
PrivateDataMessage private_data = 25;
}
2.1 Fabric Gossip Components
按包结构划分 Fabric Gossip 分为以下组件:
- gossip/comm :负责 Peer 节点间的 RPC 通信
- gossip/discovery :Fabric 网络成员发现、管理
- gossip/election :组织内 Peer 节点选举
- gossip/gossip :Gossip 协议实现
- gossip/identity :节点身份标识管理
- gossip/privdata :私有数据处理部分
- gossip/service :封装 Gossip 功能对位不提供服务
- gossip/state :节点参与的 Channel 状态管理、区块数据、私有数据与本地账本的对接
Fabric Gossip 组件图如下:
图片使用 plantuml 生成,脚本见1
2.2 从 Orderer 接收区块数据
Fabric 中在同一组织内是由担任 Leader
角色的 Gossip Node
负责从 Orderer 接收完成排序的区块,分发给其他 Follower
。需要注意 Leader
是 Pre Channel 的每个 Channel 有自己的 Leader
。
Leader
有两种方式产生,通过设置 core.yaml 相应配置如下 :
- 静态指定(静态方式下, 都设置为 false 即为
Follower
)peer: gossip: useLeaderElection: false orgLeader: true
- 动态选举产生
peer: gossip: useLeaderElection: true orgLeader: false
Leader
从 Orderer 接收区块过程如下图所示:
图片使用 plantuml 生成,脚本见1
在 InitializeChannel
阶段初始化 deliveryService
当前节点成为 Leader
时连接 Orderer 节点接收区块数据。接收到新区块时完成基本校验后调用 GossipService
的 AddPayload
方法,在 GossipService
内部将区块数据提交给本 Channel 的 State 并通过 Gossip
接口向 Follower
传播。
2.3 区块数据的传播
Follower
有三个途径接收区块数据:
- Gossip / Forward 选中
在消息单线传播时被随机选中,初始的 Leader Gossip 或后续的 Follower Forward时被选中 - 通过
BlocksPuller
主动从其他节点获取
BlocksPuller
会记录一定时间内的 Gossip 网络中的区块消息并与其他节点交换当前拥有的区块ID,需要时从其他节点获取 - 通过
State
从其他节点同步
Chain State
在进行初始化时会根据配置项(peer.gossip.state.enabled
),决定是否启动 Gossip 网络的Anti Entropy
模式,启用的情况下定时从其他节点同步区块高度。
前两种接收途径如下图蓝色路径所示:
图片使用 plantuml 生成,脚本见1
2.4 私有数据的分发
Fabric 中私有数据不通过 Orderer 节点,在背书阶段通过 Gossip 网络进行分发。分发的策略由 Chaincode approve
时指定的 CollectionConfig 来决定。
部分流程如下图所示:
图片使用 plantuml 生成,脚本见1
图中只表示了私有数据的分发过程,不包含主动获取部分,在完成区块的验证之后,会在提交到账本处理前会从 背书节点 获取本地没有的私有数据。另外如果启用了 reconciler
(通过配置项 peer.gossip.pvtData.reconciliationEnabled
配置)会定时查询 本地账本 确实的私有数据从其他 CollectionConfig
允许的节点获取私有数据放入 本地账本 中。