分佈式文件系統:FastDFS 存儲原理
FastDFS 是一個 C 語言實現的開源輕量級分佈式文件系統 。
1、FastDFS 架構
由三個部分構成
-
客戶端(Client)
-
跟蹤服務器(TrackerServer)
-
存儲服務器(StorageServer)
1.1、Tracker Server
跟蹤服務器主要做調度工作,起到負載均衡的作用。
-
服務註冊:管理 storage server 存儲集羣,storage server 啓動時,會把自己註冊到 tracker server 上,並且定期報告自身狀態信息。
-
服務發現:client 訪問 storage server 之前,必須先訪問 tracker server,動態獲取到 storage server 的連接信息,最終數據是和一個可用的 storage server 進行傳輸。
-
負載均衡:storage group 分配策略,storage server 分配策略,storage path 分配策略。
1.2、Storage Server
存儲服務器主要提供容量和備份服務。
-
分組管理:以 group 爲單位,每個 group 包含多臺 storage server,數據互爲備份,存儲容量以 group 內容量最小的 storage 爲準。
-
數據同步:文件同步只能在 group 內的 storage server 間進行,採用 push 方式,即源服務器同步給目標服務器。源服務器讀取 binlog 文件,將文件內容解析後,按操作命令發送給目標服務器,由目標服務按命令進行操作。
2、小文件存儲機制
2.1、海量小文件存儲問題
海量,百萬級數量以上。小文件:1MB 以內的文件。
linux 文件存儲結構
-
inode:索引節點,存放文件信息
-
bock:存放文件數據
每個 inode 節點的大小,一般是 128 字節或 256 字節。
海量小文件存儲主要有兩個問題
-
inode 節點佔用空間,磁盤空間利用率不高
-
增刪改查文件的時候遍歷過多 inode 節點,影響效率
2.2、小文件機制配置
對於小文件,採用合併存儲的方式,合併存儲後的文件稱爲 trunk 文件。
配置文件 tracker.conf,只需要設置 use_trunk_file=true,store_server=1 即可。
# 是否啓用trunk存儲,默認false,支持小文件存儲需要打開
use_trunk_file = true
# 設置觸發小文件機制的文件大小
# trunk文件最小分配單元,單位字節,默認256
slot_min_size = 256
# trunk文件最大分配單元,超過該值獨立存儲,默認16M
# 此時,不會存儲到trunk file中,而是作爲一個單獨的文件直接存儲到文件系統
slot_max_size = 1MB
# trunk文件大小,默認64MB,不要配置得過大或者過小,最好不要超過256MB。
trunk_file_size = 64MB
2.3、合併存儲文件
向 FastDFS 上傳文件成功時,服務器返回該文件的存取 ID:fileid。當啓用小文件存儲時,多個 fileid 對應的小文件合併存儲成一個大文件 trunk
2.3.1、trunk 文件存儲結構
trunk 內部由多個小文件組成,每個小文件由 trunkHeader + 數據組成
|||——————————————— trunkHeader 24bytes —————————————————————————————————||||—1byte —|— 4bytes —|— 4bytes —|—4bytes— |—4bytes—|———— 7bytes ————||—filetype—|—alloc_size—|—filesize—|—crc32 —|—mtime —|—formatted_ext_name—|
|||—————————————————————— file_data filesize bytes ——————————————————————||||———————————————————————— file_data ———————————————————————————————————————|
trunk 文件默認 trunk_file_size = 64MB,每次創建 trunk 文件總是會產生空餘空間,可用於存儲其他小文件。當 trunk 文件中的小文件被全部刪除後,trucnk 文件纔會被刪除。
2.3.2、小文件存儲平衡樹
如何查詢空閒塊
在 storage 內部會爲每個 store_path 構造一棵以空閒塊大小作爲關鍵字的空閒平衡樹,相同大小的空閒塊保存在鏈表中。每當需要存儲一個文件時會首先到空閒平衡樹中查找大於並且最接近的空閒塊,然後試着從該空閒塊中分割出多餘的部分作爲一個新的空閒塊,加入到空閒平衡樹中。若找不到滿足的空閒塊,則新建一個 trunk 文件 64MB,並加入到空閒平衡樹,再一次執行上述查找操作。
2、文件上傳原理
2.1、負載均衡方法
2.1.1、tracker server
tracker 之間關係對等,用戶上傳文件時可以任意選擇一個 tracker。
2.1.2、group
當 tracker 接收到上傳文件請求時,爲該文件分配一個 group,支持的規則有:
-
Round robin,組間輪詢
-
Specified group,指定某一個組
-
Load balance,選擇最大剩餘空間的組上傳文件
2.1.3、storage server
選定 group 後,tracker 在 group 內選擇一個 storage server 給用戶,支持的規則有:
-
Round robin,storage 輪詢
-
First server ordered by ip,storage 按 ip 排序
-
First server ordered by priority,storage 按優先級排序(優先級在 storage 上配置)
2.1.4、storage path
當分配好 storage server 後,用戶向 storage 發送寫文件請求,storage 將會爲文件分配一個數據存儲目錄,支持的規則有:
-
Round robin,多個存儲目錄間輪詢
-
剩餘存儲空間最多的優先
在 storage.conf 中修改:多個路徑對應多個磁盤,提升磁盤併發讀寫能力。
store_path_count = 1
store_path0 = /home/fastdfs/storage
對於大文件來說,fastdfs 只能使用一個磁盤來整個存儲。ceph 可以將大文件拆分成多個段,分配到 ceph 集羣存儲。
2.2、生成返回 fileid
選定存儲目錄後,storage 會爲文件生成一個 fileid,當文件寫入到 storage 後返回 fileid。
fileid 由以下字段拼接而成
-
storage server ip
-
文件創建時間
-
文件大小
-
文件 crc32
-
一個隨機數
然後對該二進制串進行 base64 編碼,轉換爲可打印的字符串。
2.2.1、兩級目錄
storage 的每個存儲目錄下有兩級 256*256 的子目錄,storage 會按 fileid 進行兩次 hash(猜測),路由到其中一個子目錄,然後將文件以 fileid 爲文件名存儲到該子目錄下。
例:一個父目錄存儲 100w 文件,那麼子目錄存儲的文件個數:100w / 65536 = 15.2 個文件
2.5.2、生成文件名
當文件存儲到某個子目錄後,即認爲該文件存儲成功,接下來爲其生成文件名。
文件名由:group、存儲目錄、兩級子目錄、fileid、文件後綴名(用戶指定)拼接而成
// 組名 | 磁盤 | 兩級子目錄 | fileid | 文件後綴名
group1/M00/00/00/wKgqHV4OQQyAbo9YAAAA_fdSpmg855.txt
獨立文件 fileid
fileid 採用 base64 編碼,其組成爲:
-
storage_id | ip:源 storage server ID 或 ip 地址
-
timestamp:文件創建時間戳
-
file_size:(若原始值爲 32 位則前面加入一個隨機值填充,最終爲 64 位)
-
crc32:文件內容的檢驗碼
-
隨機數 :引入隨機數的目的是防止生成重名文件
wKgqHV4OQQyAbo9YAAAA_fdSpmg855
| 4bytes | 4bytes | 8bytes |4bytes | 2bytes |
| ip | timestamp | file_size |crc32 | 隨機數 |
小文件存儲 fileid
小文件採用合併存儲,fileid 除了上述字段,還增加了
-
trunk ID:大文件 ID
-
offset:該文件在 trunk 文件中的偏移量
-
alloc_size:該文件的分配大小
eBuDxWCwrDqITi98AAAA-3Qtcs8AAAAAQAAAgAAAAIA833
| 4bytes | 4bytes | 8bytes |4bytes | 4bytes | 4bytes | 4bytes | 2bytes || | 隨機數|
3、文件下載原理
3.1、解析路徑並路由
tracker 接收 client 發送的下載請求時,tracker 從文件名中解析出 group、大小、創建時間等信息,然後從 group 選擇一個 storage server 返回。
3.2、校驗讀取並返回
client 和 storage server 建立連接,校驗文件是否存在,並返回文件數據。
3.3、一致性
一致性的強弱
-
弱一致性:先返回存儲結果,再同步,速度快,不可靠
-
強一致性:先同步,再返回存儲結果,速度慢,安全可靠,非商業付費。
FastDFS 是弱一致性,先返回存儲結果,再同步。可能發生同一組內的 storage 未同步的情況。
4、同步機制
4.1、同步規則
-
同步只在本組的 storage server 之間
-
源頭數據需要同步,副本數據不需要再次同步,避免 push 循環。
-
新增 storage server 時,全量同步;其餘情況,增量同步
4.2、binlog
FastDFS 文件同步採用 binlog 異步複製方式。storage server 使用 binlog 記錄文件 ID 和操作,根據 binlog 進行文件同步。
binlog 格式:
-
時間戳
-
操作類型
-
文件 ID(無 group)
時間戳 | 操作類型 | 文件名
1646123002 C M00/00/00/oYYBAF285cOIHiVCAACI-7zX1qUAAAAVgAACC8AAIkT490.txt
1646123047 c M00/00/00/oYYBAF285luIK8jCAAAJeheau6AAAAAVgABI-cAAAmS021.xml
文件同步只在同組內的 storage server 之間進行,採用 push 方式。FastDFS 沒有主從節點,爲避免 push 環路,規定只能由源 push 到副本。源指的是客戶端直接操作的 storage,副本指的是本組其他的 storage,由 binlog 的操作類型來決定。
文件操作類型採用單個字母編碼,大寫字母表示源操作,小寫字母表示被同步的副本操作
binlog 位置:$base_path/data/sync/
-
binlog.000:binlog 文件,最大 1G。binlog.000, binlog.001, binlog.002, …
-
binlog_index.dat:記錄當前寫的 binlog 索引
4.3、mark
爲解決文件同步如何推送給不同的 storage,使用 .mark 文件記錄已同步的位置(增量同步)。
ip.mark 位置:$base_path/data/sync/
binlog_index=0 // binlog 索引,表示上次同步的 ip-storage 的 binlog 索引
binlog_offset=3944 // 當前 binlog 偏移量,下一次讀寫的位置
scan_row_count=68 // 掃描 binlog 記錄數
sync_row_count=53 // 同步的 binlog 記錄數
4.5、新增節點同步
在已有節點 A、B 上,新增節點 storage C。A、B 競爭關係,主動請求做同步推送
5、高可用
通過使用 tracker 集羣,storage 集羣(3),即冗餘服務,實現高可用
6、高併發
高併發問題:
寫併發
-
增加 group,水平擴展
-
一個 storage 配置多個硬盤,storage_path
注意:增加 storage 沒有用,同組 storage 需要推送文件給其他 N-1 個 storage。
讀併發
-
增加 storage,適用於少寫多讀的場景
-
增加 group,水平擴展
-
一個 storage 配置多個硬盤,storage_path
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/SXDuKMTkV458ftSVNbBmqg