FastDFS 海量小檔案儲存解決之道

語言: CN / TW / HK

作者:vivo網際網路伺服器團隊-Zhou Changqing

一、FastDFS原理介紹

FastDFS是一個C語言實現的開源輕量級分散式檔案系統 。

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

二、FastDFS 架構

FastDFS 由三個部分構成:

  • 客戶端(Client)

  • 跟蹤伺服器(TrackerServer)

  • 儲存伺服器(StorageServer)

圖片

2.1 Tracker Server (跟蹤伺服器)

Tracker Server (跟蹤伺服器) 主要是做排程工作,起到負載均衡的作用。

(1)【服務註冊】管理StorageServer儲存叢集,StorageServer啟動時,會把自己註冊到TrackerServer上,並且定期報告自身狀態資訊,包括磁碟剩餘空間、檔案同步狀況、檔案上傳下載次數等統計資訊。

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

(3)【負載均衡】

  • store group分配策略:
  • 0:輪詢方式

  • 1:指定組

  • 2:平衡負載(選擇最大剩餘空間的組(卷)上傳)

  • store server分配策略:
  • 0:輪詢方式

  • 1:根據 IP 地址進行排序選擇第一個伺服器( IP 地址最小者)

  • 2:根據優先順序進行排序(上傳優先順序由storage server來設定,引數名為upload_priority)

  • stroe path分配 :
  • 0:輪流方式,多個目錄依次存放檔案

  • 2:選擇剩餘空間最大的目錄存放檔案(注意:剩餘磁碟空間是動態的,因此儲存到的目錄或磁碟可能也是變化的)

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

  • 【分組】:檔案上傳時分配 Group。

  • 【磁碟路徑】:儲存伺服器配置的虛擬路徑,對應配置引數 store_path 例如:M00對應store_path0,M01對應store_path1。

  • 【兩級目錄】:儲存伺服器在每個虛擬磁碟路徑下建立的兩級目錄,用於儲存檔案。

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 配置。

  • 開啟防盜鏈功能
  • http.default_content_type =

  • application/octet-stream

  • http.mime_types_filename=mime.types

  • 開啟token防盜鏈功能
  • http.anti_steal.check_token=true

  • token過期時間

  • http.anti_steal.token_ttl=900

  • 金鑰
  • http.anti_steal.secret_key=xxx

  • token 過期後返回的內容

  • http.anti_steal.token_check_fail=/etc/fdfs/anti-steal.jpg

【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 來重定向或者代理方式獲取檔案。

  • 重定向模式

配置項response_mode = redirect,伺服器返回302,重定向url

http://源storage ip:port/檔案路徑?redirect=1

  • 代理模式

配置項response_mode = proxy,使用源storage 地址作為代理proxy的host,其他部分不變

四、同步機制

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

操作型別(部分):

  • C表示源建立、c表示副本建立

  • A表示源追加、a表示副本追加

  • D表示源刪除、d表示副本刪除

  • . . . . . . .

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。

(4)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。

(5)同步源(假設是storage A)以 .mark為字尾的檔案記錄目標機器同步資訊,並上報變更storage C狀態為SYNCING。

(6)從/data.sync目錄下讀取binlog.index 中的,binlog檔案Id,binlog.000讀取逐行讀取,進行解析.(詳見上面binlog 內格式) 傳送資料給storage C ,C接收並儲存。

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

五、檔案儲存

5.1 LOSF問題

小檔案儲存(LOSF)面臨的問題:

  • 本地檔案系統innode梳理優先,儲存小檔案數量受限。

  • 目錄層級和目錄中檔案數量會導致訪問檔案開銷很大(IO次數多)。

  • 小檔案儲存,備份和恢復效率低。

針對小檔案儲存問題,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個位元組額外內容用來儲存偏移量等資訊。

如下:

  • 【file_size】:佔用大檔案的空間(注意按照最小slot-256位元組進行對齊)

  • 【mtime】:檔案修改時間

  • 【crc32】:檔案內容的crc32碼

  • 【formatted_ext_name】:副檔名

  • 【alloc_size】:檔案大小與size相等

  • 【id】:大檔案ID如000001

  • 【offset】:檔案內容在trunk檔案中的偏移量

  • 【size】:檔案大小。

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

各欄位含義如下:

  • file.id】:TrunkFile檔名,比如 000001

  • 【offset】:在TrunkFile檔案中的偏移量

  • 【size】:佔用的大小,按照slot對齊

六、檔案去重

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

在檔案上傳成功後,檢視 Storage儲存對應儲存路徑,會發現返回的是一個軟連結,之後每次重複上傳都是返回一個指向第一次上傳的檔案的軟連結。也就保證了檔案只儲存了一份。

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

七、總結

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