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