天天看點

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

原标題:JavaWeb項目架構之FastDFS分布式檔案系統

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

概述

分布式檔案系統:Distributed file system, DFS,又叫做網絡檔案系統:Network File System。一種允許檔案通過網絡在多台主機上分享的檔案系統,可讓多機器上的多使用者分享檔案和存儲空間。

FastDFS是用c語言編寫的一款開源的分布式檔案系統,充分考慮了備援備份、負載均衡、線性擴容等機制,并注重高可用、高性能等名額,功能包括:檔案存儲、檔案同步、檔案通路(檔案上傳、檔案下載下傳)等,解決了大容量存儲和負載均衡的問題。特别适合中小檔案(建議範圍:4KB < file_size <500MB),對以檔案為載體的線上服務,如相冊網站、視訊網站等。

FastDFS 架構

FastDFS架構包括Tracker server和Storage server。用戶端請求Tracker server進行檔案上傳、下載下傳,通過Tracker server排程最終由Storage server完成檔案上傳和下載下傳。

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

跟蹤伺服器Tracker Server

主要做排程工作,起到均衡的作用;負責管理所有的 storage server和 group,每個 storage 在啟動後會連接配接 Tracker,告知自己所屬 group 等資訊,并保持周期性心跳。tracker根據storage的心跳資訊,建立group==>[storage serverlist]的映射表。

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

存儲伺服器Storage Server

主要提供容量和備份服務;以 group 為機關,每個 group 内可以有多台 storage server,資料互為備份。以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的方式被路由到其中某個子目錄下,然後将檔案資料作為本地檔案存儲到該目錄中。

FastDFS的存儲政策

為了支援大容量,存儲節點(伺服器)采用了分卷(或分組)的組織方式。存儲系統由一個或多個卷組成,卷與卷之間的檔案是互相獨立的,所有卷的檔案容量累加就是整個存儲系統中的檔案容量。一個卷可以由一台或多台存儲伺服器組成,一個卷下的存儲伺服器中的檔案都是相同的,卷中的多台存儲伺服器起到了備援備份和負載均衡的作用。

在卷中增加伺服器時,同步已有的檔案由系統自動完成,同步完成後,系統自動将新增伺服器切換到線上提供服務。當存儲空間不足或即将耗盡時,可以動态添加卷。隻需要增加一台或多台伺服器,并将它們配置為一個新的卷,這樣就擴大了存儲系統的容量。

FastDFS的上傳過程

FastDFS向使用者提供基本檔案通路接口,比如upload、download、append、delete等,以用戶端庫的方式提供給使用者使用。

Storage Server會定期的向Tracker Server發送自己的存儲資訊。當Tracker Server Cluster中的Tracker Server不止一個時,各個Tracker之間的關系是對等的,是以用戶端上傳時可以選擇任意一個Tracker。

當Tracker收到用戶端上傳檔案的請求時,會為該檔案配置設定一個可以存儲檔案的group,當選定了group後就要決定給用戶端配置設定group中的哪一個storage server。當配置設定好storage server後,用戶端向storage發送寫檔案請求,storage将會為檔案配置設定一個資料存儲目錄。然後為檔案配置設定一個fileid,最後根據以上的資訊生成檔案名存儲檔案。

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

選擇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、檔案字尾名(由用戶端指定,主要用于區分檔案類型)拼接而成。

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

FastDFS的檔案同步

寫檔案時,用戶端将檔案寫至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生成一個同步時間戳。

FastDFS的檔案下載下傳

用戶端uploadfile成功後,會拿到一個storage生成的檔案名,接下來用戶端根據這個檔案名即可通路到該檔案。

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

跟upload file一樣,在downloadfile時用戶端可以選擇任意tracker server。tracker發送download請求給某個tracker,必須帶上檔案名資訊,tracke從檔案名中解析出檔案的group、大小、建立時間等資訊,然後為該請求選擇一個storage用來服務讀請求。

FastDFS性能方案

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

FastDFS 安裝

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

下載下傳安裝libfastcommon

下載下傳

解壓

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

編譯、安裝

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

建立軟連結

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

下載下傳安裝FastDFS

下載下傳FastDFS

解壓

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

編譯、安裝

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

配置 Tracker 服務

上述安裝成功後,在/etc/目錄下會有一個fdfs的目錄,進入它。會看到三個.sample字尾的檔案,這是作者給我們的示例檔案,我們需要把其中的tracker.conf.sample檔案改為tracker.conf配置檔案并修改它:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

編輯tracker.conf

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

建立tracker基礎資料目錄,即base_path對應的目錄

使用ln -s 建立軟連結

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

啟動服務:

檢視監聽:

如果看到22122端口正常被監聽後,這時候說明Tracker服務啟動成功啦!

tracker server 目錄及檔案結構

Tracker服務啟動成功後,會在base_path下建立data、logs兩個目錄。目錄結構如下:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

配置 Storage 服務

進入 /etc/fdfs 目錄,複制 FastDFS 存儲器樣例配置檔案 storage.conf.sample,并重命名為 storage.conf

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

編輯storage.conf

# 配置檔案是否不生效,false 為生效disabled=false

# 指定此 storage server 所在 組(卷)

group_name=group1

# storage server 服務端口

port=23000

# 心跳間隔時間,機關為秒 (這裡是指主動向 tracker server 發送心跳)

heart_beat_interval=30

# Storage 資料和日志目錄位址(根目錄必須存在,子目錄會自動生成)

base_path=/home/data/fastdfs/storage

# 存放檔案時 storage server 支援多個路徑。這裡配置存放檔案的基路徑數目,通常隻配一個目錄。

store_path_count=1

# 逐一配置 store_path_count 個路徑,索引号基于 0。

# 如果不配置 store_path0,那它就和 base_path 對應的路徑一樣。store_path0=/home/data/fastdfs/storage

# FastDFS 存儲檔案時,采用了兩級目錄。這裡配置存放檔案的目錄個數。

# 如果本參數隻為 N(如: 256),那麼 storage server 在初次運作時,會在 store_path 下自動建立 N * N 個存放檔案的子目錄。subdir_count_per_path=256

# tracker_server 的清單 ,會主動連接配接 tracker_server

# 有多個 tracker server 時,每個 tracker server 寫一行

tracker_server=192.168.1.190:22122

# 允許系統同步的時間段 (預設是全天) 。一般用于避免高峰同步産生一些問題而設定。

sync_start_time=00:00

sync_end_time=23:59

使用ln -s 建立軟連結

啟動服務

檢視監聽

啟動Storage前確定Tracker是啟動的。初次啟動成功,會在 /home/data/fastdfs/storage 目錄下建立 data、 logs 兩個目錄。如果看到23000端口正常被監聽後,這時候說明Storage服務啟動成功啦!

檢視Storage和Tracker是否在通信

FastDFS 配置 Nginx 子產品

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

FastDFS 通過 Tracker 伺服器,将檔案放在 Storage 伺服器存儲, 但是同組存儲伺服器之間需要進行檔案複制,有同步延遲的問題。

假設 Tracker 伺服器将檔案上傳到了 192.168.1.190,上傳成功後檔案 ID已經傳回給用戶端。此時 FastDFS 存儲叢集機制會将這個檔案同步到同組存192.168.1.190,在檔案還沒有複制完成的情況下,用戶端如果用這個檔案 ID 在 192.168.1.190 上取檔案,就會出現檔案無法通路的錯誤。而 fastdfs-nginx-module 可以重定向檔案連結到源伺服器取檔案,避免用戶端由于複制延遲導緻的檔案無法通路錯誤。

下載下傳 安裝 Nginx 和 fastdfs-nginx-module:

推薦您使用yum安裝以下的開發庫:

下載下傳最新版本并解壓:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

配置 nginx 安裝,加入fastdfs-nginx-module子產品:

編譯、安裝:

檢視Nginx的子產品:

有下面這個就說明添加子產品成功

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

複制 fastdfs-nginx-module 源碼中的配置檔案到/etc/fdfs 目錄, 并修改:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

複制 FastDFS 的部配置設定置檔案到/etc/fdfs 目錄:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

配置nginx,修改nginx.conf:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

啟動Nginx:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

測試上傳:

[[email protected] fdfs]# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /etc/fdfs/4.jpg

group1/M00/00/00/rBD8EFqVACuAI9mcAAC_ornlYSU088.jpg

部署結構圖:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

JAVA 用戶端內建

pom.xml引入:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

fdfs_client.conf配置:

java檔案系統_JavaWeb項目架構之FastDFS分布式檔案系統

FastDFSClient上傳類:

public class FastDFSClient{

private static final String CONFIG_FILENAME = "D:itstylesrcmainresourcesfdfs_client.conf";

private static final String GROUP_NAME = "market1";

private TrackerClient trackerClient = null; private TrackerServer trackerServer = null; private StorageServer storageServer = null; private StorageClient storageClient = null; static{

try {

ClientGlobal.init(CONFIG_FILENAME);

} catch (IOException e) {

e.printStackTrace();

} catch (MyException e) {

e.printStackTrace();

}

} public FastDFSClient() throws Exception {

trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);

trackerServer = trackerClient.getConnection();

storageServer = trackerClient.getStoreStorage(trackerServer);;

storageClient = new StorageClient(trackerServer, storageServer);

}

public String[] uploadFile(File file, String fileName) {

return uploadFile(file,fileName,null);

}

public String[] uploadFile(File file, String fileName, Map metaList) { try {

byte[] buff = IOUtils.toByteArray(new FileInputStream(file));

NameValuePair[] nameValuePairs = null; if (metaList != null) {

nameValuePairs = new NameValuePair[metaList.size()];

int index = 0;

for (Iterator> iterator = metaList.entrySet().iterator(); iterator.hasNext();) {

Map.Entry entry = iterator.next();

String name = entry.getKey();

String value = entry.getValue();

nameValuePairs[index++] = new NameValuePair(name,value);

}

} return storageClient.upload_file(GROUP_NAME,buff,fileName,nameValuePairs);

} catch (Exception e) {

e.printStackTrace();

} return null;

}

public Map getFileMetadata(String groupname,String fileId) { try {

NameValuePair[] metaList = storageClient.get_metadata(groupname,fileId); if (metaList != null) {

HashMap map = new HashMap();

for (NameValuePair metaItem : metaList) {

map.put(metaItem.getName(),metaItem.getValue());

}

return map;

}

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

public int deleteFile(String groupname,String fileId) { try { return storageClient.delete_file(groupname,fileId);

} catch (Exception e) {

e.printStackTrace();

} return -1;

}

public int downloadFile(String groupName,String fileId, File outFile) {

FileOutputStream fos = null;

try {

byte[] content = storageClient.download_file(groupName,fileId);

fos = new FileOutputStream(outFile);

InputStream ips = new ByteArrayInputStream(content);

IOUtils.copy(ips,fos);

return 0;

} catch (Exception e) {

e.printStackTrace();

} finally {

if (fos != null) {

try {

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

} return -1;

} public static void main(String[] args) throws Exception {

FastDFSClient client = new FastDFSClient();

File file = new File("D:23456.png");

String[] result = client.uploadFile(file, "png");

System.out.println(result.length);

System.out.println(result[0]);

System.out.println(result[1]);

}

}

執行main方法測試傳回:

責任編輯: