FastDFS安裝與使用


1. FastDFS介紹

FastDFS是一個開源的輕量級分布式文件系統,由跟蹤服務器(tracker server)、存儲服務器(storage server)和客戶端(client)三個部分組成,主要解決了海量數據存儲問題,特別適合以中小文件(建議范圍:4KB < file_size <500MB)為載體的在線服務。

Storage server

Storage server(后簡稱storage)以組(卷,group或volume)為單位組織,一個group內包含多台storage機器,數據互為備份,存儲空間以group內容量最小的storage為准,所以建議group內的多個storage盡量配置相同,以免造成存儲空間的浪費。

以group為單位組織存儲能方便的進行應用隔離、負載均衡、副本數定制(group內storage server數量即為該group的副本數),比如將不同應用數據存到不同的group就能隔離應用數據,同時還可根據應用的訪問特性來將應用分配到不同的group來做負載均衡;缺點是group的容量受單機存儲容量的限制,同時當group內有機器壞掉時,數據恢復只能依賴group內地其他機器,使得恢復時間會很長。

group內每個storage的存儲依賴於本地文件系統,storage可配置多個數據存儲目錄,比如有10塊磁盤,分別掛載在/data/disk1-/data/disk10,則可將這10個目錄都配置為storage的數據存儲目錄。

storage接受到寫文件請求時,會根據配置好的規則,選擇其中一個存儲目錄來存儲文件。為了避免單個目錄下的文件數太多,在storage第一次啟動時,會在每個數據存儲目錄里創建2級子目錄,每級256個,總共65536個文件,新寫的文件會以hash的方式被路由到其中某個子目錄下,然后將文件數據直接作為一個本地文件存儲到該目錄中。

Tracker server

Tracker是FastDFS的協調者,負責管理所有的storage server和group,每個storage在啟動后會連接Tracker,告知自己所屬的group等信息,並保持周期性的心跳,tracker根據storage的心跳信息,建立group==>[storage server list]的映射表。

Tracker需要管理的元信息很少,會全部存儲在內存中;另外tracker上的元信息都是由storage匯報的信息生成的,本身不需要持久化任何數據,這樣使得tracker非常容易擴展,直接增加tracker機器即可擴展為tracker cluster來服務,cluster里每個tracker之間是完全對等的,所有的tracker都接受stroage的心跳信息,生成元數據信息來提供讀寫服務。

Upload file

FastDFS向使用者提供基本文件訪問接口,比如upload、download、append、delete等,以客戶端庫的方式提供給用戶使用。

 

選擇tracker server

當集群中不止一個tracker server時,由於tracker之間是完全對等的關系,客戶端在upload文件時可以任意選擇一個trakcer。

選擇存儲的group

當tracker接收到upload file的請求時,會為該文件分配一個可以存儲該文件的group,支持如下選擇group的規則: 
     1. Round robin,所有的group間輪詢 
     2. Specified group,指定某一個確定的group 
     3. Load balance,剩余存儲空間多多group優先

選擇storage server

當選定group后,tracker會在group內選擇一個storage server給客戶端,支持如下選擇storage的規則: 
     1. Round robin,在group內的所有storage間輪詢 
     2. First server ordered by ip,按ip排序 
     3. First server ordered by priority,按優先級排序(優先級在storage上配置)

選擇storage path

當分配好storage server后,客戶端將向storage發送寫文件請求,storage將會為文件分配一個數據存儲目錄,支持如下規則: 
1. Round robin,多個存儲目錄間輪詢 
2. 剩余存儲空間最多的優先

生成Fileid

       選定存儲目錄之后,storage會為文件生一個Fileid,由storage server ip、文件創建時間、文件大小、文件crc32和一個隨機數拼接而成,然后將這個二進制串進行base64編碼,轉換為可打印的字符串

選擇兩級目錄

當選定存儲目錄之后,storage會為文件分配一個fileid,每個存儲目錄下有兩級256*256的子目錄,storage會按文件fileid進行兩次hash(猜測),路由到其中一個子目錄,然后將文件以fileid為文件名存儲到該子目錄下

生成文件名

當文件存儲到某個子目錄后,即認為該文件存儲成功,接下來會為該文件生成一個文件名,文件名由group、存儲目錄、兩級子目錄、fileid、文件后綴名(由客戶端指定,主要用於區分文件類型)拼接而成。

文件同步

寫文件時,客戶端將文件寫至group內一個storage server即認為寫文件成功,storage server寫完文件后,會由后台線程將文件同步至同group內其他的storage server。

每個storage寫文件后,同時會寫一份binlog,binlog里不包含文件數據,只包含文件名等元信息,這份binlog用於后台同步,storage會記錄向group內其他storage同步的進度,以便重啟后能接上次的進度繼續同步;進度以時間戳的方式進行記錄,所以最好能保證集群內所有server的時鍾保持同步。

storage的同步進度會作為元數據的一部分匯報到tracker上,tracke在選擇讀storage的時候會以同步進度作為參考。

比如一個group內有A、B、C三個storage server,A向C同步到進度為T1 (T1以前寫的文件都已經同步到B上了),B向C同步到時間戳為T2(T2 > T1),tracker接收到這些同步進度信息時,就會進行整理,將最小的那個做為C的同步時間戳,本例中T1即為C的同步時間戳為T1(即所有T1以前寫的數據都已經同步到C上了);同理,根據上述規則,tracker會為A、B生成一個同步時間戳。

Download file

客戶端upload file成功后,會拿到一個storage生成的文件名,接下來客戶端根據這個文件名即可訪問到該文件。

跟upload file一樣,在download file時客戶端可以選擇任意tracker server。

tracker發送download請求給某個tracker,必須帶上文件名信息,tracke從文件名中解析出文件的group、大小、創建時間等信息,然后為該請求選擇一個storage用來服務讀請求。由於group內的文件同步時在后台異步進行的,所以有可能出現在讀到時候,文件還沒有同步到某些storage server上,為了盡量避免訪問到這樣的storage,tracker按照如下規則選擇group內可讀的storage。

1. 該文件上傳到的源頭storage - 源頭storage只要存活着,肯定包含這個文件,源頭的地址被編碼在文件名中。 
2. 文件創建時間戳==storage被同步到的時間戳且(當前時間-文件創建時間戳) > 文件同步最大時間(如5分鍾) - 文件創建后,認為經過最大同步時間后,肯定已經同步到其他storage了。 
3. 文件創建時間戳 < storage被同步到的時間戳。 - 同步時間戳之前的文件確定已經同步了 。
4. (當前時間-文件創建時間戳) > 同步延遲閥值(如一天)。 - 經過同步延遲閾值時間,認為文件肯定已經同步了。

小文件合並存儲

將小文件合並存儲主要解決如下幾個問題:
1. 本地文件系統inode數量有限,從而存儲的小文件數量也就受到限制。 
2. 多級目錄+目錄里很多文件,導致訪問文件的開銷很大(可能導致很多次IO) 
3. 按小文件存儲,備份與恢復的效率低

FastDFS在V3.0版本里引入小文件合並存儲的機制,可將多個小文件存儲到一個大的文件(trunk file),為了支持這個機制,FastDFS生成的文件fileid需要額外增加16個字節

1. trunk file id 
2. 文件在trunk file內部的offset 
3. 文件占用的存儲空間大小,字節對齊及刪除空間復用,文件占用存儲空間>=文件大小

每個trunk file由一個id唯一標識,trunk file由group內的trunk server負責創建(trunk server是tracker選出來的),並同步到group內其他的storage,文件存儲合並存儲到trunk file后,根據其offset就能從trunk file讀取到文件。

文件在trunk file內的offset編碼到文件名,決定了其在trunk file內的位置是不能更改的,也就不能通過compact的方式回收trunk file內刪除文件的空間。但當trunk file內有文件刪除時,其刪除的空間是可以被復用的,比如一個100KB的文件被刪除,接下來存儲一個99KB的文件就可以直接復用這片刪除的存儲空間。

HTTP訪問支持

FastDFS的tracker和storage都內置了http協議的支持,客戶端可以通過http協議來下載文件,tracker在接收到請求時,通過http的redirect機制將請求重定向至文件所在的storage上;除了內置的http協議外,FastDFS還提供了通過apache或nginx擴展模塊下載文件的支持。

 

其他特性

FastDFS提供了設置/獲取文件擴展屬性的接口(setmeta/getmeta),擴展屬性以key-value對的方式存儲在storage上的同名文件(擁有特殊的前綴或后綴),比如/group/M00/00/01/some_file為原始文件,則該文件的擴展屬性存儲在/group/M00/00/01/.some_file.meta文件(真實情況不一定是這樣,但機制類似),這樣根據文件名就能定位到存儲擴展屬性的文件。

以上兩個接口作者不建議使用,額外的meta文件會進一步“放大”海量小文件存儲問題,同時由於meta非常小,其存儲空間利用率也不高,比如100bytes的meta文件也需要占用4K(block_size)的存儲空間。

FastDFS還提供appender file的支持,通過upload_appender_file接口存儲,appender file允許在創建后,對該文件進行append操作。實際上,appender file與普通文件的存儲方式是相同的,不同的是,appender file不能被合並存儲到trunk file。


 安裝單機版FastDFS

將安裝包上傳到服務器的/usr/local/software目錄下

安裝所需的依賴包

yum install make cmake gcc gcc-c++

這個下載的過程很慢。中間會遇到兩次確認,[Y/N],選擇Y確認

安裝libfatscommon

unzip libfastcommon-master.zip   進入解壓后的路徑,執行./make.sh

等編譯完成后,執行./make.sh install

安裝FastDFS

返回/usr/local/software目錄,解壓fastdfs-master.zip

 

unzip fastdfs-master.zip

進入解壓后的目錄,執行編譯命令

cd fastdfs-master

./make.sh

等編譯成功后,進行安裝

cd ..

 

配置Tracker服務器

創建base_path目錄

在software下創建fastdfs文件文件夾,在里面再寫一個tracker文件夾。

創建文件夾的命令是:

你也可以把tracker創建在別的地方,只要在配置文件中填寫好你存放數據的位置就行。

我存放數據的路徑是/usr/local/software/fastdfs/tracker

修改tracker配置文件

復制tracker的配置文件並重命名,編輯配置文件

 開放端口

如果你直接關閉了防火牆,可以省略這一步。

使用iptables開放如下端口
/sbin/iptables -I INPUT -p tcp --dport 22122 -j ACCEPT
保存
/etc/rc.d/init.d/iptables save
重啟服務
service iptables restart

啟動tracker

 

啟動命令:

/etc/init.d/fdfs_trackerd start

啟動成功后tracker目錄下會生成兩個文件夾

可以使用命令查看tracker的運行狀態:

ps -ef | grep fdfs_trackerd

配置Storage服務器

注:實際開發中,tracker和storage是在不同的服務器上的,所以安裝tracker和storage都要執行第1.1-1.3節中的步驟。在本課程中,只使用一台服務器,所以配置storage的時候省略了1.1-1.3節中的操作。

創建base_path目錄

mkdir -p /usr/local/software/fastdfs/storage

 

修改storage配置文件

cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf

vim /etc/fdfs/storage.conf

往下找,還有個store_path0和tracker_server, tracker_server的ip就是tracker服務器的ip

 

開放端口

如果你直接關閉了防火牆,可以省略這一步。

使用iptables開放如下端口
/sbin/iptables -I INPUT -p tcp --dport 23000 -j ACCEPT
保存
/etc/rc.d/init.d/iptables save
重啟服務
service iptables restart

啟動storage

/etc/init.d/fdfs_storaged start

pwd使用命令查看storage的運行狀態:

ps -ef | grep fdfs_storaged

測試

cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf

vim /etc/fdfs/client.conf          

修改下面這兩行為tracker的配置

保存並退出

執行

/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /usr/1712.txt

最后一個/usr/1712.txt是提前放到服務器上的文件。

返回的group1/xxxxx就是上傳成功后的訪問地址。暫時還不能通過http查看。

與nginx整合

把壓縮包上傳到/usr/local/software目錄下

解壓

unzip fastdfs-nginx-module-master.zip

進入解壓后的路徑

cd /usr/local/software/fastdfs-nginx-module-master/src

將mod_fastdfs.conf復制到/etc/fdfs下

cp mod_fastdfs.conf /etc/fdfs

修改下面的配置:

將libfdfsclient.so拷貝至/usr/lib下

cp /usr/lib64/libfdfsclient.so /usr/lib/ 

將/usr/local/software/fastdfs-master/conf下這兩個文件復制過去

創建nginx/client目錄

mkdir -p /var/temp/nginx/client

nginx依賴環境參照nginx安裝文檔

將nginx壓縮包上傳到/usr/local/software下

安裝nginx

進入/usr/local/software/nginx-1.10.0

安裝依賴包

 

yum -y install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel

這個下載的過程有點慢。

執行

./configure --prefix=/usr/local/software/nginx --sbin-path=/usr/bin/nginx --add-module=/usr/local/software/fastdfs-nginx-module-master/src

編譯后執行 make,再執行  make install

修改/usr/local/software/nginx/conf/nginx.conf

添加server:

server {

        listen       8888;

        server_name  localhost;

 

        location /group1/M00/{

ngx_fastdfs_module;

        }

}

說明:

server_name指定本機ip

location /group1/M00/:group1為nginx 服務FastDFS的分組名稱,M00是FastDFS自動生成編號,對應store_path0,如果FastDFS定義store_path1,這里就是M01

8888端口號與/etc/fdfs/storage.conf中的http.server_port=8888相對應

啟動nginx

nginx

停止nginx

nginx -s stop

重新啟動

nginx -s reload

 

java操作fastDFS文件上傳

 

下載工程https://github.com/happyfish100/fastdfs-client-java

安裝到自己的maven倉庫

導入jar包:

1 <!-- fastdfs -->
2 <dependency>
3     <groupId>org.csource</groupId>
4     <artifactId>fastdfs-client-java</artifactId>
5     <version>1.27-SNAPSHOT</version>
6 </dependency>

創建配置文件client.conf:

1 tracker_server=服務器的ip或域名:22122

測試方法:

 1 import org.csource.fastdfs.*;
 2 
 3 public class FastDFSTest {
 4     public static void main(String[] args) throws Exception {
 5         // 1、向工程中添加jar包
 6         // 2、創建一個配置文件。配置tracker服務器地址
 7         // 3、加載配置文件(絕對路徑,工程目錄不要有中文)
 8         ClientGlobal.init(FastDFSTest.class.getResource("/").getPath() + "client.conf");
 9         // 4、創建一個TrackerClient對象。
10         TrackerClient trackerClient = new TrackerClient();
11         // 5、使用TrackerClient對象獲得trackerserver對象。
12         TrackerServer trackerServer = trackerClient.getConnection();
13         // 6、創建一個StorageServer的引用null就可以。
14         StorageServer storageServer = null;
15         // 7、創建一個StorageClient對象。trackerserver、StorageServer兩個參數。
16         StorageClient storageClient = new StorageClient(trackerServer, storageServer);
17         // 8、使用StorageClient對象上傳文件。
18         String[] strings = storageClient.upload_file("f:/qf_logo.jpg", "jpg", null);
19         for (String string : strings) {
20             System.out.println(string);
21         }
22     }
23 }

封裝工具類:

 1 public class FastDFSClient {
 2 
 3    private TrackerClient trackerClient = null;
 4    private TrackerServer trackerServer = null;
 5    private StorageServer storageServer = null;
 6    private StorageClient1 storageClient = null;
 7    
 8    public FastDFSClient(String conf) throws Exception {
 9       if (conf.contains("classpath:")) {
10          conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
11       }
12       ClientGlobal.init(conf);
13       trackerClient = new TrackerClient();
14       trackerServer = trackerClient.getConnection();
15       storageServer = null;
16       storageClient = new StorageClient1(trackerServer, storageServer);
17    }
18    
19    /**
20     * 上傳文件方法
21     * <p>Title: uploadFile</p>
22     * <p>Description: </p>
23     * @param fileName 文件全路徑
24     * @param extName 文件擴展名,不包含(.)
25     * @param metas 文件擴展信息
26     * @return
27     * @throws Exception
28     */
29    public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
30       String result = storageClient.upload_file1(fileName, extName, metas);
31       return result;
32    }
33    
34    public String uploadFile(String fileName) throws Exception {
35       return uploadFile(fileName, null, null);
36    }
37    
38    public String uploadFile(String fileName, String extName) throws Exception {
39       return uploadFile(fileName, extName, null);
40    }
41    
42    /**
43     * 上傳文件方法
44     * <p>Title: uploadFile</p>
45     * <p>Description: </p>
46     * @param fileContent 文件的內容,字節數組
47     * @param extName 文件擴展名
48     * @param metas 文件擴展信息
49     * @return
50     * @throws Exception
51     */
52    public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {
53       
54       String result = storageClient.upload_file1(fileContent, extName, metas);
55       return result;
56    }
57    
58    public String uploadFile(byte[] fileContent) throws Exception {
59       return uploadFile(fileContent, null, null);
60    }
61    
62    public String uploadFile(byte[] fileContent, String extName) throws Exception {
63       return uploadFile(fileContent, extName, null);
64    }
65 }
66 測試方法:
67 FastDFSClient fastDFSClient = new FastDFSClient(
68         "classpath:client.conf");
69 String string = fastDFSClient.uploadFile("f:/logo.jpg");
70 System.out.println(string);

返回結果:

group1/M00/00/00/CscAbloEvACATPsCAALl54RJz6c951.jpg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM