Goosip协议
去中心化、容错和最终一致性的算法
信息达到同步的最优时间:log(N)。
功能:
节点发现
数据广播
gossip中有三种基本的操作:
- push - A节点将数据(key,value,version)及对应的版本号推送给B节点,B节点更新A中比自己新的数据
- pull - A仅将数据key,version推送给B,B将本地比A新的数据(Key,value,version)推送给A,A更新本地
- push/pull - 与pull类似,只是多了一步,A再将本地比B新的数据推送给B,B更新本地
说到底,gossip服务是处理消息的,每种类型的消息有不同的用途
消息类型
gossip服务使用不同模块处理不同类型的消息。消息类型原型在/protos/message.proto中定义。gossip中传播的消息以GossipMessage形式传递,具体的消息数据存放在GossipMessage中的Content成员中。
节点关系消息
与频道成员身份、关系和存续相关的消息类型。
AliveMessage - alive消息
MembershipRequest - 成员关系请求消息
MembershipResponse -成员关系应答消息
pull机制消息
pull进来的可以是以块数据为内容的消息,也可以是身份数据为内容的消息,下述4种消息中都有一个成员MsgType来表明这个消息中所携带的数据内容。从pull步骤上分为四种:
GossipHello - hello消息
DataDigest - 消息摘要
DataRequest - 摘要请求
DataUpdate - 摘要应答
state消息
和状态有关的消息。这里的状态指的是chain的数据状态,如一个结点所存储的块数据是否一致,可以说这里所谓的状态接近数据的意思。
StateInfo - 状态消息
DataMessage - 数据消息(block)
TransactionMessage - 交易数据;
辅助类消息
这类消息不承担具体传送传播数据的任务,而是辅助性的:
Empty - 空消息,用于结点间的Ping(来测试结点是否连通)和测试。
ConnEstablish - 用于gossip之间的握手,即任何时候一个peer想与另一个peer连接通信,都需要先发送这个消息以证明其身份。
gossip模块
主要功能
gossip部分接口
type Gossip interface {
// Send sends a message to remote peers
Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer)
// GetPeers returns the NetworkMembers considered alive
Peers() []discovery.NetworkMember
// PeersOfChannel returns the NetworkMembers considered alive
// and also subscribed to the channel given
PeersOfChannel(common.ChainID) []discovery.NetworkMember
// UpdateLedgerHeight updates the ledger height the peer
// publishes to other peers in the channel
UpdateLedgerHeight(height uint64, chainID common.ChainID)
// Gossip sends a message to other peers to the network
Gossip(msg *proto.GossipMessage)
// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
// If passThrough is false, the messages are processed by the gossip layer beforehand.
// If passThrough is true, the gossip layer doesn't intervene and the messages
// can be used to send a reply back to the sender
Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
// JoinChan makes the Gossip instance join a channel
JoinChan(joinMsg api.JoinChannelMessage, chainID common.ChainID)
// LeaveChan makes the Gossip instance leave a channel.
// It still disseminates stateInfo message, but doesn't participate
// in block pulling anymore, and can't return anymore a list of peers
// in the channel.
LeaveChan(chainID common.ChainID)
// Stop stops the gossip component
Stop()
}
主要模块
初始化和服务启动
消息广播
PeerA通过gossip协议广播消息,PeerB为其中一个消息接收节点。
代码应用框架
//初始化并加入通道‘A’
gossip = NewGossipInstance(15000, 1, 1000, isBoot)
gossip.JoinChan(&JoinChanMsg{}, common.ChainID("A"))
gossip.UpdateLedgerHeight(1, common.ChainID("A"))
acceptChan, _ := gossip.Accept(AcceptData, false) //AcceptData未消息选择器
//通过gossip的方式来发送消息
gossip.Gossip(msg *pb.GossipMessage)
注:gossip发送消息后,对端节点接收到消息,会把过滤的消息坊到accetpChan通道中。
gossip pull机制
消息类型
pull机制主要涉及四种消息类型
GossipHello - hello消息
DataDigest - 消息摘要
DataRequest - 摘要请求
DataUpdate - 摘要应答
具体pull的内容包括: 未定义消息,块消息,身份消息
初始化
pull机制的四个步骤
关键参数和函数
PullPeerNum //从PullPeerNum个节点pull数据
PullInterval //pull引擎每隔PullInterval开始一次pull同步
createBlockPuller: //创建pull.Mediator
- IngressDigFilter(大于本地高度的区块)//用来过滤digest,返回自己要同步数据的摘要
- IdExtractor: seqNumFromMsg //要同步数据的唯一标识
注: IDExtractor是个接口,区块数据用块高标识;身份数据用证书或者公钥相关数据表示