libp2p流将被压缩,以节省IPFS文件交换带宽

2020-10-30 16:11:59

今天,我们很高兴分享我们决定探索libp2p流压缩的故事,并最终在执行IPFS文件交换时将带宽使用减少了多达75%。

  今天,我们很高兴分享我们决定探索libp2p流压缩的故事,并最终在执行IPFS文件交换时将带宽使用减少了多达75%。这项工作是由ResNetLab领导的旨在提高IPFS以及更广泛的P2P网络中文件共享速度的更广泛计划的一部分。

  几个月前,我们面临一个新项目的挑战,该项目的主要目标是设计,原型设计,测量和评估在P2P网络中进行文件传输的方式,该方式与使用原始TCP协议进行文件交换一样快甚至更快。点对点连接(提示:受益于来自多个端点的流)。在对现有技术进行全面分析之后,我们开始设计并实施多个RFC,以期加快IPFS堆栈不同级别的传输速度。正在酝酿中的想法和原型很多,今天我们分享一个我们非常兴奋的想法。


  我们可以从当今用于文件分发的最广泛使用的协议中学到什么

  压缩已经是提高Web 2.0性能的一种重要且便捷的方法。对于某些文件,我们可以减少多达70%的大小,并相应地提高带宽要求。网络中的压缩发生在三个不同的级别:

  •首先,某些文件格式在应用程序级别使用特定的优化方法进行压缩,例如特定的视频和图像压缩算法。

  •然后,常规加密可以在HTTP级别发生(传输的资源端到端压缩)。

  •最后,可以在HTTP连接的两个节点之间的连接级别定义压缩。

  迄今为止,libp2p尚未在IPFS中以任何方式使用压缩来交换文件,那么为什么不模仿HTTP并使用压缩来提高IPFS文件交换的速度呢?


从Dropbox Broccoli汲取灵感

  激励我们探索压缩的另一大灵感是Dropbox。Dropbox每天都会在数百万个桌面客户端之间同步PB级数据,并且他们最近发布了他们围绕压缩所做的一些工作。以减少客户端向后端发送数据时的延迟和带宽要求。它们将中值延迟降低了30%以上,并且在线上发送的数据量减少了相同数量。通过使用在Rust内部构建的经过修改的Brotli压缩和代号为Broccoli(brot-cat-li)的Brotli压缩,可以以Google的Brotli实施速度的三倍压缩数据,从而达到这一结果。他们将花椰菜嵌入到块同步协议中,该协议由两个子协议组成:一个用于同步文件元数据(例如文件名和大小),另一个用于同步块,这些块是文件的最大4兆字节(MiB)对齐的块。第一部分,元数据同步协议,为块同步引擎提供一个接口,以了解需要上载或下载哪些块才能完成同步过程并达到同步完成状态。

  Dropbox的工作明确强调了压缩在文件共享系统中可能产生的影响,以及在算法级别(使用有效压缩算法)和协议级别(将协议内的算法充分利用)探索压缩的重要性。压缩)。看了第一个HTTP和现在的Dropbox的示例之后,我们肯定必须开始探索压缩。


评估如何在Bitswap(IPFS的标准块交换)中集成压缩(流与消息)

  IPFS当前使用的数据交换子系统是Bitswap,因此我们选择从那里开始评估压缩。HTTP中使用了两种相关的压缩算法:最常用的一种是gzip,另一种是新的挑战者br。然后,HTTP中使用了两种主要的压缩策略:主体压缩和使用诸如HPACK之类的算法压缩标头。

  遵循类似的方法,我们在Bitswap中实现了三种不同的压缩策略,以评估实现更好性能改进的压缩策略:

  •块压缩:Bitswap中的文件以块的形式交换。文件由以DAG结构组织的几个块组成,每个块的大小限制为256KB (请查看这些ProtoSchool教程以了解更多有关此内容)。在这种压缩方法中,我们先压缩块,然后再将块包含在消息中并通过链接传输它们。这可以认为等同于在HTTP中压缩主体。

  •完整的消息压缩:在这种压缩策略中,我们不仅在压缩消息之前还压缩了每条消息,然后再发送它,即相当于在HTTP中压缩标头+正文。

  •流压缩:此方法在流级别使用压缩,因此使用流包装器方便地压缩在传输级别进入节点的流写入器的每个字节。这实际上是Gzip HTTP处理程序的Golang实现所遵循的方法。


1030-2-1.png


  为了方便起见,我们使用Gzip作为上述策略的压缩算法。许多人都报道了brotli相对于Gzip的压缩优势,但是对于Golang缺乏稳定的brotli实施,使我们最初选择Gzip作为原型的压缩候选对象。

  我们在文件共享Testground测试平台上针对上述策略的实施情况运行了评估计划,得出了以下有趣的结果:

  •使用块压缩策略实现的压缩率明显低于使用完整消息策略或流压缩的压缩率。如果我们交换随机文件,即没有很多冗余,则尤其如此。即使在交换随机文件时,这也很合理:压缩器在压缩完整消息(或流)时能够找到冗余结构,而随机文件的块通常根本没有冗余。

  •与使用流压缩相比,使用块压缩和完整消息压缩的计算开销和文件共享延迟要高得多。这是另一个预期结果:在流压缩中,节点可以直接“吐”数据到传输层,因为它是通过流包装“即时”压缩的,在块和完整消息压缩策略中,节点拥有在将第一个字节发送到传输层之前执行适当的压缩。

  从这些实现的评估中学到的经验教训?与P2P网络协议中的其他压缩策略相比,在流级别应用压缩可以导致显着的性能改进和带宽的更有效利用。在某些情况下,根据压缩算法和文件格式等因素,带宽节省最多可达到50%!这就是我们的压缩RFC嵌入libp2p的方式。


将原型放到libp2p中

  在我们的第一个压缩原型中导致最佳结果的压缩策略不是在协议级别,而是在传输级别。这意味着,如果我们在底层传输层中实现嵌入式压缩,那么不仅文件共享协议可以从压缩中受益,而且利用该相同传输层的其他任何P2P协议都有可能受益。

  Bitswap使用libp2p作为其基础P2P传输,就像Bitswap一样,已经有许多使用libp2p作为其传输层的应用程序和协议可以直接从压缩的使用中受益,而无需对其协议和应用程序进行任何更改(存在Go,JavaScript,Rust,Python,JVM,C ++甚至Nim中的libp2p)。

  这就是我们最终在libp2p堆栈中添加新的压缩层的方式。我们已经将压缩实现为流多路复用器和安全层之间的新传输升级程序。因此,与其单独压缩每种协议的流(就像我们在Bitswap流策略中所做的那样),不如将多路复用器中的所有数据方便地压缩,在安全层加密,然后通过基础传输进行发送。

1030-2-2.png

  那为什么要压缩呢?与单个协议流或安全通道的输出相比,从多路复用器接收的数据流潜在地显示出更大的压缩潜力,因此这是我们做出放置决定的原因。

  压缩已被实现为传输升级程序,这一事实使得它无论如何都不会成为重大变化。libp2p节点当前协商安全协议以在其连接中使用并回退到两者均支持的安全协议的方式相同,或者使用未加密的连接,压缩时也是如此。Libp2p节点将协商要使用的压缩算法,如果其中一个不支持压缩,则它们会简单地退回到未压缩的连接。

  因此,可以无缝升级应用程序以使用压缩连接。它只需要升级基础libp2p节点,并添加以下优美的代码行:


1030-2-3.png


  初步的压缩实现尚未在上游的go-libp2p上实现。它目前存在于我们一直用来测试实现的一组分叉存储库中。但是,如果您想立即开始在libp2p中使用压缩,请查看以下存储库,该存储库引导您完成一系列使用压缩的示例,并指向您需要链接以在应用程序中开始使用压缩的所有分支版本:https://github.com/adlrocha/go-libp2p-compression-examples


性能提升

  那么,使用压缩技术可以期待什么样的改进呢?让我们开始讨论使用压缩可以带来的带宽节省。在此测试中,我们交换了启用和禁用压缩的这些“超棒IPFS”数据集中的数据集,并测量了节点的总带宽使用量。在所有实验中,我们都对底层gzip算法使用DefaultCompression级别的配置。


1030-2-4.png

1030-2-5.png


1030-2-6.png


  我们可以看到,根据数据集,我们最多可以节省所需带宽的75%。从测试中我们得出两个有趣的结论:

  1、大型数据集由于在数据中发现冗余的可能性较高,因此使用压缩会更多地受益;

  2、压缩器和基础数据交换的性质决定了压缩率,因此可以节省潜在的带宽。Gzip在基于文本的数据上具有非常好的性能,但是在压缩图像时表现出非常糟糕的行为。因此,只要将正确的压缩算法用于交换的数据,压缩通常可以节省带宽。

  这些节省的带宽对于从IPFS提取完整数据集的时间意味着什么?我们从上述列表中选择了一些可以节省带宽的数据集,并在Testground上运行了相同的文件交换,以模拟节点之间链接的不同带宽和延迟配置(以不同国家的平均连接速度为参考)。结果显示在下表中:


1030-2-7.png


  考虑到从带宽节省中获得的结果,并比较压缩后和无压缩时的取回时间,这会让人有些失望。对于大型数据集,压缩开始显示出明显的改善,但仍然可以认为它们可以忽略不计(低于1%)。对于IPFS用户而言,这意味着使用压缩时,葡萄牙的用户在通过IPFS下载textfiles.com数据集(1658MB)时仅节省了半分钟,而在传输未压缩数据时总共要花费4.5小时左右。我们相信,通过继续微调压缩级别可以取得更好的结果。此外,压缩是累积性的:传输的数据越多,压缩的机会就越大-您的日常使用可能会显示出更有趣的结果。

  我们用于传输的压缩算法实现是Golang的标准实现(compress / gzip)。根据以上结果,我们开始怀疑我们使用的Gzip实现是否对于我们的用例而言不够高效,因此从带宽节省中获得的所有时间都在压缩过程中丢失了。然后,我们决定使用据说更为高效的gzip golang实现和全新的go-libp2p brotli压缩传输来实现gzip传输,并比较了两种实现的计算开销和带宽节省:

1030-2-8.png

  实验结果表明,使用Gzip算法的替代实现方式会导致带宽节省稍微差一些,但是压缩的计算开销有了显着改善。甚至更多,我们看到使用替代(据称更好)的压缩算法如何在节省带宽和压缩时间方面取得改进。这说明了根据要改进的指标为任务选择合适的压缩机的重要性。


结论

  通过libp2p中压缩的实现,我们获得了一组有趣的见解。我们已经看到压缩如何可以显着提高文件共享的带宽,以及可能在libp2p上构建的许多其他协议。这些带宽节省的价值必须在Bitswap运行的整个框架(即P2P网络)中考虑。在这些网络中,用户“捐赠”其带宽资源以向其他用户提供内容。也就是说,对避免上载带宽饱和的任何贡献都具有重大价值。我们的结果表明,即使是大约1GB的适度文件交换(这在现代应用程序中也很常见)也可以缩小约50%-大大减少了!

  但是,节省这些带宽并非免费的。压缩的使用增加了计算开销,在某些情况下,最终可能会消除通过减少交换的数据量而实现的所有节省。此外,交换的基础数据可能会极大地影响压缩性能(甚至导致更高的带宽和更差的性能)。


未来工作并邀请参加研究

  如我们的实验所示,根据要优化的度量标准和要交换的数据类型,明智地选择要使用的压缩算法至关重要。相同压缩算法的不同实现方式可能导致性能和压缩率方面的显着差异。

  从这里开始,有很多关于未来工作的思路以及您可以为这项工作做出贡献并以此为基础的方式:

  •探索使用更有效的压缩算法。如上所示,Golang的Gzip标准实现在野外并不是最有效的计算,这解释了带宽节省结果与实际获取测试改进时间之间的巨大差异。改善此问题的一个简单下一步就是测试其他压缩方法,例如使用霍夫曼表(而不是完整的gzip)来最大程度地减少计算开销但节省一些带宽。或测试更复杂的压缩算法和协议,例如采用Broccoli的Dropbox所采用的方法(我们已经开始通过新的传输方式探索这种方法,请毫不犹豫地加入我们的工作)。

  •微调压缩算法。在我们所有的测试中,我们一直在使用具有默认压缩级别的Gzip和具有自动窗口且质量级别为2的Brotli。进一步探索这些算法的最佳配置可以在计算开销和压缩率之间取得正确的平衡。以实现进一步的改进(请参阅此参考资料以开始探索)。甚至,我们可以根据应用程序和交换的数据设计这些算法的动态配置。

  •探索协商协议的实现,以允许libp2p节点就要使用的压缩(在流级别或传输级别)达成一致,以根据要交换的数据和上层协议进行使用。通过这种方式,根据应用程序要执行的数据交换,它可以选择正确的压缩算法与另一端一起使用,并在什么级别上使用(只要它们两者都支持)。

  可能还有许多其他事情我们可能会遗漏,您可以提出!如果您想为这项工作做出贡献,则可以开始为libp2p实现自己的压缩传输,以查看是否能够在带宽节省和获取时间方面取得进一步的改进(考虑到当前的gzip实现,我告诉您)能够这样做)。向libp2p添加新的压缩算法很容易,您只需实现libp2p压缩接口,并将libp2p连接的读取器和写入器包装到压缩的算法接口中即可。阅读gzip和brotli的代码传输实现,以了解将自己的压缩添加到libp2p是多么简单。您还可以签出西兰花并为正在进行的西兰花运输实施工作做出贡献。您可以在我们的Testground测试平台上测试实现,将压缩算法注入IPFS节点并分析节点之间的链接。

  请毫不犹豫地与我们联系,或提出一个问题来推动我们加快P2P网络中文件共享的速度。

  在下一个之前,我们祝您有美好的一天!

ResNetLab


最新推荐