Dragonfly 中 P2P 传输协议优化

简介: 静态限流策略的理想情况是: `perPeerRateLimit` 设置为20M , `totalRateLimit` 设置为 100M ,且该节点目前运行了 5 个或更多的 P2P 下载任务,这种情况下可以确保所有任务总带宽不会超过 100M ,且带宽会被有效利用。

图片

文|孙珩珂

上海交通大学

本文1987字 阅读 10 分钟

01 优化背景

此前 Dragonfly 的 P2P 下载采用静态限流策略,相关配置项在 dfget.yaml 配置文件中:

# 下载服务选项。
download:  
# 总下载限速。  
totalRateLimit: 1024Mi  
# 单个任务下载限速。  perPeerRateLimit: 512Mi

其中 perPeerRateLimit 为单个任务设置流量上限, totalRateLimit 为单个节点的所有任务设置流量上限。

静态限流策略的理想情况是: perPeerRateLimit 设置为20M , totalRateLimit 设置为 100M ,且该节点目前运行了 5 个或更多的 P2P 下载任务,这种情况下可以确保所有任务总带宽不会超过 100M ,且带宽会被有效利用。

图片

这种限流策略的缺点是:若perPeerRateLimit 设置为 20M , totalRateLimit 设置为 100M ,并且当前该节点只运行了一个下载任务,那么该任务的最大下载速度为 20M ,和最大带宽 100M 相比,浪费了 80% 的带宽。

图片

因此,为了最大限度地利用带宽,需要使用动态限流来确保任务数量少时能能充分利用总带宽,而任务数量多时也能公平分配带宽。最终,我们设计出一套根据上下文进行动态限流的算法,其中上下文指各任务在过去一秒内使用的带宽,此外,算法还考虑到了任务数量、任务剩余大小、任务保底带宽等因素,性能相比原来的静态限流算法有显著提升。

02 相关代码分析

perPeerRateLimit 配置项最终赋值给 peerTaskConductor 的pt.limiter ,由 peerTaskConductor 的 DownloadPiece() 函数里进行限速,pt.waitLimit() 进行实际限流工作,底层调用 Go 自带的限流函数 WaitN() 。

TotalRateLimit 配置项则在创建 Daemon 时被赋值给 pieceManager 的pm.limiter ,在 pieceManager 的 DownloadPiece() 和 processPieceFromSource() 函数中用到的 pm.limiter ,而这两个函数都会由 peerTaskConductor 调用,也就是说 P2P 下载会先进行总限速,之后再进行每个任务单独限速。

图片

根据以上分析,Dragonfly 进行任务限速的逻辑为,每个peer task(peerTaskConductor)会有单独的限速 perPeerRateLimit ,同时 pieceManager 会有 TotalRateLimit 的总限速,以此达到单任务单独限流,同时限制所有任务总带宽的效果。

### 03 优化方案

为了解决此前静态限流算法总带宽利用率不佳的缺点,需要将其改进为动态限流算法,即总带宽限速仍恒定,但每个任务的单独带宽限速需要根据上下文适度、定期调整,已达到最大化利用总带宽、同时相对公平分配带宽的目的。

在经过数个改版后,最终我们确定了根据上下文进行限流的 sampling traffic shaper 动态限流算法。具体方案为,每个任务的单任务限流交由 TrafficShaper 组建进行统一管理, TrafficShaper 维护当前正在运行的所有任务,并且定期(每秒)更新这些任务的带宽。

具体来说,上下文指每个任务在上一秒使用的带宽、每个任务的剩余大小、任务数量、任务保底带宽(不能低于 pieceSize )等因素, TrafficShaper 会根据这些上下文公平地、效率最大化地为每个任务分配其下一秒的带宽(具体分配方案详见下一小节),实现动态限流的效果。

04 优化实现

定义 TrafficShaper 接口如下:

// TrafficShaper allocates bandwidth for running tasks dynamically
type TrafficShaper interface {
   // Start starts the TrafficShaper
   Start()   
   // Stop stops the TrafficShaper
   Stop()   
   // AddTask starts managing the new task
   AddTask(taskID string, ptc *peerTaskConductor)
   // RemoveTask removes completed task
   RemoveTask(taskID string)   
   // Record records task's used bandwidth
   Record(taskID string, n int)
   // GetBandwidth gets the total download bandwidth in the past second
   GetBandwidth() int64
}

该接口有两种实现,第一种是 samplingTrafficShaper 即基于上下文的 traffic shaper ,第二种是 plainTrafficShaper 只记录带宽使用情况,除此之外不做任何动态限流工作,用于和 samplingTrafficShaper 对比性能提升。

同时,将相关配置项修改为如下内容:

# 下载服务选项。
download:  
# 总下载限速。
totalRateLimit: 1024Mi
# 单个任务下载限速。
perPeerRateLimit: 512Mi
# traffic shaper类型,有sampling和plain两种可选  trafficShaperType: sampling

图片

Traffic shaper 的具体运行逻辑为,由peerTaskManager维护trafficShaper,在创建peerTaskManager时,根据配置初始化trafficShaper,并且调用Start()函数,启动trafficShaper,具体来说,新建time.NewTicker,跨度为 1 秒,也即每秒trafficShaper都会调用updateLimit()函数以动态更新所有任务的带宽限流。

updateLimit() 函数会遍历所有运行中的任务,得出每个任务上一秒消耗的带宽以及所有任务消耗的总带宽,随后根据任务上一秒使用的带宽、任务剩余大小等因素,按比例分配带宽,具体来说首先根据上一秒该任务使用带宽以及该任务剩余大小的最大值确定下一秒该任务带宽,接着所有任务带宽根据总带宽按比例缩放,得到下一秒的真实带宽;同时需要确保每个任务的带宽不低于该任务的 pieceSize ,以免出现持续饥饿状态。

在 peerTaskManager 的 getOrCreatePeerTaskConductor() 函数中,若新建任务,需要带宽,那么调用 AddTask() 更新所有任务的带宽,即按照已有任务的平均任务分配带宽,然后再根据总带宽上限将所有任务的带宽等比例进行缩放;根据平均带宽分配新任务带宽的优势为,避免了已经有一个任务占满了所有带宽,有新任务进来时,带宽会被压缩到很小 **的情况;同时,不是平均分配带宽,而是按需等比例分配,可以确保带宽需求量大的任务仍然带宽最多。在 peerTaskManager 的 PeerTaskDone() 函数中,任务完成,不再占用带宽,调用 RemoveTask() 按比例扩大所有任务的带宽。

最后, peerTaskManager 停止时,调用 Stop 函数,停止运行 traffic shaper 。

05 优化结果

测试 traffic shaper 相比原有的静态限流策略在单个任务、多个任务并发、多个任务交错等多种情况下的性能提升,测试结果如下:

图片
注:若不特殊注明,单任务限流为4KB/s,总限流为10KB/s

可以看到, traffic shaper 在单任务、多任务不相交、单任务低带宽等情况下相比静态限流策略性能提升明显,为 24%~59% 。在多个任务并发、多个任务交错等情况下和静态限流策略性能相当。综上,实验证明 sampling traffic shaper 能很好地解决任务数量较少时总带宽被大量浪费的情况,同时在任务数量较多以及其他复杂情况时依旧能保证和静态限流算法持平的效果。

PR 链接(已合并):
https://github.com/dragonflyoss/Dragonfly2/pull/1654

本周推荐阅读

Dragonfly 基于 P2P 的文件和镜像分发系统

深入 HTTP/3(2)|不那么 Boring 的 SSL

Go 代码城市上云——KusionStack 实践

MOSN 反向通道详解

相关文章
|
安全 Windows
Win10/Win11如何获取最高管理员权限
Win10/Win11如何获取最高管理员权限
4576 0
|
存储 人工智能 测试技术
具备实时数据更新能力的大语言模型——Larimar
【2月更文挑战第30天】Larimar是一种新型的人工智能研究,旨在解决大型语言模型的知识更新问题。通过引入分布式情景记忆机制,类似人脑海马体的功能,Larimar能动态更新知识而无需完全重训。在实验中,它在事实编辑基准测试中展现出高准确性和速度提升,比基础LLM快4到10倍。Larimar的精巧架构包含编码器、解码器和自适应记忆模块,能在多种场景下有效应用。该模型的记忆操作包括写入、读取和生成,且在序列事实编辑任务中表现出色,防止信息遗忘。
788 2
具备实时数据更新能力的大语言模型——Larimar
|
3月前
|
Windows CDN
Windows File Recovery Installer.exe 安装步骤详解(附文件恢复命令教程)
Windows File Recovery Installer是微软官方命令行文件恢复工具,支持Win10 2004+/Win11。可找回误删的文档、照片、视频等,安装后通过CMD运行winfr命令恢复,支持快速扫描(/n)与深度扫描(/r),恢复文件存至指定盘符Recovery文件夹。
|
Linux 虚拟化 Docker
Linux服务器部署docker windows
在当今软件开发中,Docker成为流行的虚拟化技术,支持在Linux服务器上运行Windows容器。流程包括:1) 安装Docker;2) 配置支持Windows容器;3) 获取Windows镜像;4) 运行Windows容器;5) 验证容器状态。通过这些步骤,你可以在Linux环境中顺利部署和管理Windows应用,提高开发和运维效率。
2374 1
|
缓存 搜索推荐 定位技术
PWA 适用于哪些类型的应用
PWA(渐进式网页应用)适用于多种类型的应用,包括新闻、天气、电商、社交、娱乐和工具类应用,能够提供接近原生应用的体验,支持离线访问和快速加载。
|
存储 自然语言处理 前端开发
Star 6.9k!开源的全能Markdown格式文件提取器:MinerU
总的来说,MinerU是一款非常实用且强大的数据提取工具。无论你是开发者、互联网从业者,还是有具体需求的新人小白,MinerU都能极大地提升你的工作效率,让你专注于更有价值的工作。 最后,如果你对MinerU感兴趣,不妨亲自尝试一下,相信你会爱上这款全能的Markdown格式文件提取器。
Linux_异常_02_WinSCP上传文件时显示Permission denied
异常现象如下:         二、解决方案 1.设置对应目录权限全开,就可以上传文件到这个目录了 sudo chmod 777 /devloper
2306 0
|
Shell 开发工具 git
(亲测好用)构建React-app应用时create-react-app卡住超慢的解决办法
(亲测好用)构建React-app应用时create-react-app卡住超慢的解决办法
1585 0
(亲测好用)构建React-app应用时create-react-app卡住超慢的解决办法

热门文章

最新文章