什麼是 IPFS 分散式檔案系統?
IPFS 是一個分散式檔案系統 (官方網站),中文翻譯為星際檔案系統,名字聽起來很酷炫很科幻。在 IPFS 這個檔案系統中,檔案被儲存在由網路上很多節點所組成的 IPFS 系統。每一個檔案都可以被計算出唯一的 Hash 值,其中透過 DHT 演算法可以在眾多的網路節點上進行定位,概念就像一大堆檔案散佈在一大堆節點中,取檔案的時候透過 DHT 快速找到檔案的位置進行存取。這樣的機制其實已經有很成熟的實踐,像是下載檔案常用的 BitTorrent,也是一樣的工作原理。
在 IPFS 中,沒辦法保證傳上去的檔案永久都可以被取得,概念就跟 BT 種子死亡的意思一樣,一旦整個網路沒有了任何一個節點有這個檔案的副本 (Cache),那麼你即使有了 Hash 也無法取得檔案內容。為了解決這個問題,在區塊鏈 2017 最大的 ICO 項目 Filecoin 就是透過數位貨幣獎勵來供養這些提供 Filecoin IPFS 網路的節點,好讓檔案在分散式檔案系統中可以被完整 (永久!?) 保存。雖然 Filecoin 底層使用了 IPFS,但是 Filecoin 使用的 DHT 網路與 IPFS 公用網路是不同的,Filecoin 未來有研究再分享了。
IPFS 使用教學
我們先看看怎麼玩吧!從 https://dist.ipfs.io/#go-ipfs 這裡可以下載不同作業系統版本的 IPFS 主程式,這裡測試的環境是 Ubuntu 64,解壓縮後直接安裝,如下:
wget https://dist.ipfs.io/go-ipfs/v0.4.17/go-ipfs_v0.4.17_linux-amd64.tar.gz tar -zxvf go-ipfs_v0.4.17_linux-amd64.tar.gz cd go-ipfs sudo ./install.sh cd .. rm go-ipfs_v0.4.17_linux-amd64.tar.gz rm -rf go-ipfs
初始化 IPFS
ipfs init
init 之後會在 Home 建立一個 .ipfs 目錄,並且放置 IPFS 相關檔案與 Cache,如下:
輸入「ipfs id」可以顯示 IPFS Node 相關資訊,包含每一個 Node 唯一的 Peer ID,如下:
我們先嘗試建立一個檔案,透過 ipfa add 放進 IPFS 檔案系統中 (又是 Hello World):
echo 'hello world!' > my-file.txt
ipfs add my-file.txt
執行 ipfs add 後我們可以得到檔案在 IPFS 中的 Object Hash,如上圖「QmeV1kwh3333bsnT6YRfdCRrSgUPngKmAhhTa4RrqYPbKT」,這個 File Hash 在 IPFS 網路中是唯一的,而且絕對不會重複,如果重複,你可以再做一次(跟重開機的概念一樣)。接下來我們可以透過 ipfs cat 取得這個檔案的內容,如下:
ipfs cat QmeV1kwh3333bsnT6YRfdCRrSgUPngKmAhhTa4RrqYPbKT
在沒有連上 IPFS 公用網路以前,檔案就只是存在自己的 cache 中,如果其他節點想要透過取得 Hash 取得檔案,是行不通的。要讓其他節點取得內容,必須連先上 IPFS 網路,連上公用 IPFS 命令如下:
ipfs daemon
啟動後可以開啟瀏覽器輸入「http://localhost:5001」,點擊左邊的「Connections」可以出現一個很炫的介面,會顯示整個銀河系 (星際) 中所執行的節點,顯示的當下有 796 個節點。如下:
我們到另一台 IPFS Node,這是一個 ARM Base 的環境,先透過 tmux 開啟兩個畫面,一個輸入「ipfs daemon」連上 DHT 網路,另一個用來操作。我們嘗試在另一個節點透過 IPFS 抓前面剛剛新增的檔案,如下:
ipfs cat QmeV1kwh3333bsnT6YRfdCRrSgUPngKmAhhTa4RrqYPbKT
畫面顯示 hello world! 檔案內容,如下:
看起來 IPFS 工作的還算順利,沒有遇到什麼問題,這只是最基本的操作。
建立自己的私有 IPFS 網路
在公用網路測試有時候會慢慢的,那要如何建立自己的私人 DHT 網路呢?要建立自己的 IPFS 網路必須要先產生一對密鑰,我們可以透過 ipfs-swarm-key-gen 這個程式來產生。安裝方式如下:
先安裝 Go (以 Ubuntu 為範例)
sudo apt-get install golang-go
export GOPATH=$HOME/golang
下載 ipfs-swarm-key-gen
go get -u github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm-key-gen
產生 Key
~/golang/bin/ipfs-swarm-key-gen > ~/.ipfs/swarm.key
然後複製 swarm.key 這個檔案到其他要一起加入的節點,覆蓋每個節點中的 ~/.ipfs/swarm.key 檔案,這樣 Daemon 啟動的時候才會使用這個 key 加入我們私有的 IPFS 網路。
在每一個節點中的 ~/.ipfs/config 檔案裡面,預設一開始描述的 bootstrap 都是公有雲的位置,由於我們是要建立自己的私有雲,因此先透過以下命令清除 bootstrap 設定:
ipfs bootstrap rm --all
這裡我們有兩個節點分別為 A 與 B,我們僅需要在 A 節點加入 B 節點的資訊即可。如下:
ipfs bootstrap add /ip4/192.168.20.246/tcp/4001/ipfs/QmNtXfQftbXjZm8BZNexn9N2Dwhrj2CiYHvcpdNXNDkoNj
一但連上 IPFS 網路,節點之間就會互相溝通,交互傳遞鄰近的 Peer 資訊,我們可以由以下的命令查詢每個 Node 的連線狀態:
ipfs swarm peers
接下來的操作就跟平常連上 IPFS 公網的方式一樣囉。
透過 pin 保留檔案副本
各位有沒有發現,IPFS 其實提供了一個分散式檔案路由的機制,如果檔案的源頭斷了,似乎也無法取得檔案內容。各位可以試試把執行 ipfs add 源頭 Node 關閉,然後在其他節點執行 ipfs repo gc 刪除 Cache 中的檔案,然後重新 ipfs cat 試看看,就會發現取不到了,一旦重新打開檔案源頭的 Node 就正常了。雖然分散,但是聽起來不是很保險,那我們能不能在 IPFS 網路中建立檔案副本呢?當然可以,如果要在自己的節點保留檔案資料,不因為 ipfs repo gc 被刪除或檔案來源無法連線造成檔案無法取得,可以使用 pin 指令將 File Object 儲存到磁碟中。
我們來測試一下,在 Node A 新增一支檔案,透過 ipfs add 放上網路 (使用 ipfs add 檔案會自動 Pinned),在同一個節點可以透過 ipfs pin ls 調閱目前的 pin 狀態是 recursive (說明) 表示 Pinned 不會因為 GC 而被刪除。如下:
接著我們在另一台 Node B 嘗試先 ipfs cat 取得檔案內容,然後輸入 ipfs pin ls 看看狀態,這時候會發現檔案沒有被 Pinned,如下:
如果這時候把 Node A 關閉,Node B 在執行 GC 後便無法取得檔案內容。
但我們想要做的是在 Node B 也保留副本,這樣如果 Node A 掛了,至少還有一份可以存取。要偷偷存一份很簡單,透過 ipfs pin add 指令即可,File Object Pinned 之後,即使 Node A 關閉 Node B GC,一樣可以取得檔案,因為檔案已經儲存在 local storage 中囉。測試如下:
IPFS 其實在搜尋與定位檔案的時候不算快,組織一個自己獨立的分散式檔案系統還算簡單。目前正在思考如何作到自動備援的問題,另一個火紅的 CEPH Object Storage 是透過 CRUSH Map 來實現檔案副本的機制,但一樣的機制如果用在時常變動且不穩定的 IPFS Node 架構我想也不適合。如果可以找到一個自動分派副本的方法,IPFS 應該蠻方便的,另一個 Filecoin 就有針對檔案的持久性做了改進 (白皮書描述),IPFS 其中還有 mfs 與 IPNS 沒有介紹,今天就先介紹到這裡,下次見。啊掰~