Dragonfly P2P 傳輸協(xié)議優(yōu)化代碼解析
優(yōu)化背景
此前 Dragonfly 的 P2P 下載采用靜態(tài)限流策略,相關(guān)配置項在 dfget.yaml
配置文件中:
# 下載服務(wù)選項。 download: # 總下載限速。 totalRateLimit: 1024Mi # 單個任務(wù)下載限速。 perPeerRateLimit: 512Mi
其中 perPeerRateLimit
為單個任務(wù)設(shè)置流量上限, totalRateLimit
為單個節(jié)點(diǎn)的所有任務(wù)設(shè)置流量上限。
靜態(tài)限流策略的理想情況是: perPeerRateLimit
設(shè)置為20M , totalRateLimit
設(shè)置為 100M ,且該節(jié)點(diǎn)目前運(yùn)行了 5 個或更多的 P2P 下載任務(wù),這種情況下可以確保所有任務(wù)總帶寬不會超過 100M ,且?guī)挄挥行Ю谩?/p>
這種限流策略的缺點(diǎn)是:若perPeerRateLimit
設(shè)置為 20M , totalRateLimit
設(shè)置為 100M ,并且當(dāng)前該節(jié)點(diǎn)只運(yùn)行了一個下載任務(wù),那么該任務(wù)的最大下載速度為 20M ,和最大帶寬 100M 相比,浪費(fèi)了 80% 的帶寬。
因此,為了最大限度地利用帶寬,需要使用動態(tài)限流來確保任務(wù)數(shù)量少時能能充分利用總帶寬,而任務(wù)數(shù)量多時也能公平分配帶寬。最終,我們設(shè)計出一套根據(jù)上下文進(jìn)行動態(tài)限流的算法,其中上下文指各任務(wù)在過去一秒內(nèi)使用的帶寬,此外,算法還考慮到了任務(wù)數(shù)量、任務(wù)剩余大小、任務(wù)保底帶寬等因素,性能相比原來的靜態(tài)限流算法有顯著提升。
相關(guān)代碼分析
perPeerRateLimit
配置項最終賦值給 peerTaskConductor
的pt.limiter
,由 peerTaskConductor
的 DownloadPiece()
函數(shù)里進(jìn)行限速,pt.waitLimit()
進(jìn)行實(shí)際限流工作,底層調(diào)用 Go 自帶的限流函數(shù) WaitN()
。
TotalRateLimit
配置項則在創(chuàng)建 Daemon
時被賦值給 pieceManager
的pm.limiter
,在 pieceManager
的 DownloadPiece()
和 processPieceFromSource()
函數(shù)中用到的 pm.limiter
,而這兩個函數(shù)都會由 peerTaskConductor
調(diào)用,也就是說 P2P 下載會先進(jìn)行總限速,之后再進(jìn)行每個任務(wù)單獨(dú)限速。
根據(jù)以上分析,Dragonfly 進(jìn)行任務(wù)限速的邏輯為,每個peer task(peerTaskConductor
)會有單獨(dú)的限速 perPeerRateLimit
,同時 pieceManager
會有 TotalRateLimit
的總限速,以此達(dá)到單任務(wù)單獨(dú)限流,同時限制所有任務(wù)總帶寬的效果。
優(yōu)化方案
為了解決此前靜態(tài)限流算法總帶寬利用率不佳的缺點(diǎn),需要將其改進(jìn)為動態(tài)限流算法,即總帶寬限速仍恒定,但每個任務(wù)的單獨(dú)帶寬限速需要根據(jù)上下文適度、定期調(diào)整,已達(dá)到最大化利用總帶寬、同時相對公平分配帶寬的目的。
在經(jīng)過數(shù)個改版后,最終我們確定了根據(jù)上下文進(jìn)行限流的 sampling traffic shaper 動態(tài)限流算法。具體方案為,每個任務(wù)的單任務(wù)限流交由 TrafficShaper
組建進(jìn)行統(tǒng)一管理, TrafficShaper
維護(hù)當(dāng)前正在運(yùn)行的所有任務(wù),并且定期(每秒)更新這些任務(wù)的帶寬。
具體來說,上下文指每個任務(wù)在上一秒使用的帶寬、每個任務(wù)的剩余大小、任務(wù)數(shù)量、任務(wù)保底帶寬(不能低于 pieceSize
)等因素, TrafficShaper
會根據(jù)這些上下文公平地、效率最大化地為每個任務(wù)分配其下一秒的帶寬(具體分配方案詳見下一小節(jié)),實(shí)現(xiàn)動態(tài)限流的效果。
優(yōu)化實(shí)現(xiàn)
定義 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 }
該接口有兩種實(shí)現(xiàn),第一種是 samplingTrafficShaper
即基于上下文的 traffic shaper ,第二種是 plainTrafficShaper
只記錄帶寬使用情況,除此之外不做任何動態(tài)限流工作,用于和 samplingTrafficShaper
對比性能提升。
同時,將相關(guān)配置項修改為如下內(nèi)容:
# 下載服務(wù)選項。 download: # 總下載限速。 totalRateLimit: 1024Mi # 單個任務(wù)下載限速。 perPeerRateLimit: 512Mi # traffic shaper類型,有sampling和plain兩種可選 trafficShaperType: sampling
Traffic shaper 的具體運(yùn)行邏輯為,由peerTaskManager
維護(hù)trafficShaper
,在創(chuàng)建peerTaskManager
時,根據(jù)配置初始化trafficShaper
,并且調(diào)用Start()
函數(shù),啟動trafficShaper
,具體來說,新建time.NewTicker
,跨度為 1 秒,也即每秒trafficShaper
都會調(diào)用updateLimit()
函數(shù)以動態(tài)更新所有任務(wù)的帶寬限流。
updateLimit()
函數(shù)會遍歷所有運(yùn)行中的任務(wù),得出每個任務(wù)上一秒消耗的帶寬以及所有任務(wù)消耗的總帶寬,隨后根據(jù)任務(wù)上一秒使用的帶寬、任務(wù)剩余大小等因素,按比例分配帶寬,具體來說首先根據(jù)上一秒該任務(wù)使用帶寬以及該任務(wù)剩余大小的最大值確定下一秒該任務(wù)帶寬,接著所有任務(wù)帶寬根據(jù)總帶寬按比例縮放,得到下一秒的真實(shí)帶寬;同時需要確保每個任務(wù)的帶寬不低于該任務(wù)的 pieceSize
,以免出現(xiàn)持續(xù)饑餓狀態(tài)。
在 peerTaskManager
的 getOrCreatePeerTaskConductor()
函數(shù)中,若新建任務(wù),需要帶寬,那么調(diào)用 AddTask()
更新所有任務(wù)的帶寬,即按照已有任務(wù)的平均任務(wù)分配帶寬,然后再根據(jù)總帶寬上限將所有任務(wù)的帶寬等比例進(jìn)行縮放;根據(jù)平均帶寬分配新任務(wù)帶寬的優(yōu)勢為,避免了已經(jīng)有一個任務(wù)占滿了所有帶寬,有新任務(wù)進(jìn)來時,帶寬會被壓縮到很小 **的情況;同時,不是平均分配帶寬,而是按需等比例分配,可以確保帶寬需求量大的任務(wù)仍然帶寬最多。在 peerTaskManager
的 PeerTaskDone()
函數(shù)中,任務(wù)完成,不再占用帶寬,調(diào)用 RemoveTask()
按比例擴(kuò)大所有任務(wù)的帶寬。
最后, peerTaskManager
停止時,調(diào)用 Stop
函數(shù),停止運(yùn)行 traffic shaper 。
優(yōu)化結(jié)果
測試 traffic shaper 相比原有的靜態(tài)限流策略在單個任務(wù)、多個任務(wù)并發(fā)、多個任務(wù)交錯等多種情況下的性能提升,測試結(jié)果如下:
注:若不特殊注明,單任務(wù)限流為4KB/s,總限流為10KB/s
可以看到, traffic shaper 在單任務(wù)、多任務(wù)不相交、單任務(wù)低帶寬等情況下相比靜態(tài)限流策略性能提升明顯,為 24%~59% 。在多個任務(wù)并發(fā)、多個任務(wù)交錯等情況下和靜態(tài)限流策略性能相當(dāng)。綜上,實(shí)驗證明 sampling traffic shaper 能很好地解決任務(wù)數(shù)量較少時總帶寬被大量浪費(fèi)的情況,同時在任務(wù)數(shù)量較多以及其他復(fù)雜情況時依舊能保證和靜態(tài)限流算法持平的效果。
PR 鏈接(已合并): github.com/dragonflyos…
以上就是Dragonfly P2P 傳輸協(xié)議優(yōu)化代碼解析的詳細(xì)內(nèi)容,更多關(guān)于Dragonfly P2P 傳輸協(xié)議的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序 flex實(shí)現(xiàn)導(dǎo)航實(shí)例詳解
這篇文章主要介紹了微信小程序 flex實(shí)現(xiàn)導(dǎo)航實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04arcgis?js完整懸停效果實(shí)現(xiàn)demo
這篇文章主要為大家介紹了arcgis?js完整懸停效果實(shí)現(xiàn)demo詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM二
這篇文章主要為大家介紹了JS函數(shù)式編程實(shí)現(xiàn)XDM示例詳解第2/3篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06