我们如何将IPFS内容发布速度提升10倍

Hacker News Top 工具

摘要

Optimistic Provide通过早期记录存储、早期遍历终止和后台重试等技术,将IPFS内容发布时间从超过13秒缩短至不到1秒。该优化已在Kubo 0.39.0中发布,显著提升了IPFS上的实时内容发布。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/01 17:00

# 乐观提供:我们如何将 IPFS 内容发布速度提升 10 倍 来源:https://probelab.io/blog/optimistic-provide/ ## 引言 传统上,在分布式哈希表(DHT)中发布内容一直是一项缓慢的操作,尤其是在以下情况下:i)网络规模庞大,ii)参与网络的节点频繁切换。IPFS 的 Amino DHT 也不例外,它同时满足这两个条件。ProbeLab 团队多年前就通过广泛的测量(https://dl.acm.org/doi/abs/10.1145/3544216.3544232)发现了这一问题,并提出了一项优化方案,该方案已被证明能够提升性能,即将内容发布时间降低超过一个数量级,同时将网络开销减少 40%。 这项优化名为 **乐观提供**(Optimistic Provide),最近刚刚作为 IPFS 的 Kubo 0.39.0 版本的默认功能发布!该研究发表于 IEEE INFOCOM 2024(https://ieeexplore.ieee.org/abstract/document/10621404),我们建议读者参阅该论文以获取更详细但更密集的细节。 在这篇博文中,我们将概述我们的团队提出的技术,同时提供基本的技术细节,当然还有证明我们最初关于其有效性的主张正确性的结果。 > 衷心感谢 IPShipyard 团队(https://ipshipyard.com/)在此过程中的支持,以及最终推动该功能进入生产环境的努力。根据结果来看,这一切努力都是值得的。 ## 摘要 乐观提供背后的基本思想如下: 1. 在“遍历”DHT 时,立即将记录存储给那些很可能是全网 20 个最接近节点的对等节点。 2. 当发现的最接近 20 个节点的集合很可能构成全网最接近节点时,立即终止 DHT 遍历。 3. 在大多数(并非全部)PUT RPC 成功后,将控制权返回给用户,并在后台继续处理剩余的请求。 第 1 点和第 2 点需要了解网络的总规模,我们通过一种轻量级的估计方法获得,该方法利用路由表刷新机制,不产生任何额外的网络开销。 乐观提供显著降低了上传延迟,从超过 13 秒(通常接近 20 秒)降至不到 1 秒,为 IPFS 的性能带来了巨大的价值和影响。 实际意义:内容发布者现在可以几乎实时地发布内容,即在内容推送到网络后大约 1 秒内完成。与之前的 > 10 秒相比,这是一个重大改进,因为开发者、用户和应用程序提供商可以实时地进行迭代和调试。 ## 传统提供操作 要理解这些优化是如何工作的,我们首先需要了解传统的“提供”操作。在基于 Kademlia 的分布式哈希表(DHT)中,例如 IPFS 使用的 Amino 网络(https://blog.ipfs.tech/2023-09-amino-refactoring/),存储一条记录需要找到与该数据标识符最接近的 k 个对等节点,其中 k 在 Amino DHT 中设置为 20(https://github.com/libp2p/specs/blob/6b6203ee6f62938ce67efdb33498173f475851c0/kad-dht/README.md)。在这里,“接近”并非由地理距离定义,而是通过 XOR 距离度量来确定的。该度量通过计算对等节点的唯一 PeerID 与数据的内容标识符(CID)之间的按位异或运算,来衡量两者之间的距离。 从一个硬编码的引导节点集合开始,一个节点会填充自己的本地路由表。找到这 20 个最接近对等节点的过程被称为 **DHT 遍历**(DHT Walk)。这是一个迭代搜索过程:节点查询自己的本地路由表,找到最接近的已知节点,并向它们询问更接近的候选节点。这个循环会一直持续,直到发起节点收到它发现的最接近的 3 个节点的成功响应。一旦遍历终止,**后续阶段**(Follow-Up phase)开始:发起节点将提供者记录推送给所有这 20 个最接近的节点,以确保即使某些节点离开网络,数据仍然可用。 因此,总结一下:一个提供过程包含两个阶段: 1. **DHT 遍历**:找到全网最接近的 20 个节点。 2. **后续阶段**:将记录推送给这 20 个节点。 ## 性能瓶颈 尽管这个系统很健壮,但历史上它非常缓慢,通常需要几十秒甚至几分钟才能完成。我们在 ProbeLab 的研究发现,主要的延迟在于 DHT 遍历的终止条件。 “传统”算法是僵化的:在 DHT 遍历阶段,它坚持等待发现的 3 个最接近节点的响应。在一个无许可的网络中,节点频繁切换,这些特定的节点往往无法访问。系统随后会“回溯”,查询更远的节点来填补空缺,而此时实际最接近的 20 个节点可能已经被发现了。 下图显示了从欧洲(传统上最快的地区)执行的提供操作总持续时间的累积分布函数。原始图表可以在这里找到(https://probelab.io/ipfs/dht/#chart-ipfs-dht-publish-performance-cdf)。图表显示,中位延迟约为 20 秒,在最坏的情况下,一次提供操作可能需要超过两分钟。 IPFS DHT 发布延迟的 CDF 图(0–180 秒)。约 30% 的发布在 5 秒内完成,约 80% 在 20 秒内完成,约 95% 在 60 秒内完成,长尾部分可达 180 秒。 这种性能特征对延迟敏感的应用程序来说是 prohibitive 的,而这正是我们试图通过乐观提供来解决的问题。 ## 乐观提供 **乐观提供**通过用统计启发式方法替代僵化的等待,解决了缓慢的提供操作。自 **Kubo v0.39.0** 起,这是默认行为,通过三个关键机制实现了亚秒级的记录存储: 1. **网络规模估计**:单个节点现在使用一种轻量级的、偏差校正的邻近模型来本地估计全局网络规模。 2. **预测性终止**:在 DHT 遍历期间,发起者使用网络规模估计来计算单个节点及其当前最接近节点集合是否“足够接近”的概率。一旦有 90% 的把握发现某个节点属于全网最接近的 20 个节点之一,就立即存储记录。一旦有 90% 的把握找到了目标集合,就立即终止遍历。 3. **提前返回**:在后续阶段,一旦 20 个节点中的一部分(例如 15 个)确认了存储,系统就将控制权返回给用户。剩余的 5 个请求在后台异步继续进行,确保记录完全复制,而无需用户等待。 ### 网络规模估计 一个看似直观的获取网络规模估计的解决方案可能涉及爬取整个网络以获取参与节点的数量。然而,由于这种方法引入了过多的开销,实际上并不可行。将任务分配给一组共享信息的节点则需要信任它们的诚实性,这在无许可网络中是一个具有挑战性的命题。 相反,我们设计了一种轻量级的估计算法,它利用节点已经在收集的数据——路由表刷新,这意味着我们不会产生任何额外的网络开销。在刷新过程中,节点会为其维护的每个桶查找一个随机键,在 Kubo 的情况下,这意味着 16 次查找,加上节点自身的 ID。每次查找都会返回一个随机目标键在全网中最接近的节点,因此单次刷新轮次自然会得到一个覆盖不同尺度密钥空间的节点距离样本。 核心见解是:假设节点 ID 是均匀分布的,那么对于任何给定键,其 20 个最近邻节点的距离遵循一个可预测的统计分布,具体来说就是顺序统计量(https://en.wikipedia.org/wiki/Order_statistic)的 Beta 分布(https://en.wikipedia.org/wiki/Beta_distribution)(参见这篇优秀的博文(https://eli.sohl.com/2020/06/05/dht-size-estimation.html))。这使得我们可以将一次查找结果中的每个节点视为一个独立的网络规模估计。因此,一次返回 20 个节点的查找可以产生 20 个估计值,而不仅仅是考虑密钥空间密度时的一个值。对几次查找的结果进行平均,得出的结果与我们使用 Nebula 爬虫(https://github.com/dennis-tra/nebula)从真实数据中获得的计数相比,表现良好。 但有一个复杂之处:在自身密钥空间邻域内进行查询(如路由表刷新机制所做的那样)会引入密度偏差。位于密集密钥空间区域中的节点会高估全局网络规模;而在稀疏区域中的节点则会低估它。我们的偏差校正通过指数级降低非满桶数据点的权重来解决这个问题。其直观原理是:一个满桶表明其覆盖的密钥空间区域具有足够多的节点,具有代表性;而稀疏桶则表明局部视图存在偏差。这种校正并非在所有情况下都完美,但它显著降低了不同节点之间估计值的方差。 下图展示了 IPFS Amino 网络中六个独立节点在连续三天内使用未加权和加权方法得到的网络规模估计值,并叠加了我们 Nebula 爬虫的总节点数和可拨号节点数。 两个时间序列图显示了 IPFS 网络规模估计(2023 年 6 月 9–12 日),分别使用未加权和加权方法。在加权图中,所有估计值在整个期间保持稳定,大约在 28,000–32,000 个节点之间,方差更小。 关于该方法的更详细讨论,我们感兴趣的读者可以参考我们的论文(https://ieeexplore.ieee.org/abstract/document/10621404)。 ### 预测性终止 有了可靠的网络规模估计,我们现在可以在 DHT 遍历期间做出概率性决策,而无需等待传统算法所需的僵化确认。 这发生在两个层面。第一个层面是针对单个节点:每次发起者在遍历过程中遇到一个新节点时,它会检查该节点是否已经足够接近目标键,以至于很可能属于全网最接近的 20 个节点。通过反转顺序统计量 Beta 分布的对应 CDF,我们可以计算出一个距离阈值,如果某个节点落在这个阈值内,我们可以有 90% 的把握确定它属于最终的目标集合。当满足该条件时,我们不会等待,而是立即将记录存储给该节点。 第二个层面是针对当前已知的最接近 20 个节点的整个集合。每次查询响应后,发起者会检查这个集合是否很可能已经是全局最接近的 20 个节点。我们观察到,最接近目标键的 20 个节点的期望平均距离等于假设中的第 10.5 个最近节点的期望距离,这为我们提供了一个清晰的标量阈值。一旦已知集合的平均距离低于该阈值(同样在 90% 的置信水平下),遍历就会终止,而无需等待最接近的 3 个节点确认,这与经典算法的要求不同。 > 这两个条件共同消除了使经典提供操作变得缓慢的大部分等待时间。之前导致遍历回溯并逐步探测更远节点的不可达节点,不再会拖延整个过程的进度。 ### 提前返回 预测性终止解决了 DHT 遍历的瓶颈,但在后续阶段引入了新的问题。通过跳过经典算法的回溯行为,我们失去了它原本对不可达节点的过滤效果,这些节点现在在记录存储阶段暴露出来。实际上,在绝大多数操作中,20 个后续请求中至少会有一个失败,而一个不响应的节点就可能使整个阶段因等待超时而停滞。 解决办法很简单:与其等待所有 20 个节点确认存储,不如一旦有 15 个节点响应,就将控制权返回给用户。剩余的 5 个请求在后台异步继续,永远不会被取消。完全复制仍然会发生,只是对用户不可见。我们选择 15 这个数字是基于先前的工作(https://github.com/probe-lab/network-measurements/blob/main/results/rfm17-provider-record-liveness.md#5-conclusion),该工作表明,将复制因子从 20 降低到 15 对 IPFS 网络中的记录可用性影响可以忽略不计,因此在此刻移交控制权不会带来有意义的可靠性成本。 ## 结果 ProbeLab 长期以来一直通过我们广泛的工具(https://probelab.io/tools)监控 IPFS Kubo 的“上传”性能以及其他许多指标(https://probelab.io/ipfs)。我们在二月初将 Kubo 版本更新到了 v0.39.0。下面的图表显示了在部署包含乐观提供的 Kubo 之后,上传延迟从平均约 15 秒急剧下降到约 0.7 秒。 柱状图显示了从 2026 年 1 月中旬到 3 月中旬 Kubo 的“上传”性能(平均时间,以秒为单位)。在 2 月初部署 Kubo v0.39.0 后,提供持续时间从约 15 秒急剧下降到约 1 秒。 ### 记录可用性 任何缩短经典算法的优化都会引发一个自然的担忧:是否会损害记录可用性?将记录存储给错误的节点或存储给过少的节点可能会导致内容更难被发现。我们的测量表明情况并非如此。通过乐观方法选择的节点在统计上足够接近目标键,因此可检索性得以保持,GET 错误率与经典基线相当。该方法确实导致每次 PUT 成功存储确认的次数平均略有减少,但这是一种可接受的权衡:我们的提前返回阈值正是基于我们先前的工作(https://github.com/probe-lab/network-measurements/blob/main/results/rfm17-provider-record-liveness.md)所建立的结论:复制程度的适度减少对 IPFS 网络中的可用性影响可以忽略不计。 Kubo 的重新提供扫描(https://ipshipyard.com/blog/2025-dht-provide-sweep/)进一步加强了这一点,该扫描随后会执行精确的 PUT 操作,以确保记录存储在最准确的节点集合中。初始的乐观提供用一定的放置精度换取速度;而重新提供扫描则在后台悄悄地纠正这一点。 ### 局限性 整个优化依赖于可靠的网络规模估计。如果该估计严重错误,则用于节点选择和遍历终止的距离阈值将出现偏差,记录存储的准确性将受到影响。 这里一个日益严峻的挑战是 IPFS Amino DHT 中不可拨号节点的增加。如下面的图表所示,目前网络中约 50% 的节点身份仅通告私有 IP 地址,无法从公共互联网访问。在当前实现中,这些节点仍然被纳入网络规模估计,从而夸大了计数。这会导致高估,进而使终止阈值更保守而非更激进。这种失败模式是性能下降而非可用性受损,但这确实意味着优化无法充分发挥其潜力。 时间序列图表显示了从 2 月下旬到 3 月中旬 IPFS 拨号错误类型(节点占比)。错误类型 `no_public_ip_addresses` 占主导地位,约为 50%,而 `io_timeout` 保持稳定在约 9%。所有其他错误类型在整个期间均接近 0%。 第二个限制是冷启动问题:Kubo 节点需要至少完成部分路由表刷新,才能拥有足够的数据来运行估计,这在启动后可能需要几秒到几分钟的时间。 我们提出三项增量改进: 1. 仅通告私有 IP 地址的节点将被过滤掉,不参与网络规模估计。 2. 在冷启动期间,节点将使用保守的默认值(即较小的网络规模),直到获得足够的本地数据为止。 3. 后续阶段中用于提前返回的阈值将从 15 调整为动态值,考虑到网络规模估计的置信度。当估计不准确时,阈值将提高(要求更多的确认),以确保记录可用性不因不良的采样而受损。 ## 结论 传统上,在 IPFS 的 DHT 中发布内容是一项缓慢的操作,通常需要 > 10 秒,有时甚至长达数分钟。这种缓慢的体验对实时应用和开发者工作流来说是一种障碍,他们不得不等待很长时间才能看到内容在线。 通过乐观提供,我们通过从一个关键洞察推导出的三个核心技术,将内容发布时间从 > 10 秒降低到 < 1 秒:在分布式哈希表中,等待不可达节点确认记录存储是低效的。通过在推理层面而不是时间层面推动工作,我们可以显著提高性能——在本例中,将整个过程从 > 10 秒降低到 < 1 秒。 这一结果在真正的大规模部署中实现了:该改进已在全球运行的数十万个 Kubo 节点上部署,产生了可衡量的影响。更重要的是,这场胜利不仅仅局限于一项指标;整个 IPFS 生态系统都受益于更有效地路由内容的能力——每个发布者、每个消费者,以及更广泛的网络。 这证明了以数据为导向的问题解决方法和对开放网络核心基础设施进行持续投资的巨大价值。

相似文章

FediMeteo、HAProxy 与不浪费 snac 线程的艺术

Lobsters Hottest

作者介绍了在 FediMeteo 服务中使用 HAProxy 缓存来减少 snac 线程上的不必要负载,此前已用 nginx 做过类似优化。该方法旨在通过让反向代理吸收重复的公共请求,保持轻量级 ActivityPub 服务器的高效。

使用图论加速后端(2019年)

Lobsters Hottest

Sensor Tower 工程团队利用图论分析和性能分析工具,识别出后端端点缓慢的瓶颈,通过优化 Protobuf 解码和编码步骤,实现了四倍的速度提升。