FastDFS學習筆記
- 2019 年 10 月 5 日
- 筆記
fastdfs作者及軟體的下載方式:https://github.com/happyfish100
FastDFS基礎
fastdfs是一個開源的,高性能的的分散式文件系統,他主要的功能包括:文件存儲,同步和訪問,設計基於高可用和負載均衡,fastfd非常適用於基於文件服務的站點,例如圖片分享和影片分享網站
fastfds有兩個角色:跟蹤服務和存儲服務
跟蹤服務控制:主要做調度工作,在訪問上起負載均衡的作用。
存儲服務包括:文件存儲,文件同步,提供文件訪問介面,同時以key value的方式管理文件的元數據
跟蹤器和存儲節點都可以由一台多台伺服器構成。跟蹤器和存儲節點中的伺服器均可以隨時增加或下線而不會影響線上服務。其中跟蹤器中的所有伺服器都是對等的,可以根據伺服器的壓力情況隨時增加或減少。
為了支援大容量,存儲節點(伺服器)採用了分卷(或分組)的組織方式。存儲系統由一個或多個卷組成,卷與卷之間的文件是相互獨立的,所有卷的文件容量累加就是整個存儲系統中的文件容量。一個卷可以由一台或多台存儲伺服器組成,一個卷下的存儲伺服器中的文件都是相同的,卷中的多台存儲伺服器起到了冗餘備份和負載均衡的作用。
在卷中增加伺服器時,同步已有的文件由系統自動完成,同步完成後,系統自動將新增伺服器切換到線上提供服務。
當存儲空間不足或即將耗盡時,可以動態添加卷。只需要增加一台或多台伺服器,並將它們配置為一個新的卷,這樣就擴大了存儲系統的容量。
輕量級
FastDFS只有兩個角色:Tracker server和Storage server。
Tracker server作為中心結點,其主要作用是負載均衡和調度。
Tracker server在記憶體中記錄分組和Storage server的狀態等資訊,不記錄文件索引資訊,佔用的記憶體量很少。另外,客戶端(應用)和Storage server訪問Tracker server時,Tracker server掃描記憶體中的分組和Storage server資訊,然後給出應答。由此可以看出Tracker server非常輕量化,不會成為系統瓶頸。
FastDFS中的Storage server在其他文件系統中通常稱作Trunk server或Data server。Storage server直接利用OS的文件系統存儲文件。FastDFS不會對文件進行分塊存儲,客戶端上傳的文件和Storage server上的文件一一對應。
眾所周知,大多數網站都需要存儲用戶上傳的文件,如圖片、影片、電子文檔等。出於降低頻寬和存儲成本的考慮,網站通常都會限制用戶上傳的文件大小,例如圖片文件不能超過5MB、影片文件不能超過100MB等。我認為,對於互聯網應用,文件分塊存儲沒有多大的必要。它既沒有帶來多大的好處,又增加了系統的複雜性。FastDFS不對文件進行分塊存儲,與支援文件分塊存儲的DFS相比,更加簡潔高效,並且完全能滿足絕大多數互聯網應用的實際需要。
在FastDFS中,客戶端上傳文件時,文件ID不是由客戶端指定,而是由Storage server生成後返回給客戶端的。文件ID中包含了組名、文件相對路徑和文件名,Storage server可以根據文件ID直接定位到文件。因此FastDFS集群中根本不需要存儲文件索引資訊,這是FastDFS比較輕量級的一個例證。而其他文件系統則需要存儲文件索引資訊,這樣的角色通常稱作NameServer。其中mogileFS採用MySQL資料庫來存儲文件索引以及系統相關的資訊,其局限性顯而易見,MySQL將成為整個系統的瓶頸。
FastDFS輕量級的另外一個體現是程式碼量較小。最新的V2.0包括了C客戶端API、FastDHT客戶端API和PHP extension等,程式碼行數不到5.2萬行。
分組方式
類Google FS都支援文件冗餘備份,例如Google FS、TFS的備份數是3。一個文件存儲到哪幾個存儲結點,通常採用動態分配的方式。採用這種方式,一個文件存儲到的結點是不確定的。舉例說明,文件備份數是3,集群中有A、B、C、D四個存儲結點。文件1可能存儲在A、B、C三個結點,文件2可能存儲在B、C、D三個結點,文件3可能存儲在A、B、D三個結點。
FastDFS採用了分組存儲方式。集群由一個或多個組構成,集群存儲總容量為集群中所有組的存儲容量之和。一個組由一台或多台存儲伺服器組成,同組內的多台Storage server之間是互備關係,同組存儲伺服器上的文件是完全一致的。文件上傳、下載、刪除等操作可以在組內任意一台Storage server上進行。類似木桶短板效應,一個組的存儲容量為該組記憶體儲伺服器容量最小的那個,由此可見組記憶體儲伺服器的軟硬體配置最好是一致的。【一組storage的文件是一致的,客戶端可以從組內的任一伺服器下載文件】
採用分組存儲方式的好處是靈活、可控性較強。比如上傳文件時,可以由客戶端直接指定上傳到的組。一個分組的存儲伺服器訪問壓力較大時,可以在該組增加存儲伺服器來擴充服務能力(縱向擴容)。當系統容量不足時,可以增加組來擴充存儲容量(橫向擴容)。採用這樣的分組存儲方式,可以使用FastDFS對文件進行管理,使用主流的Web server如Apache、nginx等進行文件下載。
對等結構
FastDFS集群中的Tracker server也可以有多台,Tracker server和Storage server均不存在單點問題。Tracker server之間是對等關係,組內的Storage server之間也是對等關係。傳統的Master-Slave結構中的Master是單點,寫操作僅針對Master。如果Master失效,需要將Slave提升為Master,實現邏輯會比較複雜。和Master-Slave結構相比,對等結構中所有結點的地位是相同的,每個結點都是Master,不存在單點問題。

從圖上可以看出,Tracker server之間相互獨立,不存在直接聯繫。
客戶端和Storage server主動連接Tracker server。Storage server主動向Tracker server報告其狀態資訊,包括磁碟剩餘空間、文件同步狀況、文件上傳下載次數等統計資訊。Storage server會連接集群中所有的Tracker server,向他們報告自己的狀態。Storage server啟動一個單獨的執行緒來完成對一台Tracker server的連接和定時報告。需要說明的是,一個組包含的Storage server不是通過配置文件設定的,而是通過Tracker server獲取到的。
不同組的Storage server之間不會相互通訊,同組內的Storage server之間會相互連接進行文件同步。
Storage server採用binlog文件記錄文件上傳、刪除等更新操作。binlog中只記錄文件名,不記錄文件內容。
文件同步只在同組內的Storage server之間進行,採用push方式,即源頭伺服器同步給目標伺服器。只有源頭數據才需要同步,備份數據並不需要再次同步,否則就構成環路了。有個例外,就是新增加一台Storage server時,由已有的一台Storage server將已有的所有數據(包括源頭數據和備份數據)同步給該新增伺服器。
Storage server中由專門的執行緒根據binlog進行文件同步。為了最大程度地避免相互影響以及出於系統簡潔性考慮,Storage server對組內除自己以外的每台伺服器都會啟動一個執行緒來進行文件同步。
文件同步採用增量同步方式,系統記錄已同步的位置(binlog文件偏移量)到標識文件中。標識文件名格式:{dest storage IP}_{port}.mark,例如:192.168.1.14_23000.mark。
上傳文件交互過程:

下載文件交互過程:

1. client詢問tracker下載文件的storage,參數為文件標識(卷名和文件名)
2. tracker返回一台可用的storage
3. client直接和storage通訊完成文件下載
需要說明的是,client為使用FastDFS服務的調用方,client也應該是一台伺服器,它對tracker和storage的調用均為伺服器間的調用。

文件同步延遲問題的提出
客戶端將一個文件上傳到一台Storage server後,文件上傳工作就結束了。由該Storage server根據binlog中的上傳記錄將這個文件同步到同組的其他Storage server。這樣的文件同步方式是非同步方式,非同步方式帶來了文件同步延遲的問題。新上傳文件後,在尚未被同步過去的Storage server上訪問該文件,會出現找不到文件的現象。FastDFS是如何解決文件同步延遲這個問題的呢?
文件的訪問分為兩種情況:文件更新和文件下載。文件更新包括設置文件附加屬性和刪除文件。文件的附加屬性包括文件大小、圖片寬度、圖片高度等。FastDFS中,文件更新操作都會優先選擇源Storage server,也就是該文件被上傳到的那台Storage server。這樣的做法不僅避免了文件同步延遲的問題,而且有效地避免了在多台Storage server上更新同一文件可能引起的時序錯亂的問題。
那麼文件下載是如何解決文件同步延遲這個問題的呢?
要回答這個問題,需要先了解文件名中包含了什麼樣的資訊。Storage server生成的文件名中,包含了源Storage server的IP地址和文件創建時間等欄位。文件創建時間為UNIX時間戳,後面稱為文件時間戳。從文件名或文件ID中,可以反解出這兩個欄位。
然後我們再來看一下,Tracker server是如何準確地知道一個文件已被同步到一台Storage server上的。前面已經講過,文件同步採用主動推送的方式。另外,每台storage server都會定時向tracker server報告它向同組的其他storage server同步到的文件時間戳。當tracker server收到一台storage server的文件同步報告後,它會依次找出該組內各個storage server(後稱作為S)被同步到的文件時間戳最小值,作為S的一個屬性記錄到記憶體中。
FastDFS對文件同步延遲問題的解決方案
一個最簡單的解決辦法,和文件更新一樣,優先選擇源Storage server下載文件即可。這可以在Tracker server的配置文件中設置,對應的參數名為download_server。
另外一種選擇Storage server的方法是輪流選擇(round-robin)。當Client詢問Tracker server有哪些Storage server可以下載指定文件時,Tracker server返回滿足如下四個條件之一的Storage server:
1. 該文件上傳到的源Storage server,文件直接上傳到該伺服器上的;
2. 文件創建時間戳 < Storage server被同步到的文件時間戳,這意味著當前文件已經被同步過來了;
3. 文件創建時間戳=Storage server被同步到的文件時間戳,且(當前時間—文件創建時間戳) > 一個文件同步完成需要的最大時間(如5分鐘);
4. (當前時間—文件創建時間戳) > 文件同步延遲閾值,比如我們把閾值設置為1天,表示文件同步在一天內肯定可以完成。
FastDFS的簡單實驗配置
tracker: node1 192.168.2.11
tracker: node2 192.168.2.12
storage: node1 192.168.2.11
storage: node2 192.168.2.12
安裝必要的軟體包
fastdfs下載地址:https://github.com/happyfish100/fastdfs (版本號 5.0.8)
下面的步驟在tracker和storage差不多。就/etc/fdfs下的啟用的文件不一樣。
安裝libfastcommon
# git clonehttps://github.com/happyfish100/libfastcommon.git
# cd libfastcommon/
#./make.sh
#./make.sh install
編譯安裝FastDFS
下載地址:https://github.com/happyfish100/fastdfs/releases
# unzip fastdfs-master.zip
# cd fastfds-master
# vim make.sh 修改地方如下:

# ./make.sh
# ./make.sh install
安裝完成後,會在/etc/fdfs目錄下生成3個文件
此外,我們還要把conf目錄下的http.conf、mime.types、storage_ids.conf 複製到/etc/fdfs目錄下。
install安裝的同時還會在/etc/init.d目錄下生成2個腳本文件
注意下,這2個啟動腳本裡面的程式的路徑和我們安裝的路徑不一致,下面我們會做一個軟鏈接即可解決。
添加環境變數及創建軟鏈接
# ln -s /usr/local/FastDFS/bin/fdfs_trackerd/usr/bin/fdfs_trackerd
# ln -s /usr/local/FastDFS/bin/fdfs_storaged/usr/bin/fdfs_storaged
# echo 'exportPATH=$PATH:/usr/local/FastDFS/bin' > /etc/profile.d/fdfs.sh
# source /etc/profile.d/fdfs.sh
【tracker節點的配置方法】
# cd /etc/fdfs/
# egrep -v '^#|^$' tracker.conf.sample > tracker.conf
# vim tracker.conf 主要注意的內容如下:
disabled=false #啟用配置文件【】
port=22122 #設置tracker的埠號
base_path=/data/fastdfs/tracker # 設置tracker的數據文件和日誌目錄(需預先創建)
store_lookup=2 # 以負載均衡方式存文件(優先存放在最大空閑的group里)
store_group=group1
http.server_port=18080
其他未列出的就是保持默認的參數,配置文件里具體『』都有很詳細的說明
【2台storage節點的配置方法】
# cd /etc/fdfs/
# egrep -v '^#|^$' storage.conf.sample >storage.conf
# vim storage.conf 內容如下:
port=23000
base_path=/data/fastdfs/storage
#store_path0=/data/fastdfs/storage 可以直接注釋掉這行,這樣默認就使用base_path的路徑。如果有多塊硬碟,也可以使用store_pathX這種寫法
store_group=group1
tracker_server=192.168.2.11:22122 # 如果有多個tracker_server,則每行寫一個
tracker_server=192.168.2.11:22122 # 如果有多個tracker_server,則每行寫一個
http.server_port=8888
【client節點的配置方法】
# egrep -v '^$|^#' client.conf.conf.sample >client.conf
# vim client.conf.conf 內容如下:
base_path=/data/fastdfs/client
tracker_server=192.168.2.11:22122
tracker_server=192.168.2.11:22122 # 如果有多個tracker_server,則每行寫一個
創建上面提到的幾個目錄
# mkdir -pv/data/fastdfs/{tracker,storage,client}
啟動trakcer、storaged
# /etc/rc.d/init.d/fdfs_trackerdstart
# /etc/rc.d/init.d/fdfs_storagedstart
ps -ef|grep fdfs可以看到fastdfs進程已經啟動了
trakcer、storaged節點上配置開機自啟動
# chkconfig fdfs_trackerd on
# chkconfig fdfs_storaged on
上傳文件測試
# fdfs_upload_file/etc/fdfs/client.conf /etc/passwd

此時,我們如果使用find命令查找這個文件的話,可以看到圖片上傳到/data/fastdfs/storage/data/00/00目錄下面的。
下載剛才上傳的那個文件
用法:Usage: fdfs_download_file <config_file><file_id> [local_filename] [<download_offset><download_bytes>]
例如:fdfs_download_file /etc/fdfs/client.confgroup1/M00/00/00/wKgCC1hQBa2AO4kXAAAM0bnQXLc8822806
查看文件的info

可以看到很詳細的資訊。
刪除文件
# fdfs_delete_file/etc/fdfs/client.conf group1/M00/00/00/wKgCC1hQBa2AO4kXAAAM0bnQXLc8822806
追加上傳的方法:
echo abc > f1.txt
echo def > f2.txt
fdfs_upload_appender/etc/fdfs/client.conf f1.txt
fdfs_download_file/etc/fdfs/client.conf group1/M00/00/00/wKgCDFhQDwuET0QeAAAAAEd3frE087.txt 可以驗證下內容和f1.txt一致
fdfs_append_file/etc/fdfs/client.conf group1/M00/00/00/wKgCDFhQDwuET0QeAAAAAEd3frE087.txtf2.txt 追加上傳
fdfs_download_file/etc/fdfs/client.conf group1/M00/00/00/wKgCDFhQDwuET0QeAAAAAEd3frE087.txt 可以下載驗證下內容和f1.txt一致
列出詳細資訊
fdfs_monitor /etc/fdfs/client.conf
會列出當前的全部group、tracker等資訊。
刪除某個storagegroup
先停止需要刪除的那個group節點(以192.168.2.11為例)的storaged進程/etc/init.d/fdfs_storaged stop
然後執行fdfs_monitor /etc/fdfs/client.conf delete group1 192.168.2.11 即可刪除

使用php_client來進行測試(這在官方的github有詳細的安裝配置方法):
在github下載的壓縮包裡面,自帶了php_client的測試程式。
tar xf fastdfs-5.08.tar.gz
cd /root/fastdfs-5.08/php_client
./configure–with-php-config=/usr/local/php/bin/php-config #我這裡演示的是編譯安裝的php5.4
make && make install
cat fastdfs_client.ini >> /usr/local/php/etc/php.ini 直接將內容追加到php.ini尾部即可
/usr/local/php/bin/php /root/fastdfs-5.08/php_client/fastdfs_test.php 即可執行官方自帶的測試腳本
類似下圖:

對於java的程式,官方也給出了實例文件。
下載地址 https://github.com/happyfish100/fastdfs-client-java
下面我直接在/root目錄下演示的。
git clonehttps://github.com/happyfish100/fastdfs-client-java.git
cd /root/fastdfs-client-java/src
/usr/local/ant/bin/ant # 執行ant命令即可(需要事先安裝ant工具)

這樣就在build/目錄下生成了fastdfs_client.jar文件及一個classess文件夾。
java -cp /root/fastdfs-client-java/src/build/fastdfs_client.jar 就可以顯示java裡面對fastdfs的具體的用法了。
具體用法:https://github.com/happyfish100/fastdfs-client-java/tree/master/src
嘗試java調用fastdfs上傳文件
cd /root/fastdfs-client-java/src
java -cp fastdfs_client.jarorg.csource.fastdfs.test.TestClient /etc/fdfs/client.conf /etc/shadow

我們可到/data/fastdfs/storage/data/00/00目錄下,可以發現wKgCDFhQK-uANJG7AAAJG3YcMRs0452086這個文件和/etc/shadow內容一樣的。
監控fastdfs的狀態:
java -cp fastdfs_client.jarorg.csource.fastdfs.test.Monitor /etc/fdfs/client.conf
在tracker1上安裝配置nginx[重點掌握]:
以node1 tracker為例演示。
fastdfs的nginx模組:https://github.com/happyfish100/fastdfs-nginx-module
cd /root
git clone https://github.com/happyfish100/fastdfs-nginx-module.git
另外需要解壓縮一個pcre的包,下面nginx編譯會用到,我這的路徑是/root/pcre-8.36
找一個nginx-1.11.5的源碼包,解壓後執行:
# ./configure –user=www–group=www
–prefix=/usr/local/nginx–with-http_stub_status_module
–with-http_ssl_module–with-http_gzip_static_module
–with-http_sub_module–with-google_perftools_module
–with-pcre=/root/pcre-8.36
–add-module=/root/fastdfs-nginx-module/src
# make && make install
# cp /root/fastdfs-nginx-module/src/mod_fastdfs.conf/etc/fdfs/
# cd /root/fastdfs-5.08/conf/
# cp anti-steal.jpg http.confmime.types /etc/fdfs/
# touch /var/log/mod_fastdfs.log
# chown www.www /var/log/mod_fastdfs.log
# vim /etc/fdfs/mod_fastdfs.conf 設置下tracker的資訊
tracker_server=192.168.2.11:22122
tracker_server=192.168.2.12:22122
url_have_group_name=true
store_path0=/data/fastdfs/storage # 注意這裡的路徑要和/etc/fdfs/storage.conf裡面配置的一致
log_filename=/var/log/mod_fastdfs.log
response_mode=proxy
然後,修改nginx的配置文件
# cd /usr/local/nginx/conf/
# vim nginx.conf 修改如下:
# 官方操作方法參考https://github.com/happyfish100/fastdfs-nginx-module/blob/master/INSTALL
server
{
listen 80;
server_name 192.168.2.11;
index index.html index.htm index.php;
root /home/wwwroot/default;
location /group1/M00 {
root /data/fastdfs/storage/data;
ngx_fastdfs_module;
}
# 注意,如果還要加其他的location同學請注意,我之前的某些其他location導致圖片無法載入的。
}
啟動nginx測試
# nginx -t
# /etc/init.d/nginx start
# 上傳文件測試
fdfs_upload_file /etc/fdfs/client.conf /etc/inittab
此處我得到的路徑為:group1/M00/00/00/wKgCC1hRbyWAVZw0AAADdDn5EZ87807780
然後,直接通過瀏覽器訪問即可下載到這個文件。

fastdfs對圖片的支援
上傳圖片後,在瀏覽里輸入地址即可訪問,如下圖:
