從分佈式存儲到IPFS

分佈式存儲

以電影為例子,那麼有很多電影,分佈式節點是不是都要把所有的電影完整存儲在本地節點上,還是分開存儲,如果一旦分散存儲,節點加入和退出會不會影響到整個存儲電影的數據。

一致性哈希

一致性哈希算法在1997年由麻省理工學院提出的一種分佈式哈希(DHT)實現算法,設計目標是為了解決因特網中的熱點(Hot spot)問題,初衷和CARP十分類似。一致性哈希修正了CARP使用的簡 單哈希算法帶來的問題,使得分佈式哈希(DHT)可以在P2P環境中真正得到應用。

一致性hash算法提出了在動態變化的Cache環境中,判定哈希算法好壞的四個定義:

  • 平衡性(Balance):平衡性是指哈希的結果能夠儘可能分佈到所有的緩衝中去,這樣可以使得所有的緩衝空間都得到利用。很多哈希算法都能夠滿足這一條件。

  • 單調性(Monotonicity):單調性是指如果已經有一些內容通過哈希分派到了相應的緩衝中,又有新的緩衝加入到系統中。哈希的結果應能夠保證原有已分配的內容可以被映射到原有的或者新的緩衝中去,而不會被映射到舊的緩衝集合中的其他緩衝區。

  • 分散性(Spread):在分佈式環境中,終端有可能看不到所有的緩衝,而是隻能看到其中的一部分。當終端希望通過哈希過程將內容映射到緩衝上時,由於不同終端所見的緩衝範圍有可能不同,從而導致哈希的結果不一致,最終的結果是相同的內容被不同的終端映射到不同的緩衝區中。這種情況顯然是應該避免的,因為它導致相同內容被存儲到不同緩衝中去,降低了系統存儲的效率。分散性的定義就是上述情況發生的嚴重程度。好的哈希算法應能夠儘量避免不一致的情況發生,也就是儘量降低分散性。

從分佈式存儲到IPFS

一致性哈希(Consistent Hashing):結合上面的例子說明,使用一組不同的hash函數,根據電影的文件名movie-name分別計算出一組h1(x)計算hash值。根據hash函數h(x)再結合分佈式網絡中每個節點n的唯一名稱或者標籤,再計算一組h2(x)計算hash值。針對某一個電影來說,那麼h1(x)≈h2(x)。那麼講其一個副本存儲在該網絡節點上。計算公式:|h1(x)-h2(x)|=min{|h1(x)-h2(x)|}。這個針對每一個任意節點來計算。

那麼我們假設有m部電影、網絡中有n個節點、有k個hash函數,根據節點的hash值和電影hash最為接近的原則,得到一個存放電影的期望值km/n。

那麼問題來了,節點如果不能保證長期在線正常的工作,這個時候就需要考慮節點的加入和退出帶來的影響。在這個環境中,網絡中的節點無法直接知道那個節點具體存放了那個電影,在搜索的時候會不斷詢問周邊節點,周邊節點再詢問周邊,直到找到所需要的信息。簡單理解分佈式系統內部有一個虛擬網絡,稱為覆蓋網絡(Overlay Network)。

一致性哈希算法設計原理

針對節點的加入和退出,一致性hash算法原則:

環形Hash空間

按照常用的hash算法來將對應的key哈希到一個具有2^32次方個桶的空間中,即0~(2^32)-1的數字空間中。現在我們可以將這些數字頭尾相連,想象成一個閉合的環形。

把數據通過一定的hash算法處理後映射到環上,每個對象通過特定的Hash函數計算出對應的key值,然後散列到Hash環上。

節點機器通過hash算法映射到環上

在採用一致性哈希算法的分佈式集群中將新的機器加入,其原理是通過使用與對象存儲一樣的Hash算法將機器也映射到環中,然後以順時針的方向計算,將所有對象存儲到離自己最近的機器中。這樣的部署環境中,hash環是不會變更的,因此,通過算出對象的hash值就能快速的定位到對應的機器中,這樣就能找到對象真正的存儲位置了。

機器的刪除

節點(機器)的刪除,如果任意出現故障被刪除了,那麼按照順時針遷移的方法,對象將會被遷移到下一個節點中,這樣僅僅是對象的映射位置發生了變化,其它的對象沒有任何的改動。

機器的增加

節點(機器)的添加,如果往集群中添加一個新的節點,通過對應的哈希算法得到KEY4,並映射到環中。

按順時針遷移的規則,那麼對象被遷移到了下一個節點中,其它對象還保持這原有的存儲位置。通過對節點的添加和刪除的分析,一致性哈希算法在保持了單調性的同時,還是數據的遷移達到了最小,這樣的算法對分佈式集群來說是非常合適的,避免了大量數據遷移,減小了服務器的的壓力。

平衡性處理

一致性哈希算法滿足了單調性和負載均衡的特性以及一般hash算法的分散性,但這還並不能當做其被廣泛應用的原由,因為還缺少了平衡性。引入“虛擬節點”( virtual node )是實際節點(機器)在 hash 空間的複製品( replica ),一實際個節點(機器)對應了若干個“虛擬節點”,這個對應個數也成為“複製個數”,“虛擬節點”在 hash 空間中以hash值排列。

  • 參考:https://blog.csdn.net/cywosp/article/details/23397179/有興趣可以看看全文,文章圖片和文字都有詳細說明。

IPFS

星際文件系統IPFS(InterPlanetary File System)是一個面向全球的、點對點的分佈式版本文件系統,目標是為了補充(甚至是取代)目前統治互聯網的超文本傳輸協議(HTTP),將所有具有相同文件系統的計算設備連接在一起。原理用基於內容的地址替代基於域名的地址,也就是用戶尋找的不是某個地址而是儲存在某個地方的內容,不需要驗證發送者的身份,而只需要驗證內容的哈希,通過這樣可以讓網頁的速度更快、更安全、更健壯、更持久。

IPFS的存儲與讀取

接下來先基礎地介紹下IPFS是怎麼進行存儲和讀取的。IPFS文件的存儲和讀取與BitTorrent上傳下載原理相似。

IPFS採用的索引結構是DHT(分佈式哈希表),數據結構是Merkle DAG(Merkle 有向無環圖)。

單文件存儲

研究過文件系統的人都知道索引和扇區這兩個概念,如:NTFS一個扇區通常是4K,真正的文件數據都是保存在扇區裡面的,找到這些扇區的方式就是建立索引(確切的說是高效的索引),IPFS也是一個文件系統,不同的是,IPFS是沒有存儲上限的,且不存在空間回收的功能。IPFS存儲文件時,如圖(沒天賦,略醜),會經歷以下幾個步驟:

1. 把單個文件拆分成若干個256KB大小的塊( block,這個就可以理解成扇區 );

2. 逐塊(block)計算block hash,hashn = hash ( blockn );

3. 把所有的block hash拼湊成一個數組,再計算一次hash,便得到了文件最終的hash,hash ( file ) = hash ( hash1……n ),並將這個 hash(file) 和block hash數組“捆綁”起來,組成一個對象,把這個對象當做一個索引結構;

4. 把block、索引結構全部上傳給IPFS節點(這裡先不介紹細節),文件便同步到了IPFS網絡了;

5. 把 Hash(file)打印出來,讀的時候用;

PS: 這裡可以看出IPFS計算文件得到的hash,其實和我們平時計算hash的方式不一樣,而且最終的結果也不一樣!

這裡還漏掉了一個小文件的處理邏輯,和NTFS等文件系統類似,小文件(小於 1KB) 的文件,IPFS會把數據內容直接和Hash(索引)放在一起上傳給IPFS節點,不會再額外的佔用一個block的大小。

本地有一個1G的大文件File1,已經同步到IPFS了,後面在這個文件File1後面追加了1K的內容,現在需要重新同步這個文件,算下來需要花費的空間應該是:1G+1G+1K;

然而,事實並非如此。IPFS在儲存數據的時候,同一份數據只存儲一次,文件是分塊(block)存儲的,hash相同的block,只會存儲一次,也就說,前面1G的內容沒有發生改變,其實IPFS並不會為這些數據分配新的空間,只會為最後1K的數據分配一個新的block,再重新上傳hash,實際佔用的空間是: 1G + 1K ;

不同的文件有很多數據是存在重複的,如不同語言字幕的電影,影音部分相同的,只有字幕部分不一樣,當兩個不同國家的人都在上傳同一部電影的時候,這些文件在分塊(block)的時候,很有可能有大部分block的hash是一致的,這些block在IPFS上也只會存儲一份,這樣一來就可能會有很多文件的索引指向同一個block,這裡就構成了前面提到的一個數據結構——Merkle DAG(Merkle 有向無環圖)。

因為所有的索引上都保存了hash,所以Merkle DAG具有以下特點(從白皮書上扒下來的):

1. 內容可尋址:所有內容都是被多重hash校驗和來唯一識別的,包括links。

2. 無法篡改:所有的內容都用它的校驗和來驗證。如果數據被篡改或損壞,IPFS會檢測到。

3. 重複數據刪除:重複內容並只存儲一次。

文件樹存儲

IPFS支持目錄結構,存儲目錄的方式很簡單:

先把目錄下所有的文件同步到IPFS網絡中去,為所有的文件hash建立一個別名,這個別名其實就是本地文件名,把hash和別名“捆綁”在一起組建成一個名為 IPFSLink 的對象;

把該目錄下所有的 IPFSLink 對象組成一個數組,對該數組計算一個目錄hash,並將數組和目錄hash拼成一個結構體,同步到IPFS網絡;

如果上層還有目錄結構,則為目錄hash建立一個別名(就是目錄名),把目錄hash和別名“捆綁”在一起組建成一個 IPFSLink 的對象,重複從步驟2開始執行;

把目錄hash打印出來,讀取的時候用;

由上可以看出,對於IPFS而言,存儲目錄和文件其實是一樣的處理方式,IPFS甚至根本沒有關心節點想要存儲的是一個目錄還是一個文件。

單文件讀取

IPFS取文件的方式,就比較簡單了,就是存儲方式的一個逆推過程:

根據hash搜索該hash的索引結構,即找到該文件hash 的 block hash數組(這一步由IPFS網絡完成,是曠工該乾的事情),下載下來;此時已經得到了 block 的索引,根據block hash,搜索block所在的節點位置,下載下來;本地拼裝block:根據block hash數組的順序,把文件拼湊好。block的下載是IPFS的核心,這中間涉及到很多複雜的技術細節,因為個人能力有限,這裡沒有展開討論,只是先一筆帶過。希望不會誤導新入門的讀者,以為IPFS就只幹了這麼點事情!

文件樹讀取

目錄的讀取也是目錄存儲過程的逆推:

根據hash搜索該hash的索引結構,找到該目錄的 IPFSLink 對象數組,即目錄下的子列表;

遍歷數組,如果IPFSLink對象是文件,則取出文件的hash下載該文件;

如果IPFSLink對象是目錄,取出目錄hash,重新從步驟1開始執行。

大致介紹IPFS文件存儲於讀取,磨鏈社區-陳狍子,原文鏈接:http://mochain.info/wordpress/index.php/2018/03/12/qian_xi_ipfs_de_cun_chu_yu_du_qu/


分享到:


相關文章: