【深度知識】從數(shù)據(jù)的角度帶你深入了解IPFS

一乘碑、概述

IPFS 和區(qū)塊鏈有著非常緊密的聯(lián)系跪解, 隨著區(qū)塊鏈的不斷發(fā)展悔常,對數(shù)據(jù)的存儲需求也越來越高怀吻, 由于性能和成本的限制瞬浓,現(xiàn)有的區(qū)塊鏈設(shè)計(jì)方案大部分都選擇了把較大的數(shù)據(jù)存儲在鏈外,通過對數(shù)據(jù)進(jìn)行加密蓬坡, 哈希運(yùn)算等手段來防止數(shù)據(jù)被篡改猿棉, 在區(qū)塊鏈上只引用所存數(shù)據(jù)的hash 值, 從而滿足業(yè)務(wù)對數(shù)據(jù)的存儲需求。 本文從IPFS 的底層設(shè)計(jì)出發(fā)屑咳, 結(jié)合源代碼萨赁, 分析了IPFS 的一些技術(shù)細(xì)節(jié)。 由于IPFS還在不斷更新中兆龙, 文中引用的部分可能和最新代碼有所出入杖爽。

閱讀本文需要讀者

  • 了解網(wǎng)絡(luò)編程
  • 了解分布式存儲
  • 了解基本的區(qū)塊鏈知識

二、什么是IPFS紫皇?

維基百科上是這樣解釋的:是一個旨在創(chuàng)建持久且分布式存儲和共享文件的網(wǎng)絡(luò)傳輸協(xié)議慰安。

上面的解釋稍顯晦澀, 我的理解是:

  1. 首先它是一個FS(文件系統(tǒng))

  2. 其次它支持點(diǎn)對點(diǎn)傳輸

既然是文件系統(tǒng)聪铺, 那它和普通的文件系統(tǒng)有什么區(qū)別呢化焕? 有以下幾點(diǎn)區(qū)別:

  • 存儲方式: 它是分布式存儲的, 為了方便傳輸,文件被切分成多個block, 每個block 通過hash運(yùn)算得到唯一的ID铃剔, 方便在網(wǎng)絡(luò)中進(jìn)行識別和去重撒桨。 考慮到傳輸效率, 同一個block 可能有多個copy, 分別存儲在不同的網(wǎng)絡(luò)節(jié)點(diǎn)上键兜。
  • 內(nèi)容尋址方式: 每個block都有唯一的ID凤类,我們只需要根據(jù)節(jié)點(diǎn)的ID 就可以獲取到它所對應(yīng)的block。

那么問題來了普气, 既然文件被切分成了多個block谜疤,如何組織這些block 數(shù)據(jù),組成邏輯上的文件呢? 在IFPS中采用的merkledag, 下面是 merkledag的一個示意圖:

簡單來說, 就是2種數(shù)據(jù)結(jié)構(gòu)merkle 和DAG(有向無環(huán)圖)的結(jié)合茎截, 通過這種邏輯結(jié)構(gòu)苇侵, 可以滿足:

  • 內(nèi)容尋址: 使用hash ID來唯一識別一個數(shù)據(jù)塊的內(nèi)容
  • 防篡改: 可以方便的檢查哈希值來確認(rèn)數(shù)據(jù)是否被篡改
  • 去重: 由于內(nèi)容相同的數(shù)據(jù)塊哈希是相同的,可以很容去掉重復(fù)的數(shù)據(jù)企锌,節(jié)省存儲空間

確定了數(shù)據(jù)模型后, 接下來要做的事: 如何把數(shù)據(jù)分發(fā)到不同的網(wǎng)絡(luò)節(jié)點(diǎn)上于未, 達(dá)到分布式存儲和共享的目的撕攒? 我們先思考一下, 通過網(wǎng)絡(luò)烘浦,比如HTTP抖坪, 訪問某個文件的步驟,首先我們要知道存儲這個文件的服務(wù)器地址闷叉, 然后我們需要知道這個文件對應(yīng)的ID擦俐, 比如文件名。前者我們可以抽象成網(wǎng)絡(luò)節(jié)點(diǎn)尋址握侧, 后者我們抽象成文件對象尋址蚯瞧; 在IPFS中, 這兩種尋址方式使用了相同的算法品擎, KAD, 介紹KAD算法的文章很多埋合,這里不贅述, 只簡單說明一下核心思想:

KAD 最精妙之處就是使用XOR 來計(jì)算ID 之間的距離萄传,并且統(tǒng)一了節(jié)點(diǎn)ID 和 對象ID的尋址方式甚颂。 采用 XOR(按比特異或操作)算法計(jì)算 key 之間的“距離”。

這種做法使得它具備了類似于“幾何距離”的某些特性(下面用 ⊕ 表示 XOR)

  • (A ⊕ B) == (B ⊕ A) XOR 符合“交換律”秀菱,具備對稱性振诬。
  • (A ⊕ A) == 0 反身性,自身距離為零
  • (A ⊕ B) > 0 【不同】的兩個 key 之間的距離必大于零
  • (A ⊕ B) + (B ⊕ C) >= (A ⊕ C) 三角不等式

通過KAD算法衍菱,IPFS 把不同ID的數(shù)據(jù)塊分發(fā)到與之距離較近的網(wǎng)絡(luò)節(jié)點(diǎn)中赶么,達(dá)到分布式存儲的目的。

通過IPFS獲取文件時梦碗,只需要根據(jù)merkledag, 按圖索驥禽绪,根據(jù)每個block的ID, 通過KAD算法從相應(yīng)網(wǎng)絡(luò)節(jié)點(diǎn)中下載block數(shù)據(jù), 最后驗(yàn)證是否數(shù)據(jù)完整洪规, 完成拼接即可印屁。

下面我們再從技術(shù)實(shí)現(xiàn)的角度做更深入的介紹。

三斩例、IPFS的系統(tǒng)架構(gòu)

image

我們先看一下IPFS的系統(tǒng)架構(gòu)圖雄人, 分為5層:

  • 一層為naming, 基于PKI的一個命名空間;
  • 第二層為merkledag础钠, IPFS 內(nèi)部的邏輯數(shù)據(jù)結(jié)構(gòu)恰力;
  • 第三層為exchange, 節(jié)點(diǎn)之間block data的交換協(xié)議;
  • 第四層為routing, 主要實(shí)現(xiàn)節(jié)點(diǎn)尋址和對象尋址旗吁;
  • 第五層為network, 封裝了P2P通訊的連接和傳輸部分踩萎。

站在數(shù)據(jù)的角度來看, 又可以分為2個大的模塊:

  • IPLD( InterPlanetary Linked Data) 主要用來定義數(shù)據(jù)很钓, 給數(shù)據(jù)建模香府;
  • libp2p解決的是數(shù)據(jù)如何傳輸?shù)膯栴}。

下面分別介紹IFPS 中的2個主要部分IPLD 和 libP2P码倦。

1.IPLD

通過hash 值來實(shí)現(xiàn)內(nèi)容尋址的方式在分布式計(jì)算領(lǐng)域得到了廣泛的應(yīng)用企孩, 比如區(qū)塊鏈, 再比如git repo袁稽。 雖然使用hash 連接數(shù)據(jù)的方式有相似之處勿璃, 但是底層數(shù)據(jù)結(jié)構(gòu)并不能通用, IPFS 是個極具野心的項(xiàng)目推汽, 為了讓這些不同領(lǐng)域之間的數(shù)據(jù)可互操作补疑, 它定義了統(tǒng)一的數(shù)據(jù)模型IPLD, 通過它民泵, 可以方便地訪問來自不同領(lǐng)域的數(shù)據(jù)癣丧。

image

前面已經(jīng)介紹數(shù)據(jù)的邏輯結(jié)構(gòu)是用merkledag表示的, 那么它是如何實(shí)現(xiàn)的呢栈妆? 圍繞merkledag作為核心胁编, 它定義了以下幾個概念:

  • merkle link 代表dag 中的邊
  • merkel-dag 有向無環(huán)圖
  • merkle-path 訪問dag節(jié)點(diǎn)的類似unix path的路徑
  • IPLD data model 基于json 的數(shù)據(jù)模型
  • IPLD serialized format 序列化格式
  • canonical 格式: 為了保證同樣的logic object 總是序列化為一個同樣的輸出, 而制定的確定性規(guī)則

圍繞這些定義它實(shí)現(xiàn)了下面幾個components

  • CID 內(nèi)容ID
  • data model 數(shù)據(jù)模型
  • serialization format 序列化格式
  • tools & libraries 工具和庫
  • IPLD selector 類似CSS 選擇器鳞尔, 方便選取dag中的節(jié)點(diǎn)
  • IPLD transformation 對dag 進(jìn)行轉(zhuǎn)換計(jì)算

我們知道嬉橙,數(shù)據(jù)是多樣性的,為了給不同的數(shù)據(jù)建模寥假, 我們需要一種通用的數(shù)據(jù)格式市框, 通過它可以最大程度地兼容不同的數(shù)據(jù), IPFS 中定義了一個抽象的集合糕韧, multiformat, 包含multihash枫振、multiaddr、multibase萤彩、multicodec粪滤、multistream幾個部分。

(一)multihash

自識別hash, 由3個部分組成雀扶,分別是:hash函數(shù)編碼杖小、hash值的長度和hash內(nèi)容, 下面是個簡單的例子:

image

這種設(shè)計(jì)的最大好處是非常方便升級,一旦有一天我們使用的hash 函數(shù)不再安全了予权, 或者發(fā)現(xiàn)了更好的hash 函數(shù)昂勉,我們可以很方便的升級系統(tǒng)。

(二)multiaddr

自描述地址格式扫腺,可以描述各種不同的地址

image

(三)multibase

multibase 代表的是一種編碼格式岗照, 方便把CID 編碼成不同的格式, 比如這里定義了2進(jìn)制斧账、8進(jìn)制谴返、10進(jìn)制、16進(jìn)制咧织、也有我們熟悉的base58btc 和 base64編碼。

image

(四)multicodec

mulcodec 代表的是自描述的編解碼籍救, 其實(shí)是個table习绢, 用1到2個字節(jié)定了數(shù)據(jù)內(nèi)容的格式, 比如用字母z表示base58btc編碼蝙昙, 0x50表示protobuf 等等闪萄。

image

五)multistream

multistream 首先是個stream, 它利用multicodec奇颠,實(shí)現(xiàn)了自描述的功能败去, 下面是基于一個javascript 的例子; 先new 一個buffer 對象烈拒, 里面是json對象圆裕, 然后給它加一個前綴protobuf, 這樣這個multistream 就構(gòu)造好了, 可以通過網(wǎng)絡(luò)傳輸荆几。在解析時可以先取codec 前綴吓妆,然后移除前綴, 得到具體的數(shù)據(jù)內(nèi)容吨铸。

image

結(jié)合上面的部分行拢, 我們重點(diǎn)介紹一下CID。
CID 是IPFS分布式文件系統(tǒng)中標(biāo)準(zhǔn)的文件尋址格式诞吱,它集合了內(nèi)容尋址舟奠、加密散列算法和自我描述的格式, 是IPLD 內(nèi)部核心的識別符。目前有2個版本房维,CIDv0 和CIDv1沼瘫。

CIDv0是一個向后兼容的版本,其中:

  • multibase 一直為 base58btc
  • multicodec 一直為 protobuf-mdag
  • version 一直為 CIDv0
  • multihash 表示為cidv0 ::= <multihash-content-address>

為了更靈活的表述ID數(shù)據(jù)握巢, 支持更多的格式晕鹊, IPLD 定義了CIDv1,CIDv1由4個部分組成:

image
  • multibase
  • version
  • multicodec
  • multihash

IPLD 是IPFS 的數(shù)據(jù)描述格式, 解決了如何定義數(shù)據(jù)的問題溅话, 下面這張圖是結(jié)合源代碼整理的一份邏輯圖晓锻,我們可以看到上面是一些高級的接口, 比如file, mfs, fuse 等飞几。 下面是數(shù)據(jù)結(jié)構(gòu)的持久化部分砚哆,節(jié)點(diǎn)之間交換的內(nèi)容是以block 為基礎(chǔ)的, 最下面就是物理存儲了屑墨。比如block 存儲在blocks 目錄躁锁, 其他節(jié)點(diǎn)之間的信息存儲在leveldb, 還有keystore, config 等卵史。

image

2.數(shù)據(jù)如何傳輸呢战转?

接下來我們介紹libP2P, 看看數(shù)據(jù)是如何傳輸?shù)囊郧ibP2P 是個模塊化的網(wǎng)絡(luò)協(xié)議棧槐秧。

image

做過socket編程的小伙伴應(yīng)該都知道, 使用raw socket 編程傳輸數(shù)據(jù)的過程忧设,無非就是以下幾個步驟:

  1. 獲取目標(biāo)服務(wù)器地址
  2. 和目標(biāo)服務(wù)器建立連接
  3. 握手協(xié)議
  4. 傳輸數(shù)據(jù)
  5. 關(guān)閉連接

libP2P 也是這樣刁标,不過區(qū)別在于它把各個部分都模塊化了, 定義了通用的接口址晕, 可以很方便的進(jìn)行擴(kuò)展膀懈。

(一)架構(gòu)圖

image

由以下幾個部分組成,分別是:

  • Peer Routing
  • Swarm (傳輸和連接)
  • Distributed Record Store
  • Discovery

下面我們對它們做分別介紹, 我們先看關(guān)鍵的路由部分谨垃。

(二)Peer Routing

libP2P定義了routing 接口启搂,目前有2個實(shí)現(xiàn),分別是KAD routing 和 MDNS routing, 擴(kuò)展很容易乘客, 只要按照接口實(shí)現(xiàn)相應(yīng)的方法即可狐血。

ipfs 中的節(jié)點(diǎn)路由表是通過維護(hù)多個K-BUCKET來實(shí)現(xiàn)的, 每次新增節(jié)點(diǎn)易核, 會計(jì)算節(jié)點(diǎn)ID 和自身節(jié)點(diǎn)ID 之間的common prefix, 根據(jù)這個公共前綴把節(jié)點(diǎn)加到對應(yīng)的KBUCKET 中, KBUCKET 最大值為20匈织, 當(dāng)超出時,再進(jìn)行拆分牡直。

image

更新路由表的流程如下:

image

除了KAD routing 之外缀匕, IPFS 也實(shí)現(xiàn)了MDNS routing, 主要用來在局域網(wǎng)內(nèi)發(fā)現(xiàn)節(jié)點(diǎn), 這個功能相對比較獨(dú)立, 由于用到了多播地址碰逸, 在一些公有云部署環(huán)境中可能無法工作乡小。

(三)Swarm(傳輸和連接)

swarm 定義了以下接口:

  • transport 網(wǎng)絡(luò)傳輸層的接口
  • connection 處理網(wǎng)絡(luò)連接的接口
  • stream multiplex 同一connection 復(fù)用多個stream的接口

下面我們重點(diǎn)看下是如何動態(tài)協(xié)商stream protocol 的,整個流程如下:

image
  1. 默認(rèn)先通過multistream-select 完成握手
  2. 發(fā)起方嘗試使用某個協(xié)議饵史, 接收方如果不接受满钟, 再嘗試其他協(xié)議胜榔, 直到找到雙方都支持的協(xié)議或者協(xié)商失敗。

另外為了提高協(xié)商效率湃番, 也提供了一個ls 消息夭织, 用來查詢目標(biāo)節(jié)點(diǎn)支持的全部協(xié)議。

(四)Distributed Record Store

record 表示一個記錄吠撮, 可以用來存儲一個鍵值對尊惰,比如ipns name publish 就是發(fā)布一個objectId 綁定指定 node id 的record 到ipfs 網(wǎng)絡(luò)中, 這樣通過ipns 尋址時就會查找對應(yīng)的record, 再解析到objectId, 實(shí)現(xiàn)尋址的功能泥兰。

(五)Discovery

目前系統(tǒng)支持3種發(fā)現(xiàn)方式弄屡, 分別是:

  • bootstrap 通過配置的啟動節(jié)點(diǎn)發(fā)現(xiàn)其他的節(jié)點(diǎn)
  • random walk 通過查詢隨機(jī)生成的peerID, 從而發(fā)現(xiàn)新的節(jié)點(diǎn)
  • mdns 通過multicast 發(fā)現(xiàn)局域網(wǎng)內(nèi)的節(jié)點(diǎn)

最后總結(jié)一下源代碼中的邏輯模塊:

image

從下到上分為5個層次:

  • 最底層為傳輸層鞋诗, 主要封裝各種協(xié)議膀捷, 比如TCP,SCTP削彬, BLE担孔, TOR 等網(wǎng)絡(luò)協(xié)議
  • 傳輸層上面封裝了連接層,實(shí)現(xiàn)連接管理和通知等功能
  • 連接層上面是stream 層吃警, 實(shí)現(xiàn)了stream的多路復(fù)用
  • stream層上面是路由層
  • 最上層是discovery, messaging以及record store 等

四、總結(jié)

本文從定義數(shù)據(jù)和傳輸數(shù)據(jù)的角度分別介紹了IPFS的2個主要模塊IPLD 和 libP2P:

  • IPLD 主要用來定義數(shù)據(jù)啄育, 給數(shù)據(jù)建模
  • libP2P 解決數(shù)據(jù)傳輸問題

這兩部分相輔相成酌心, 雖然都源自于IPFS項(xiàng)目,但是也可以獨(dú)立使用在其他項(xiàng)目中挑豌。

IPFS的遠(yuǎn)景目標(biāo)就是替換現(xiàn)在瀏覽器使用的 HTTP 協(xié)議安券, 目前項(xiàng)目還在迭代開發(fā)中, 一些功能也在不斷完善氓英。為了解決數(shù)據(jù)的持久化問題侯勉, 引入了filecoin 激勵機(jī)制, 通過token激勵铝阐,讓更多的節(jié)點(diǎn)加入到網(wǎng)絡(luò)中來址貌,從而提供更穩(wěn)定的服務(wù)。

本文轉(zhuǎn)載自《從數(shù)據(jù)的角度帶你深入了解IPFS》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末徘键,一起剝皮案震驚了整個濱河市练对,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吹害,老刑警劉巖螟凭,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異它呀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)班眯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門粹胯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奢人,你說我怎么就攤上這事⊥粲担” “怎么了达传?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長迫筑。 經(jīng)常有香客問我宪赶,道長,這世上最難降的妖魔是什么脯燃? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任搂妻,我火速辦了婚禮,結(jié)果婚禮上辕棚,老公的妹妹穿的比我還像新娘欲主。我一直安慰自己,他們只是感情好逝嚎,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布扁瓢。 她就那樣靜靜地躺著,像睡著了一般补君。 火紅的嫁衣襯著肌膚如雪引几。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天挽铁,我揣著相機(jī)與錄音伟桅,去河邊找鬼。 笑死叽掘,一個胖子當(dāng)著我的面吹牛楣铁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播更扁,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼盖腕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了疯潭?” 一聲冷哼從身側(cè)響起赊堪,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竖哩,沒想到半個月后哭廉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡相叁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年遵绰,在試婚紗的時候發(fā)現(xiàn)自己被綠了辽幌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡椿访,死狀恐怖乌企,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情成玫,我是刑警寧澤加酵,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站哭当,受9級特大地震影響猪腕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钦勘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一陋葡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彻采,春花似錦腐缤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至特笋,卻和暖如春绍在,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雹有。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留臼寄,地道東北人霸奕。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像吉拳,于是被迫代替她去往敵國和親质帅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容