FastDFS 海量小文件存儲解決之道
作者:vivo互聯(lián)網(wǎng)服務器團隊-Zhou Changqing
一、FastDFS原理介紹
FastDFS是一個C語言實現(xiàn)的開源輕量級分布式文件系統(tǒng) 。
支持 Linux、FreeBSD、AID 等Unix系統(tǒng),解決了大容量的文件存儲和高并發(fā)訪問問題,文件存取實現(xiàn)了負載均衡,適合存儲 4KB~500MB 之間的小文件,特別適合以文件為載體的在線服務,如圖片、視頻、文檔等等。
二、FastDFS 架構
FastDFS 由三個部分構成:
- 客戶端(Client)
- 跟蹤服務器(TrackerServer)
- 存儲服務器(StorageServer)
2.1 Tracker Server (跟蹤服務器)
Tracker Server (跟蹤服務器) 主要是做調度工作,起到負載均衡的作用。
(1)【服務注冊】管理StorageServer存儲集群,StorageServer啟動時,會把自己注冊到TrackerServer上,并且定期報告自身狀態(tài)信息,包括磁盤剩余空間、文件同步狀況、文件上傳下載次數(shù)等統(tǒng)計信息。
(2)【服務發(fā)現(xiàn)】Client訪問StorageServer之前,必須先訪問TrackerServer,動態(tài)獲取到StorageServer的連接信息,最終數(shù)據(jù)是和一個可用的StorageServer進行傳輸。
(3)【負載均衡】
store group分配策略:
- 0:輪詢方式
- 1:指定組
- 2:平衡負載(選擇最大剩余空間的組(卷)上傳)
store server分配策略:
- 0:輪詢方式
- 1:根據(jù) IP 地址進行排序選擇第一個服務器( IP 地址最小者)
- 2:根據(jù)優(yōu)先級進行排序(上傳優(yōu)先級由storage server來設置,參數(shù)名為upload_priority)
stroe path分配 :
- 0:輪流方式,多個目錄依次存放文件
- 2:選擇剩余空間最大的目錄存放文件(注意:剩余磁盤空間是動態(tài)的,因此存儲到的目錄或磁盤可能也是變化的)
2.2 Tracker Server (跟蹤服務器)
Tracker Server (跟蹤服務器) 主要提供容量和備份服務。
【分組管理】以Group為單位,每個Group包含多臺Storage Server,數(shù)據(jù)互為備份,存儲容量以Group內容量最小的 storage 為準,已 Group 為單位組織存儲方便應用隔離、負載均衡和副本數(shù)據(jù)定制。
缺點:Group容量受單機存儲容量的限制,數(shù)據(jù)恢復只能依賴Group其他機器重新同步。
【數(shù)據(jù)同步】文件同步只能在 Group 內的Storage Server之間進行,采用push方式,即源服務器同步給目標服務器。源服務器讀取 binlog 文件,將文件內容解析后,按操作命令發(fā)送給目標服務器,有目標服務按命令進行操作。
三、上傳下載流程
3.1 上傳流程解析
3.1.1 選擇Tracker Server
集群中的 tracker 之間都是對等的,客戶端在上傳文件時可任意選擇一個 tracker 即可。
3.1.2 分配Group、Stroage Server 和storage path(磁盤或者掛載點)
tracker 接收到上傳請求時會先給該文件分配一個可以存儲的 Group ,然后在Group中分配一個Storage Server給客戶端,最后在接收到客戶端寫文件請求時,Storage Server 會分配一個數(shù)據(jù)存儲目錄并寫入。
(該過程中的分配策略詳見:【負載均衡】)
3.1.3 生成file_id寫入并返回
Storage 會生成一個 file_id 來作為當前文件名,file_id 采用 base64 編碼,包含:源 storage server ip、文件創(chuàng)建時間、文件大小、文件CRC32校驗碼 和 隨機數(shù)。每個存儲目錄下 有兩個256*256個子目錄。
Storage 會根據(jù) file_id 進行兩次 hash 路由到其中一個子目錄中。
最后以file_id為文件名存儲文件到該子目錄下并返回文件路徑給客戶端。
最終文件存儲路徑:
**分組 |磁盤|子目錄| 文件名 **
group1/M00/00/89/eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.apk
【分組】:文件上傳時分配 Group。
【磁盤路徑】:存儲服務器配置的虛擬路徑,對應配置參數(shù) store_path 例如:M00對應store_path0,M01對應store_path1。
【兩級目錄】:存儲服務器在每個虛擬磁盤路徑下創(chuàng)建的兩級目錄,用于存儲文件。
3.2 下載流程解析
3.2.1 解析路徑并路由
tracker 接收 client 發(fā)送的下載請求時,tracker 從文件名中解析出 Group、大小、創(chuàng)建時間等信息,然后根據(jù)Group 選擇一個 storage server 返回。
3.2.2 校驗讀取并返回
客戶端和 Storage Server 建立鏈接,校驗文件是否存在,最終返回文件數(shù)據(jù)。
缺點:Group之間文件同步是異步進行的,可能上傳的文件還未同步到當前訪問的 Storage Server 這臺機器上或者延遲原因,將導致下載文件出現(xiàn)404。所以引入nginx_fastdfs_module 可以很好的解決同步和延遲問題。
3.3 引入fastdfs_nginx_module組件后的下載架構
FastDFS Nginx Module功能介紹
(1)【防盜鏈檢查】
利用 FastDFS nginx 擴展功能動態(tài)生成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 范圍。
服務器會自動根據(jù)token,st 以及設置的秘鑰來驗證合法性。訪問鏈接形式如:
(2)【文件元數(shù)據(jù)解析】
根據(jù) file_id 獲取元數(shù)據(jù)信息, 包括:源storage ip,文件路徑,名稱,大小 等。
(3)【文件訪問路由】
因文件的file_Id 包含了上傳文件時的源 Storage Server IP ,所以在獲取不到本機下的文件時(未同步或者延遲情況下)FastDFS 擴展組件,會根據(jù)源服務器IP 來重定向或者代理方式獲取文件。
重定向模式
- 配置項response_mode = redirect,服務器返回302,重定向url
- http://源storage ip:port/文件路徑?redirect=1
代理模式
- 配置項response_mode = proxy,使用源storage 地址作為代理proxy的host,其他部分不變
四、同步機制
4.1 同步規(guī)則
同步只發(fā)生在本組的 Storage Server 之間。
源頭數(shù)據(jù)才需要同步,備份數(shù)據(jù)不需要再次同步。
新增 Storage Server 時,會由已有一臺 Storage Server 將已有的所有數(shù)據(jù)(源頭數(shù)據(jù)和備份數(shù)據(jù))同步給新增服務器。
4.2 Binlog 復制
FastDFS 文件同步采用binlog異步復制方式,Storage Server 使用binlog文件記錄文件上傳、刪除等操作,根據(jù)Binlog進行文件同步。Binlog中只記錄文件ID和操作,不記錄文件內容 .binlog 格式如下:
時間戳 | 操作類型 | 文件名
1490251373 C M02/52/CB/
CtAqWVjTbm2AIqTkAAACd_nIZ7M797.jpg
操作類型(部分):
- C表示源創(chuàng)建、c表示副本創(chuàng)建
- A表示源追加、a表示副本追加
- D表示源刪除、d表示副本刪除
- . . . . . . .
4.3 同步流程
新增 Storage Server 后,組內其他 Storage Server 服務器會啟動同步線程,在 tracker的協(xié)調下向新增服務器發(fā)起全量和增量同步操作。
(1)Storage C啟動后向tracker 上報所屬group、ip、port、版本號、存儲目錄數(shù)、子目錄數(shù)、啟動時間、老數(shù)據(jù)是否同步完成,當前狀態(tài)等信息。
(2)tracker 收到Storage C 加入申請請求后,更新本地storage list,返回給C,并適時同步給A、B。
- storage C向tracker 申請同步請求,響應后變更自身狀態(tài)為WAIT_SYNC。
- storage A 和B 在心跳周期內從同步到的新storage list 發(fā)現(xiàn)沒有C,則啟動同步線程,先向tracker發(fā)起同步申請
(TRACKER_PROTO_CMD_STORAGE_SYNC_SRC_REQ),tracker會把同步源IP級同步時間戳返回給A和B,如果源IP和自己本地IP一致,則標記自己作為同步源用來做老數(shù)據(jù)同步(全量同步源),如果不一致,則標記自己作為增量同步源(只有在C節(jié)點狀態(tài)為Active時才同步)。該決策是由tracker 選擇產(chǎn)生的,不可A、B同時作為同步源,同時同步給C。
(3)同步源(假設是storage A)以 .mark為后綴的文件記錄目標機器同步信息,并上報變更storage C狀態(tài)為SYNCING。
(4)從/data.sync目錄下讀取binlog.index 中的,binlog文件Id,binlog.000讀取逐行讀取,進行解析.(詳見上面binlog 內格式) 發(fā)送數(shù)據(jù)給storage C ,C接收并保存。
(5)數(shù)據(jù)同步過程中 storage C 的狀態(tài)變更過程OFFLINE->ONLINE->ACTIVE。ACTIVE 是最終狀態(tài),表示storage C 已對外提供服務。
五、文件存儲
5.1 LOSF問題
小文件存儲(LOSF)面臨的問題:
- 本地文件系統(tǒng)innode梳理優(yōu)先,存儲小文件數(shù)量受限。
- 目錄層級和目錄中文件數(shù)量會導致訪問文件開銷很大(IO次數(shù)多)。
- 小文件存儲,備份和恢復效率低。
針對小文件存儲問題,F(xiàn)astDFS 提供了文件合并解決方案。FastDFS 默認創(chuàng)建大文件為 64M,大文件可以存儲很多小文件,容納一個小文件的空間叫slot,solt 最小256字節(jié),最大16M。小于256字節(jié)當256字節(jié)存儲,超過16M文件單獨存儲。
5.2 存儲方式
(1)【默認存儲方式】未開啟合并 ,F(xiàn)astDFS生成的file_id 和磁盤上實際存儲的文件一一對應。
(2)【合并存儲方式】多個file_id對應文件被存儲成了一個大文件 。trunk文件名格式:/fastdfs/data/00/000001 文件名從1開始遞增。而生成的file_id 更長,會新增16個字節(jié)額外內容用來保存偏移量等信息。
如下:
- 【file_size】:占用大文件的空間(注意按照最小slot-256字節(jié)進行對齊)
- 【mtime】:文件修改時間
- 【crc32】:文件內容的crc32碼
- 【formatted_ext_name】:文件擴展名
- 【alloc_size】:文件大小與size相等
- 【id】:大文件ID如000001
- 【offset】:文件內容在trunk文件中的偏移量
- 【size】:文件大小。
5.4 存儲空間管理
(1)【Trunk Server】由tracker leader 在一組Storage Server 選擇出來的,并通知給該組內所有Storage Server,負責為該組內所有upload操作分配空間。
(2)【空閑平衡樹】trunk server 會為每個store_path構造一個空閑平衡樹,相同大小的空閑塊保存在鏈表中,每次上傳請求時會到根據(jù)上傳的文件大小到平衡樹中查找獲取大于或者接近的空閑塊,然后從空閑塊中分割出多余的作為新的空閑塊,重新加入平衡樹。如果找不到則會重建一個新的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系統(tǒng),底層采用Berkeley DB 來做數(shù)據(jù)庫持久化,同步方式使用binlog復制方式。在FastDFS去重場景中,對文件內容做hash,然后判斷文件是否一致。
在文件上傳成功后,查看 Storage存儲對應存儲路徑,會發(fā)現(xiàn)返回的是一個軟鏈接,之后每次重復上傳都是返回一個指向第一次上傳的文件的軟鏈接。也就保證了文件只保存了一份。
(注意:FastDFS不會返回原始文件的索引,返回的全部都是軟鏈接,當所有的軟鏈接都被刪除的時候,原始文件也會從FastDFS中被刪除)。
七、總結
FastDFS 真正意義上只是一個管理文件的系統(tǒng)(應用級文件系統(tǒng)),比如管理上傳文件、圖片等。并不像系統(tǒng)磁盤文件系統(tǒng)NTFS或者FAT 等這種系統(tǒng)級文件系統(tǒng)。