Skip to content

Latest commit

 

History

History
97 lines (52 loc) · 11.4 KB

File metadata and controls

97 lines (52 loc) · 11.4 KB

初窥P2P网络

P2P是“peer-to-peer”的缩写,peer在英语里一般是指同伴,同事的意思,因此P2P通常被称为对等网络,网络中的每个节点也被称为对等节点。在P2P网络中的每个节点地位是对等平权的,既能作为服务的请求者又可以为其它节点提供服务。通过P2P网络打破了互联网中传统的客户端/服务器结构,使每个节点具有了自由、平等通信的权利。

P2P技术的发展到目前为止经历了四个阶段:集中式,纯分布式,混合式和结构化网络,每一阶段都代表着一种网络模型,目前主流区块链平台大多采用混合式和结构化网络模型来构建。

当我们通过TLS可以构建两个节点间的安全通信后,只需要很简单的将这个模式扩展,就可以得到一个由多个节点两两建立安全通信的网络。

集中式网络

当肆无忌惮的建立一个由100个节点组成的网络时,就会发现一些之前没有预料到的问题,构建两个节点之间的连接时,需要彼此知道双方的地址,但是当新节点加入网络的时候节点数量不多还好处理,凭借记忆可以解决,但是当网络中存在大量的节点,已经很难全部记住节点地址的时候,又该如何知道网络中其他全部节点地址呢?

要知道在以太坊网络中,全节点的数量大约有8000个,这些节点分布在全球不同的地方,并且节点数量还随时增加或者减少,一个新节点加入网络想要知道网络中全量的节点信息是一件非常困难的事。

在生活中是如何解决这个问题的呢?

一般对于一个比较大的公司而言,新人入职以后都会发由一个通讯录来记录同事间的电话号码,或者邮件地址,当需要联系同事时,只需要查询这个通讯录即可。受到这种方式的启发,我们不再单纯地将节点简单两两连接,而是用一个节点作为索引服务器来充当通讯录的角色,采用这种方式来组建新的网络。

设置一个索引服务器,保存了所有节点的信息,当有新节点想要加入网络的时候,只需向索引服务器索要节点信息即可。

四个节点

这样,当有新节点想加入网络的时候,只需要把自己的信息告诉索引服务器,连接到索引服务器的其他节点就可以及时感知到有新节点加入到网络,并且可以获得新节点的信息,以便及时和新节点创建连接,尽快建立通信。除了允许索引服务器保存地址之外,网络中的其他节点还可以向索引服务器进行资源注册,索引服务器存储所有资源的共享信息,具体的共享资源还是存储在各个节点中。当用户需要查找具体的资源时,向索引服务器发出查询请求即可,当定位到资源所在节点后,资源的下载可以不依赖索引服务器。

当网络建立完成,开始了日常的运行,不断地有节点加入网络,也不断地有节点退出网络,整个体系看起来运行地十分完美。但是突然有一天,索引服务器出现了故障,停止了运行,看似有条不紊的节奏都被打乱了。

如此设计的网络结构问题也暴露了出来,如果索引服务器出现宕机故障,整个网络就会出现问题,至少新节点将无法加入网络。但是如果索引服务器是恶意的,它就可以决定谁可以加入网络,谁不能加入网络,显然和建立区块链对等平权节点这一理念相冲突,权力都集中到索引服务器是我们不想看到的结果。

这种网络结构太过依赖索引服务器的网络,不妨称之为集中式的P2P网络。

问题是由索引服务器权力集中引起,在这个基础上进一步进行改造,首先需要解决索引服务器中心化的问题,将权力下放到每一个节点。

纯分布式网络

我们来回想一下当时引入索引服务器的目的?是因为节点过多,需要索引服务器来保存全量的节点信息,并以此来获得整个网络的节点信息。

如果某天在工作时,丢失了通讯录,而又因工作需要必须找到一个同事A,此时需要怎么办呢?当然是询问和自己熟悉的同事B是否知道A的电话号码,这个时候如果同事B知道问题就解决了。如果同事B不知道,但是B突然想到同事C可能知道,于是好心地帮你询问了一下C,进而通过同事间的热心帮助终于联系到了同事A。

好像问题并不严重,通信录也并不是说丢失后就让人束手无策,只要认识的同事足够多问题也没有那么大,可以很快地询问认识的同事获得答案。虽然同事间如此频繁地询问并不是一个好习惯,但是计算机却可以不厌其烦地回答你的每一个询问。

节点间不需要全量的连接,每个节点只要随机保持和几个节点连接即可,而每个节点都这样,只要运气不是太差,整个网络也不会产生分区。

四个节点

在连接12,15,16三个节点的时候,都只有一条连接,当2号节点到12号节点的网络连接故障之后,即使15和16号节点的网络是正常的,也无法连接到网络。针对这种情况,只需要规定一个节点至少连接几个节点即可保证网络的健壮。

当我们想把消息从1号节点传播到16号节点的时候,可以看到通过1->2->15->16这个路径就可以把消息传递过去,每个节点只需要把自己接收到的消息告诉和自己建立连接的节点即可。它采用泛洪式请求(Flooding Request),用户的请求通过相连接的节点传递,这些节点如果不能满足请求,则想自己相连的其它节点广播,直到请求得到响应为止。

在Hyperledger Fabric中,节点间同步数据采用的是Gossip协议,Gossip协议的过程就是这样,当节点因为异常缺少账本数据时,可以通过Gossip协议从邻近的节点获得账本数据,保证集群中节点账本的一致性。

Gossip协议

Gossip是流言的意思,启发于现实社会中流言蜚语或者病毒的传播方式。Gossip协议也被称为反熵(Anti-entropy)。熵是物理学中的一个概念,代表杂乱无序,错乱,而反熵则是在杂乱中寻求一致,生动的体现了Gossip协议在于相邻节点杂乱的通信中最终状态达成一致的特点。

协议流程

  • 节点A周期性的选择相邻的K个节点,并且向这K个节点发送自身存储的数据;
  • K个节点接收到A发送过来的数据后,发现自身没有则存储下来,如果有则丢掉,并且重复节点A的过程。

gossip

在节点A向节点K发送数据的时候有三种方式;

  • push模式,节点A将数据(key,version,value)推送给K,K更新version比自己新的数据。
  • pull模式,节点A将数据(key,version)推送给K,K将本地version比A新的数据推送给A。
  • push/pull模式,先采用push模式更新K,然后采用pull模式更新A。

push模式需要通信一次,pull模式需要两次,pull/push模式需要通信三次,而从最终一致性的收敛速度也与通信次数成正比。将消息传播到所有节点的时间复杂度为log(n)。

分布式网络中,没有一种完美的解决方案,Gossip 协议跟其他协议一样,也有一些不可避免的缺陷,主要是两点消息延迟和消息冗余。

  • 消息的延迟,由于 Gossip 协议中,节点只会随机向少数几个节点发送消息,消息最终是通过多个轮次的散播而到达全网的,因此使用 Gossip 协议会造成不可避免的消息延迟。不适合用在对实时性要求较高的场景。

  • 消息冗余,Gossip 协议规定,节点会定期随机选择周围节点发送消息,而收到消息的节点也会重复该步骤,因此就不可避免地存在消息重复发送给同一节点的情况,造成了消息的冗余,同时也增加了收到消息的节点的处理压力。而且,由于是定期发送,即使收到了消息的节点还是会反复收到重复消息,加重了消息的冗余。

采用Gossip协议以后,我们想要确定性地把一个消息传输给一个节点就变得不可能了。比如想把消息从1号节点确定地传输到16号节点,即使16号节点不在网络中了也可以明确地给我一个传输失败的反馈。

1号节点能做的只能是把想传播的消息告诉相邻的节点,然后期望是能被16号节点接收,如果失败了,也需要等待一会以期待别的节点把消息广播给1号节点。

导致这个问题最根本的原因就是Gossip协议中,无法计算节点间的距离,每个节点都不知道离目标节点到底还有多远,只能通过这样随机性的方法期待结果最终收敛。

这种网络,称之为纯分布式网络。

混合式网络

纯分布式网络架构的问题是每个节点都只知道自己相邻的节点,无法知道整个网络的状况,通过泛洪的方式发起请求,发送者需要等待网络中的节点层层转发最后才能得到响应,对整个过程缺乏一定的确定性。

这个时候我们可以结合之前的两种网络组织形式,适当的集中权力,但是又避免完全的依赖特定节点。

四个节点

其中的绿色节点可以称为超级节点,每个普通节点都需要和超级节点连接才能和整个网络通信,超级节点作为普通节点的代理人。这样当有多个超级节点的时候,即使少量的超级节点限制普通节点加入网络或者出现故障,也不会影响网络的正常运行。

网络中存在多个超级节点组成分布式网络,而每个超级节点则与多个普通节点组成局部的集中式网络。一个新的普通节点加入网络需要先选择一个超级节点通信,该超级节点再推送其他超级节点列表给新加入的节点,加入节点再根据超级节点列表中的状态选择加入哪个超级节点作为父节点。这种结构限制了泛洪广播的范围,避免了大规模的泛洪问题。

当我们需要明确地知道消息是否传达到了目标节点的时候,只要发送给超级节点,超级节点帮我们把消息传递到目标节点的超级节点,最后发给目标节点,其中的任意一环出现问题,我们都能及时收到答复,整个过程是确定的。比如,每一步等待结果的超时时间是5秒,发送者发送消息以后,最多等15秒就可以知道是否有响应,而不用像Gossip协议那样等待一个“maybe”。

在实际应用中,混合式结构是相对灵活且比较有效的网络架构,实现也相对容易。

这种方式在中心化和分布式之间进行了权衡,普通节点与网络之间只有一条连接,连接依然脆弱,超级节点的数量也有限,我们理想化的P2P网络它只能实现了一半。