通过委托路由HTTP服务器中的缓存实现浏览器中更快的点对点检索
TL;DR
去年我们对Someguy进行了重大改进,这是Amino DHT和IPNI的HTTP委托路由API。该更新引入了缓存地址簿和针对DHT对等节点的主动探测功能。这一变化显著提高了返回地址的提供者比例,从而加速了浏览器和移动应用中的点对点内容检索。该功能已包含在Someguy的v0.7.0版本中。
什么是Someguy及其重要性
Someguy是一个委托路由HTTP API,用于将IPFS路由请求代理到Amino DHT、IPNI或任何实现相同API的路由系统。其主要目的是帮助IPFS客户端查找CID的提供者节点及其网络地址,并将其暴露为HTTP API。
这对于需要获取IPFS内容但不运行完整DHT客户端的浏览器和移动应用至关重要。Amino DHT客户端是有状态的,通常需要打开数百个连接来维护其路由表并查找提供者和节点记录。
问题是浏览器和移动设备在网络能力方面受到限制——无论是它们可以使用的传输协议还是可以打开的连接数量。移动设备还有有限的电池和带宽,使得运行完整的DHT客户端不切实际。
委托路由允许这些设备通过单个HTTP请求查询DHT以获取内容提供者,而不需要它们自己维护复杂的DHT连接。
Someguy在IPFS内容检索中的作用
当Helia或@helia/verified-fetch从IPFS网络获取内容时,它经历以下过程:
- Helia使用
Accept: application/x-ndjson头向Someguy请求CID的提供者,用于流式响应 - Someguy遍历Amino DHT并响应具有内容的提供者,通常包括它们的网络地址
- 浏览器/移动应用在每个提供者记录到达流中时直接连接到这些节点,实现并行连接尝试和更快的内容检索
性能方程很简单:Someguy响应有效节点地址的速度越快,浏览器和移动应用就能越快开始点对点获取内容。
问题:没有节点地址的提供者记录
在v0.7之前,Someguy经常响应包含节点ID但不包含其网络地址的提供者记录。这意味着客户端必须额外请求/routing/v1/peers/{peerid}来获取每个节点的实际地址。
但为什么提供者返回时没有节点地址?
广泛使用的go-libp2p和go-libp2p-kad-dht库有几个重要的常量,控制提供者和节点地址在内存中的缓存时间:
DefaultProvideValidity = 48 * time.Hour:提供者记录在多哈希(来自CID)和节点ID之间的TTLDefaultProviderAddrTTL = 24 * time.Hour:这些提供者地址的TTLRecentlyConnectedAddrTTL = time.Minute * 15:节点断开连接后其地址在内存中保留的时间
换句话说,DHT服务器可以返回没有节点地址的提供者记录。
解决方案:缓存节点地址
PR #90引入了多种机制,确保Someguy始终返回带有新鲜节点地址的提供者记录,或者根本不返回提供者记录,从而为客户端节省对不可路由节点的额外节点路由请求。
这是通过以下组合实现的:缓存地址簿、主动节点探测和缓存路由器,该路由器用地址增强结果并过滤掉不可拨号的节点。
缓存地址簿
新的缓存地址簿包装了go-libp2p memoryAddrBook,并具有以下属性:
- 48小时缓存:存储节点地址48小时,与DHT提供者记录过期时间匹配
- 100万节点容量:设置内存使用上限
- 内存高效:使用LRU驱逐保持最相关的节点随时可用
- 事件驱动的缓存维护:通过订阅libp2p事件总线缓存节点
后台主动节点探测
Someguy现在在后台测试节点连接性:
- 后台验证:每15分钟测试缓存的节点地址是否仍然有效
- 指数退避:停止在持续离线的节点上浪费时间
- 并发测试:同时测试最多20个节点连接
- 选择性探测:仅测试最近未验证的节点
缓存路由器:为HTTP客户端提供更好的响应
cachedRouter使用缓存地址簿通过非阻塞迭代器增强节点和提供者请求的路由结果:
- 缓存优先响应:当可用时立即返回已验证的节点地址
- 后台解析:如果不存在缓存地址,则查找新地址而不阻塞响应
- 流式结果:一旦找到工作节点地址就发送
- 回退处理:省略无法访问的节点而不是发送错误地址
测量影响
为了测量这些变化的影响,我们部署了两个someguy实例,一个启用缓存地址簿和主动探测,另一个禁用。
我们观察到缓存地址簿大小指标在大约12小时后稳定,此时缓存约有3万个节点。该指标继续逐渐增长,最终停滞在约6万个节点。
节点地址缓存有效性
| 查找类型 | 数量 | 百分比 |
|---|---|---|
| 使用地址缓存 | 1,287,619 | 34.4% |
| 未使用地址缓存 | 2,455,120 | 65.6% |
| 总计 | 3,742,739 | 100.0% |
我们测量了两个关键指标来评估缓存影响:
-
需要缓存的频率如何?
- 在约66%的请求中,DHT返回的提供者记录已包含地址
- 剩余的约34%返回没有地址的提供者,需要缓存查找或额外的节点路由
-
当需要时,缓存的效果如何?
- 对于需要地址解析的34.4%请求:
- 缓存命中:约83%(在缓存中找到地址)
- 缓存未命中:约17%(需要新的节点查找)
- 对于需要地址解析的34.4%请求:
HTTP请求延迟和成功率
我们检查了按响应代码(200 vs 404)分组的对/routing/v1/providers/[CID]的HTTP请求的P95(第95百分位)延迟,以及由200与404响应比率衡量的成功率。
| 场景 | 200s P95 | 404s P95 | 成功率 | 延迟改进 |
|---|---|---|---|---|
| 缓存禁用 | 1.91s | 7.35s | 52.0% | 基线 |
| 缓存启用并预热 | 1.35s | 7.46s | 57.2% | -560ms(快29%) |
关键见解
启用节点地址缓存后,我们观察到超出地址可用性的意外改进:
- 成功响应的P95延迟从1.91秒提高到1.35秒(快29%)
- 成功率从52.0%增加到57.2%
这些改进可能源于主动后台探测,它预先验证节点连接性。
配置
缓存地址簿和主动探测可以通过以下环境变量配置:
SOMEGUY_CACHED_ADDR_BOOKSOMEGUY_CACHED_ADDR_BOOK_ACTIVE_PROBINGSOMEGUY_CACHED_ADDR_BOOK_RECENT_TTL
额外优化:HTTP级缓存
除了上面讨论的节点地址缓存外,Someguy还通过Cache-Control头实现HTTP级缓存:
- 缓存持续时间:
- 有结果的提供者响应:5分钟
- 空响应(未找到提供者):15秒
stale-while-revalidate:48小时
结论
向Someguy添加节点地址缓存和主动探测代表了在受限环境中去中心化内容检索的重要进步。通过消除约83%的额外节点查找并将P95延迟减少约30%(约560毫秒),这些改进使通过浏览器和移动应用访问IPFS的数百万用户明显感受到直接点对点内容检索的速度提升。