Libp2p学习
参考资料:libp2p-specifications : https://github.com/libp2p/specs
持续更新ing
1. 介绍
Libp2p的实现目标是:
- 支持各种各样的传输方式:
- 传输:TCP,UDP,SCTP,UDP,uTP,QUIC,SSH,etc.
- 安全传输:TLS,DTLS,CurveCP,SSH
- 有效使用sockets(连接重用)
- 允许端点之间的交流可以在一个socket上复用(避免过多的握手)
- 允许端点之间通过一个协商过程使用多协议以及各自的版本
- 向后兼容
- 在现在的系统中可以运行
- 充分使用当前网络技术的能力
- 实现NAT转换
- 实现连接中继
- 实现加密通道
- 充分使用基础传输(例如原生的流复用等)
传统的7层OSI模型表征不适合libp2p。Libp2p根据协议的角色(功能)进行划分。不同的lip2p协议可以具有相同的功能,例如,bootstrap lists,mDNS,DHT discovery,PEX都进行节点发现,但他们可以同时存在甚至协同工作。而在OSI中,每一层通常都只有一个协议。
2. 基础
libp2p使用了multiaddr,一个自描述的地址形式,可以理解为不同协议不同地址类型的一个封装。这使得libp2p可以不透明的处理系统中的所有地址,支持网络层中的各种传输协议。
libp2p的协议是多个协议的集合。为了节约资源并使连接更容易,libp2p可以通过一个端口执行所有操作,它可以通过点对点连接复用其众多协议。这种多路复用适用于可信赖的流连接或者不可信赖的数据报。libp2p的目标是变得更加模块化和灵活,以适应于各种应用场景。
libp2p中的交流可以是加密、签名或者是明文。它使用了TLS这样的加密模型,但并不是整个TLS。它只使用了TLS模型中用于加密的最小的一部分。
由于对称NAT,容器以及虚拟机NAT和其他的不能绕过的NAT,libp2p必须使用中继通信来建立一个全连接图。中继应该是可选的,能够被用户关闭。连接中继应该作为transport实现,以对上层透明。
libp2p中支持结构化、非结构化、混合以及中心化的网络拓扑结构。它也解决了网络中资源的发现问题。高效的消息传输协议可以提供低延迟的传输或更大更复杂的网络拓扑结构。libp2p试图利用Multicast和PubSub一起来满足该需求。libp2p也支持命名。
3. 架构
libp2p根据Unix哲学来设计,创建了易于理解和测试的小组件。这些组件应当可以被交换以适用于不同的技术或者场景,同时也应当能够随着时间来对它们进行不断的升级与更新。
虽然不同的节点可能会支持不同的协议,但任何一个节点都可以充当dialer或者listener。建立的连接可以被连接两端的节点重用,消除了客户端和服务端之间的差别。
libp2p的接口将许多节点之间通信所必需的子系统连接起来。这些子系统的主要工作区域有:
- 节点路由:决定哪些节点用于路由特定的消息。这个路由的过程可以是递归、迭代的完成的,也可以是以广播、组播的形式完成。
- Swarm:处理libp2p中所有和"开启一个流"相关的事情,包括协议复用、流复用、NAT转换和连接中继。
- 分布式记录存储:用于存储和分发记录的系统。记录是其他系统用于发信号、建立链接、宣布节点或内容等等的小条目。在更广泛的互联网中,它们与DNS的作用类似。
- 发现:找到网络中的其他节点
系统架构如下图所示:
┌─────────────────────────────────────────────────────────────────────────────────┐
│ libp2p │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐┌─────────────────┐┌──────────────────────────┐┌───────────────┐
│ Peer Routing ││ Swarm ││ Distributed Record Store ││ Discovery │
└─────────────────┘└─────────────────┘└──────────────────────────┘└───────────────┘
3.1 节点路由
节点路由子系统暴露出一些接口,用来确定一条消息应该被路由到DHT中的哪些节点。它接受一个key,且返回一个或多个PeerInfo对象。以下是两个节点路由子系统的实例,第一个基于Kademlia DHT,第二个基于mDNS。然而,只要实现了同样的功能和接口,其他的节点路由机制也可以被实现。
kad-routing实现了Kademlia路由表,每个节点都保存着一个k桶集合,每个k桶中都包含着几个来自网络中其他节点的PeerInfo对象。
mDNS-routing使用mDNS探测来识别局域网节点是否有指定的key或者他们是否在线。
3.2 Swarm
流复用器必须实现指定的接口:interface-stream-muxer
协议复用是在应用层实现的,而不是传统的端口层(不同的服务/协议监听不同的端口)。这使得我们能够在一个socket上复用多个协议,从而节省了对多个端口进行NAT转换的消耗。协议复用是通过multistream
完成的,multistream
是一个协议,它使用multicodec
来协调不同类型的流或协议。
关于中继:
由于NAT,反向代理,防火墙或不支持相同的传输(例如,go-ipfs与browser-ipfs),中继在某些情况下是很有必要的。中继连接使用起来和常规的连接差不多,也同样是端对端加密的。中继线路既是隧道传输,也是Swarm协议。传输是建立与接受连接的工具,swarm协议是中继连接的工具。
3.3 分布式记录存储
此部分原文中无内容,我也暂时懒得去看。
3.4 发现
mDNS-discovery:
mDNS-discovery是一种局域网上使用mDNS的发现协议。它发出mDNS信标来探测是否有更多可获得的节点。由于低延迟的特性,局域网节点是非常适用p2p协议的。
mDNS-discovery是一个独立的协议,不依赖于任何其它的libp2p协议。mDNS-discovery能够发现局域网中可用的节点,而不需要依赖于其它的基础组件。在内网、不与Internet骨干网连接的网络、暂时失去连接的网络中,这样做是非常有用的。
mDNS-discovery可以按照服务配置(例如,仅仅发现加入特定协议的节点,比如ipfs),也支持私有网络(发现属于同一个私有网络的节点)。
libp2p开发者正在探索让mDNS-discovery信标加密的方法(这样可以让局域网中的其他节点无法识别正在使用的服务),尽管mDNS的性质总会暴露出本地IP地址。
random-walk:
Random-walk是DHT(以及其它有路由表的协议)的发现协议。它会进行随机DHT查询,以便快速了解到大量的节点。这使得DHT(或其他协议)收敛的更快,其代价是一开始时的小负载。
boostrap-list:
Bootstrap-List是一种发现协议,它使用本地存储来缓存网络中可用的、高度稳定且可信的节点地址。这允许协议发现网络的其余部分。这本质上和DNS引导自身的方式基本相同。
这个列表应该被存储到长期本地存储中,无论这对本地节点意味着什么(例如,对磁盘而言)。该协议可以发送一个硬编码的默认列表,也可以附带标准代码分发(如DNS,好吧这一段可以看看原文?翻译不出来…)。在大多数情况下(包括IPFS),bootstrap列表应该是用户可配置的,因为用户可能希望建立单独的网络,或者信任特定的节点。
4. 接口
libp2p是多个协议的集合,它们共同协作,提供了可以与其它网络可寻址进程通信的通用实体接口。实现方式为:将当前存在的协议和实现填充进一组确定的接口中:Peer Routing,Discovery,Stream Muxing,Transports,Connections等。
**libp2p: **libp2p是顶层模块,它为其它构成libp2p实例的模块提供接口,接口中必须包括对其它节点的拨号(dial)、对所有我们想要支持的模块的插拔。
**Peer Routing: ** 该模块为一个libp2p节点提供了找到另一个节点的PeerInfo的方式,这样它就可以向另一个节点发起拨号。最基本的功能为:一个Peer Routing模块应该有这样一个接口:输入一个"key",返回一个PeerInfo的集合。
Peer Discovery: 该模块应该返回PeerInfo对象,因为它找到了一些新的节点,这些节点应该被我们的Peer Routing模块考虑进去。
Swarm、Transport、Connection、Stream Muxing、Distributed Record Store略。
5. 性质
5.1 通信模块-Streams
网络层处理所有关于连接到一个节点的问题,并且暴漏出简单的双向流。用户既可以打开一个新的流(NewStream),也可以注册一个流处理器(SetStreamHandler)。之后用户可以*的实现他想要的任何消息传递协议。这使得构造一个p2p协议更简单,因为连接、多传输支持、流控制等的复杂度得到了处理。