FastDFS 海量小文件存儲解決之道

vivo 互聯網服務器團隊 - Zhou Changqing

一、FastDFS 原理介紹

FastDFS 是一個 C 語言實現的開源輕量級分佈式文件系統 。

支持 Linux、FreeBSD、AID 等 Unix 系統,解決了大容量的文件存儲和高併發訪問問題,文件存取實現了負載均衡,適合存儲 4KB~500MB 之間的小文件,特別適合以文件爲載體的在線服務,如圖片、視頻、文檔等等。

二、FastDFS 架構

FastDFS 由三個部分構成:

圖片

2.1 Tracker Server (跟蹤服務器)

**Tracker Server (跟蹤服務器) ** 主要是做調度工作,起到負載均衡的作用。

(1)【服務註冊】 管理 StorageServer 存儲集羣,StorageServer 啓動時,會把自己註冊到 TrackerServer 上,並且定期報告自身狀態信息,包括磁盤剩餘空間、文件同步狀況、文件上傳下載次數等統計信息。

(2)【服務發現】 Client 訪問 StorageServer 之前,必須先訪問 TrackerServer,動態獲取到 StorageServer 的連接信息,最終數據是和一個可用的 StorageServer 進行傳輸。

(3)【負載均衡】

2.2 Tracker Server (跟蹤服務器)

**Tracker Server (跟蹤服務器) ** 主要提供容量和備份服務。

【分組管理】 以 Group 爲單位,每個 Group 包含多臺 Storage Server,數據互爲備份,存儲容量以 Group 內容量最小的 storage 爲準,已 Group 爲單位組織存儲方便應用隔離、負載均衡和副本數據定製。

缺點: Group 容量受單機存儲容量的限制,數據恢復只能依賴 Group 其他機器重新同步。

【數據同步】 文件同步只能在 Group 內的 Storage Server 之間進行,採用 push 方式,即源服務器同步給目標服務器。源服務器讀取 binlog 文件,將文件內容解析後,按操作命令發送給目標服務器,有目標服務按命令進行操作。

三、上傳下載流程

3.1 上傳流程解析

圖片

3.1.1 選擇 Tracker Server

集羣中的 tracker 之間都是對等的,客戶端在上傳文件時可任意選擇一個 tracker 即可。

3.1.2 分配 Group、Stroage Server 和 storage path(磁盤或者掛載點)

tracker 接收到上傳請求時會先給該文件分配一個可以存儲的 Group ,然後在 Group 中分配一個 Storage Server 給客戶端,最後在接收到客戶端寫文件請求時,Storage Server 會分配一個數據存儲目錄並寫入。

(該過程中的分配策略詳見:【負載均衡】)

3.1.3 生成 file_id 寫入並返回

Storage 會生成一個 file_id 來作爲當前文件名,file_id 採用 base64 編碼,包含:源 storage server ip、文件創建時間、文件大小、文件 CRC32 校驗碼 和 隨機數。每個存儲目錄下 有兩個 256*256 個子目錄。

Storage 會根據 file_id 進行兩次 hash 路由到其中一個子目錄中。

最後以 file_id 爲文件名存儲文件到該子目錄下並返回文件路徑給客戶端。

最終文件存儲路徑:

分組 | 磁盤 | 子目錄 | 文件名

group1/M00/00/89/eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.apk

3.2  下載流程解析

圖片

3.2.1 解析路徑並路由

tracker 接收 client 發送的下載請求時,tracker 從文件名中解析出 Group、大小、創建時間等信息,然後根據 Group 選擇一個 storage server 返回。

3.2.2 校驗讀取並返回

客戶端和 Storage Server 建立鏈接,校驗文件是否存在,最終返回文件數據。

缺點: Group 之間文件同步是異步進行的,可能上傳的文件還未同步到當前訪問的 Storage Server 這臺機器上或者延遲原因,將導致下載文件出現 404。所以引入 nginx_fastdfs_module 可以很好的解決同步和延遲問題。

3.3 引入 fastdfs_nginx_module 組件後的下載架構

圖片

FastDFS Nginx Module 功能介紹

(1)【防盜鏈檢查】

利用 FastDFS nginx 擴展功能動態生成 token,設置 http.conf 配置。

【token 生成算法】:md5(fileid_without_group + privKey + ts) 同時 ts 沒有超過 ttl 範圍。

服務器會自動根據 token,st 以及設置的祕鑰來驗證合法性。訪問鏈接形式如:

http://localhost/G1/M00/00/01/wKgBD01c15nvKU1cAABAOeCdFS466570.jpg?token=b32cd06a53dea4376e43d71cc882f9cb&ts=1297930137

(2)【文件元數據解析】

根據 file_id 獲取元數據信息, 包括: storage ip,文件路徑,名稱,大小 等。

(3)【文件訪問路由】

因文件的 file_Id 包含了上傳文件時的源 Storage Server IP ,所以在獲取不到本機下的文件時(未同步或者延遲情況下)FastDFS 擴展組件,會根據源服務器 IP 來重定向或者代理方式獲取文件。

四、同步機制

4.1 同步規則

同步只發生在本組的 Storage Server 之間。

源頭數據才需要同步,備份數據不需要再次同步。

新增 Storage Server 時,會由已有一臺 Storage Server 將已有的所有數據(源頭數據和備份數據)同步給新增服務器。

4.2 Binlog 複製

FastDFS 文件同步採用 binlog 異步複製方式,Storage Server 使用 binlog 文件記錄文件上傳、刪除等操作,根據 Binlog 進行文件同步。Binlog 中只記錄文件 ID 和操作,不記錄文件內容 .binlog 格式如下:

時間戳 | 操作類型 | 文件名

1490251373 C M02/52/CB/

CtAqWVjTbm2AIqTkAAACd_nIZ7M797.jpg

操作類型(部分):

4.3 同步流程

圖片

新增 Storage Server 後,組內其他 Storage Server 服務器會啓動同步線程,在 tracker 的協調下向新增服務器發起全量和增量同步操作。

(1)Storage C 啓動後向 tracker 上報所屬 group、ip、port、版本號、存儲目錄數、子目錄數、啓動時間、老數據是否同步完成,當前狀態等信息。

(2)tracker 收到 Storage C 加入申請請求後,更新本地 storage list,返回給 C,並適時同步給 A、B。

(3)storage C 向 tracker 申請同步請求,響應後變更自身狀態爲 WAIT_SYNC。

(3)storage A 和 B 在心跳週期內從同步到的新 storage list 發現沒有 C,則啓動同步線程,先向 tracker 發起同步申請

(TRACKER_PROTO_CMD_STORAGE_SYNC_SRC_REQ),tracker 會把同步源 IP 級同步時間戳返回給 A 和 B, 如果源 IP 和自己本地 IP 一致,則標記自己作爲同步源用來做老數據同步(全量同步源),如果不一致,則標記自己作爲增量同步源(只有在 C 節點狀態爲 Active 時才同步)。該決策是由 tracker 選擇產生的,不可 A、B 同時作爲同步源,同時同步給 C。

(3)同步源(假設是 storage A)以 .mark 爲後綴的文件記錄目標機器同步信息,並上報變更 storage C 狀態爲 SYNCING。

(4)從 / data.sync 目錄下讀取 binlog.index 中的,binlog 文件 Id,binlog.000 讀取逐行讀取,進行解析.(詳見上面 binlog 內格式) 發送數據給 storage C ,C 接收並保存。

(5)數據同步過程中 storage C 的狀態變更過程 OFFLINE->ONLINE->ACTIVE。ACTIVE 是最終狀態,表示 storage C 已對外提供服務。

五、文件存儲

5.1 LOSF 問題

小文件存儲(LOSF)面臨的問題:

針對小文件存儲問題,FastDFS 提供了文件合併解決方案。FastDFS 默認創建大文件爲 64M,大文件可以存儲很多小文件,容納一個小文件的空間叫 slot,solt 最小 256 字節,最大 16M。小於 256 字節當 256 字節存儲,超過 16M 文件單獨存儲。

5.2 存儲方式

(1)【默認存儲方式】 未開啓合併 ,FastDFS 生成的 file_id 和磁盤上實際存儲的文件一一對應。

(2)【合併存儲方式】 多個 file_id 對應文件被存儲成了一個大文件 。trunk 文件名格式:/fastdfs/data/00/000001 文件名從 1 開始遞增。而生成的 file_id 更長,會新增 16 個字節額外內容用來保存偏移量等信息。

如下:

5.3 存儲空間管理

(1)【Trunk Server】 由 tracker leader 在一組 Storage Server 選擇出來的,並通知給該組內所有 Storage Server,負責爲該組內所有 upload 操作分配空間。

(2)【空閒平衡樹】 trunk server 會爲每個 store_path 構造一個空閒平衡樹,相同大小的空閒塊保存在鏈表中,每次上傳請求時會到根據上傳的文件大小到平衡樹中查找獲取大於或者接近的空閒塊,然後從空閒塊中分割出多餘的作爲新的空閒塊,重新加入平衡樹。如果找不到則會重建一個新的 trunk 文件,並加入到平衡樹中。該分配過程即是一個維護空閒平衡樹的過程。

(3)【Trunk Binlog】 開啓了合併存儲後,Trunk Server 會多出一個 TrunkBinlog 同步。TrunkBinlog 記錄了 TrunkServer 所有分配與回收的空閒塊操作,並由 Trunk Server 同步給同組中其他 storage server。

TrunkBinlog 格式如下:

時間戳 | 操作類型 | store_path_index | 

sub_path_high| sub_path_low | 

file.id| offset | 

size 1410750754 A 0 0 0 1 0 67108864

各字段含義如下: 

六、文件去重

FastDFS 不具備文件去重能力,必須引入 FastDHT 來配合完成。FastDHT 是一個鍵值對的高效分佈式 hash 系統,底層採用 Berkeley DB 來做數據庫持久化,同步方式使用 binlog 複製方式。在 FastDFS 去重場景中,對文件內容做 hash,然後判斷文件是否一致。

在文件上傳成功後,查看 Storage 存儲對應存儲路徑,會發現返回的是一個軟鏈接,之後每次重複上傳都是返回一個指向第一次上傳的文件的軟鏈接。也就保證了文件只保存了一份。

(注意:FastDFS 不會返回原始文件的索引,返回的全部都是軟鏈接,當所有的軟鏈接都被刪除的時候,原始文件也會從 FastDFS 中被刪除)。

七、總結

FastDFS 真正意義上只是一個管理文件的系統(應用級文件系統),比如管理上傳文件、圖片等。並不像系統磁盤文件系統 NTFS 或者 FAT 等這種系統級文件系統。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Tk_H-ofrS5_kLwT1DZsxyA