【特殊提醒:本文理論性較強,請謹慎閱讀】
上一篇文章中分析了UC浏覽器的視訊下載下傳方式:UC浏覽器視訊播放緩存以及視訊下載下傳分析,講到了P2P的下載下傳方式,本文就分析一下什麼是P2P的下載下傳方式,以及P2P所屬的分布式的下載下傳緩存體系。
傳統的下載下傳就是client和server端互動,這個server是固定的,就是存儲資源的伺服器,這時候不管網速如何,下載下傳的速度嚴重依賴于伺服器的服務穩定性,如果伺服器不太穩定,接入就比較慢,下載下傳速度就會受到很大的限制,這也是傳統下載下傳方式的速度優化有一個非常明顯的天花闆——難以解決單一伺服器帶來的帶寬壓力。鑒于這個瓶頸問題,我們想要是可以将伺服器的壓力分擔出去就好了,不唯一依賴某一個或者某幾個伺服器,這樣至少可以将下載下傳速度的上限明顯提高。
很顯然,真的有這樣的下載下傳方式,就是P2P。P2P 就是 peer-to-peer。資源開始并不集中地存儲在某些裝置上,而是分散地存儲在多台裝置上。這些裝置我們姑且稱為 peer。想要下載下傳一個檔案的時候,你隻要得到那些已經存在了檔案的 peer,并和這些 peer 之間,建立點對點的連接配接,而不需要到中心伺服器上,就可以就近下載下傳檔案。一旦下載下傳了檔案,你也就成為 peer 中的一員,你旁邊的那些機器,也可能會選擇從你這裡下載下傳檔案,是以當你使用 P2P 軟體的時候,例如 BitTorrent,往往能夠看到,既有下載下傳流量,也有上傳的流量,也即你自己也加入了這個 P2P 的網絡,自己從别人那裡下載下傳,同時也提供給其他人下載下傳。可以想象,這種方式,參與的人越多,下載下傳速度越快,一切完美。
種子檔案解析
我們怎麼知道有哪些用戶端有資源檔案?
就輪到“種子檔案”登場了,種子檔案的字尾是“.torrent”,這個相信大家并不陌生,PC時代有很多P2P的下載下傳工具,其中著名的有迅雷、電驢、風行,還有一些使用P2P技術的播放器,比較著名的有快播。哈哈,言歸正傳,種子檔案中記錄中每一個節點中存放着什麼資料,并且這個節點的一些基本資訊,友善我們能連接配接上這個節點并且下載下傳這個資源。
給大家介紹一個線上的torrent分析站點:http://tool.chacuo.net/commontorrentinfo,我現在想解析一個本地的torrent檔案,結果如下:
.torrent 檔案由兩部分組成,分别是:announce(tracker URL)和檔案資訊。
下載下傳時,BT 用戶端首先解析.torrent 檔案,得到 tracker 位址,然後連接配接 tracker 伺服器。tracker 伺服器回應下載下傳者的請求,将其他下載下傳者(包括釋出者)的 IP 提供給下載下傳者。下載下傳者再連接配接其他下載下傳者,根據.torrent 檔案,兩者分别對方告知自己已經有的塊,然後交換對方沒有的資料。此時不需要其他伺服器參與,并分散了單個線路上的資料流量,是以減輕了伺服器的負擔。
下載下傳者每得到一個塊,需要算出下載下傳塊的 Hash 驗證碼,并與.torrent 檔案中的對比。如果一樣,則說明塊正确,不一樣則需要重新下載下傳這個塊。這種規定是為了解決下載下傳内容的準确性問題。
從這個過程也可以看出,這種方式特别依賴 tracker。tracker 需要收集下載下傳者資訊的伺服器,并将此資訊提供給其他下載下傳者,使下載下傳者們互相連接配接起來,傳輸資料。雖然下載下傳的過程是非中心化的,但是加入這個 P2P 網絡的時候,都需要借助 tracker 中心伺服器,這個伺服器是用來登記有哪些使用者在請求哪些資源。
是以,這種工作方式有一個弊端,一旦 tracker 伺服器出現故障或者線路遭到屏蔽,BT 工具就無法正常工作了。
- info 區:這裡指定的是該種子有幾個檔案、檔案有多長、目錄結構,以及目錄和檔案的名字。
- Name 字段:指定頂層目錄名字。
- 每個段的大小:BitTorrent(簡稱 BT)協定把一個檔案分成很多個小段,然後分段下載下傳。
- 段哈希值:将整個種子中,每個段的 SHA-1 哈希值拼在一起。
DHT——去中心化
鑒于P2P下載下傳的一些瑕疵,那能不能徹底去中心化呢?
為了解決P2P下載下傳的這個問題,DHT(Distributed Hash Table)應運而生,這是一種完全的去中心化的網絡。每個加入這個 DHT 網絡的人,都要負責存儲這個網絡裡的資源資訊和其他成員的聯系資訊,相當于所有人一起構成了一個龐大的分布式存儲資料庫。
有一種著名的 DHT 協定,叫 Kademlia 協定。這個和區塊鍊的概念一樣,很抽象,我來詳細講一下這個協定。任何一個 BitTorrent 啟動之後,它都有兩個角色。一個是 peer,監聽一個 TCP 端口,用來上傳和下載下傳檔案,這個角色表明,我這裡有某個檔案。另一個角色 DHT node,監聽一個 UDP 的端口,通過這個角色,這個節點加入了一個 DHT 的網絡。
任何一個 BitTorrent 啟動之後,它都有兩個角色。一個是 peer,監聽一個 TCP 端口,用來上傳和下載下傳檔案,這個角色表明,我這裡有某個檔案。另一個角色 DHT node,監聽一個 UDP 的端口,通過這個角色,這個節點加入了一個 DHT 的網絡。
在 DHT 網絡裡面,每一個 DHT node 都有一個 ID。這個 ID 是一個很長的串。每個 DHT node 都有責任掌握一些知識,也就是檔案索引,也即它應該知道某些檔案是儲存在哪些節點上。它隻需要有這些知識就可以了,而它自己本身不一定就是儲存這個檔案的節點。
當然,每個 DHT node 不會有全局的知識,也即不知道所有的檔案儲存在哪裡,它隻需要知道一部分。那應該知道哪一部分呢?這就需要用雜湊演算法計算出來。
每個檔案可以計算出一個哈希值,而 DHT node 的 ID 是和哈希值相同長度的串。DHT 算法是這樣規定的:如果一個檔案計算出一個哈希值,則和這個哈希值一樣的那個 DHT node,就有責任知道從哪裡下載下傳這個檔案,即便它自己沒儲存這個檔案。當然不一定這麼巧,總能找到和哈希值一模一樣的,有可能一模一樣的 DHT node 也下線了,是以 DHT 算法還規定:除了一模一樣的那個 DHT node 應該知道,ID 和這個哈希值非常接近的 N 個 DHT node 也應該知道。
什麼叫和哈希值接近呢?例如隻修改了最後一位,就很接近;修改了倒數 2 位,也不遠;修改了倒數 3 位,也可以接受。總之,湊齊了規定的 N 這個數就行。
剛才那個圖裡,檔案 1 通過哈希運算,得到比對 ID 的 DHT node 為 node C,當然還會有其他的節點。是以,node C 有責任知道檔案 1 的存放位址,雖然 node C 本身沒有存放檔案 1。同理,檔案 2 通過哈希運算,得到比對 ID 的 DHT node 為 node E,但是 node D 和 E 的 ID 值很近,是以 node D 也知道。當然,檔案 2 本身沒有必要一定在 node D 和 E 裡,但是碰巧這裡就在 E 那有一份。
接下來一個新的節點 node new 上線了。如果想下載下傳檔案 1,它首先要加入 DHT 網絡,如何加入呢?
在這種模式下,種子.torrent 檔案裡面就不再是 tracker 的位址了,而是一個 list 的 node 的位址,而所有這些 node 都是已經在 DHT 網絡裡面的。當然随着時間的推移,很可能有退出的,有下線的,但是我們假設,不會所有的都聯系不上,總有一個能聯系上。node new 隻要在種子裡面找到一個 DHT node,就加入了網絡。
node new 會計算檔案 1 的哈希值,并根據這個哈希值了解到,和這個哈希值比對,或者很接近的 node 上知道如何下載下傳這個檔案,例如計算出來的哈希值就是 node C。
但是 node new 不知道怎麼聯系上 node C,因為種子裡面的 node 清單裡面很可能沒有 node C,但是它可以問,DHT 網絡特别像一個社交網絡,node new 隻有去它能聯系上的 node 問,你們知道不知道 node C 的聯系方式呀?
在 DHT 網絡中,每個 node 都儲存了一定的聯系方式,但是肯定沒有 node 的所有聯系方式。DHT 網絡中,節點之間通過互相通信,也會交流聯系方式,也會删除聯系方式。和人們的方式一樣,你有你的朋友圈,你的朋友有它的朋友圈,你們互相加微信,就互相認識了,過一段時間不聯系,就删除朋友關系。
有個理論是,社交網絡中,任何兩個人直接的距離不超過六度,也即你想聯系比爾蓋茨,也就六個人就能夠聯系到了。
是以,node new 想聯系 node C,就去萬能的朋友圈去問,并且求轉發,朋友再問朋友,很快就能找到。如果找不到 C,也能找到和 C 的 ID 很像的節點,它們也知道如何下載下傳檔案 1。
在 node C 上,告訴 node new,下載下傳檔案 1,要去 B、D、 F,于是 node new 選擇和 node B 進行 peer 連接配接,開始下載下傳,它一旦開始下載下傳,自己本地也有檔案 1 了,于是 node new 告訴 node C 以及和 node C 的 ID 很像的那些節點,我也有檔案 1 了,可以加入那個檔案擁有者清單了。
但是你會發現 node new 上沒有檔案索引,但是根據雜湊演算法,一定會有某些檔案的哈希值是和 node new 的 ID 比對上的。在 DHT 網絡中,會有節點告訴它,你既然加入了咱們這個網絡,你也有責任知道某些檔案的下載下傳位址。
這兒引出兩個問題?
- DHT網絡是如何維護這麼多node的?
- DHT網絡是如何查找需要的node?具體的原理算法是什麼?
這些問題我會在下一篇文章中闡釋一下。請繼續關注。
小結
- 傳統下載下傳方式一般采用單一伺服器方式,下載下傳速度受到較大的制約。分布式的下載下傳方式解決了傳統下載下傳方式的弊端。
- 分布式下載下傳方式也有兩種:依賴tracker的“中繼資料集中,檔案資料分散”的方式;另一種是基于分布式的雜湊演算法,保證中繼資料和檔案資料完全分開。
關注JeffMony,随時帶來音視訊/算法/python知識分享,感謝與我一起成長,長按關注一下吧。