簡(jiǎn)介
FastDFS 是基于 C 語(yǔ)言開(kāi)發(fā)的吵冒,是一個(gè)輕量級(jí)開(kāi)源的高性能分布式文件系統(tǒng)。主要功能有:文件存儲(chǔ)、文件同步、文件訪問(wèn)(文件上傳/下載)惩淳,解決了大容量的文件存儲(chǔ)和高并發(fā)訪問(wèn)的問(wèn)題,文件存取時(shí)實(shí)現(xiàn)了負(fù)載均衡乓搬。FastDFS 特別適合中大型網(wǎng)站以文件為載體的在線服務(wù)思犁,適合存儲(chǔ) 4KB ~ 500MB 之間的小文件,如照片共享網(wǎng)站进肯、視頻共享網(wǎng)站(圖片激蹲、文檔、音頻江掩、視頻等等)学辱。
術(shù)語(yǔ)
Client 客戶端,實(shí)現(xiàn)文件上傳下載的服務(wù)器环形,就是我們自己的項(xiàng)目所部署在的服務(wù)器策泣。通過(guò)專(zhuān)有接口,使用 TCP/IP 協(xié)議與跟蹤服務(wù)器或存儲(chǔ)服務(wù)器進(jìn)行數(shù)據(jù)交互抬吟。FastDFS 向使用者提供基本文件訪問(wèn)接口萨咕,比如 upload、download火本、append危队、delete等,以客戶端庫(kù)的方式提供給用戶使用钙畔。
Tracker Server 跟蹤服務(wù)器茫陆,負(fù)責(zé)文件訪問(wèn)的調(diào)度和負(fù)載均衡,負(fù)責(zé)管理所有的 Storage Server 和 group 組/卷擎析。
Storage Server 存儲(chǔ)服務(wù)器簿盅,負(fù)責(zé)文件存儲(chǔ),文件同步/備份,提供文件訪問(wèn)接口桨醋,文件元數(shù)據(jù)管理见秽。以 group 為單位,每個(gè) group 內(nèi)可以有多臺(tái) Storage Server讨盒,數(shù)據(jù)互為備份解取,達(dá)到容災(zāi)的目的。每個(gè) Storage 在啟動(dòng)以后會(huì)主動(dòng)連接 Tracker返顺,告知自己所屬 group 等存儲(chǔ)相關(guān)信息禀苦,并保持周期性心跳。
Group 組遂鹊,也可稱為 Volume 卷振乏。同組內(nèi)服務(wù)器上的文件是完全相的,同一組內(nèi)的 Storage Server 之間是對(duì)等的秉扑,文件上傳慧邮、刪除等操作可以在任意一臺(tái) Storage Server 上進(jìn)行。
Metadata 文件系統(tǒng)中存儲(chǔ)的數(shù)據(jù)分為數(shù)據(jù)和元數(shù)據(jù)兩部分舟陆,數(shù)據(jù)是指文件中的實(shí)際數(shù)據(jù)误澳,即文件的實(shí)際內(nèi)容;而元數(shù)據(jù)是用來(lái)描述一個(gè)文件特征的系統(tǒng)數(shù)據(jù)秦躯,諸如訪問(wèn)權(quán)限忆谓、文件擁有者以及文件數(shù)據(jù)塊的分布信息等等。如果文件是一張圖片踱承,元數(shù)據(jù)就是圖片的寬倡缠,高等等。
安裝
下載資源
1茎活、github: https://github.com/happyfish100
下載 libfastcommon 昙沦, fastdfs ,fastdfs-nginx-module载荔、libserverframe 三個(gè)項(xiàng)目對(duì)應(yīng)的壓縮包
2盾饮、通過(guò)資源地址:https://sourceforge.net/projects/fastdfs/files/ 下載
3、giteet: https://toscode.gitee.com/fastdfs100/projects
libfastcommon :從 fastdfs 項(xiàng)目和 fastdht 項(xiàng)目中提取出來(lái)的公共 C 函數(shù)庫(kù)身辨。
fastdfs :FastDFS 核心項(xiàng)目丐谋。
fastdfs-nginx-module :Nginx 整合 FastDFS 時(shí) Nginx 需要添加的模塊資源芍碧。
libserverframe :網(wǎng)絡(luò)框架庫(kù) libserverframe煌珊,替換原有的 tracker nio 和 storage nio 兩個(gè)模塊
安裝依賴
FastDFS 是基于 C 語(yǔ)言開(kāi)發(fā)的,安裝它之前必須先安裝它所依賴的環(huán)境泌豆。
yum install -y make cmake gcc gcc-c++
安裝zip定庵、unzip
yum install zip
yum install unzip
libfastcommon-master.zip
#解壓 libfastcommon-master 至當(dāng)前所在目錄
unzip libfastcommon-master.zip
# 進(jìn)入解壓后的 libfastcommon-master 目錄
cd libfastcommon-master
# 編譯并安裝
./make.sh && ./make.sh install
fastdfs-master.zip
#解壓 libserverframe-maste 至當(dāng)前所在目錄
unzip libserverframe-master.zip
# 進(jìn)入解壓后的 libfastcommon-master 目錄
cd libserverframe-master
# 編譯并安裝
./make.sh && ./make.sh install
fastdfs 默認(rèn)安裝在以下位置:
/usr/bin :可執(zhí)行文件
/etc/fdfs :配置文件
/etc/init.d :主程序代碼 (如果改文件中沒(méi)有 fdfs_storaged 和fdfs_trackerd 時(shí),拷貝fastdfs-master中init.d總共的文件)
/usr/include/fastdfs :插件組
啟動(dòng) Tracker
tracker 和 storage 其實(shí)都是 fastdfs ,只不過(guò)啟動(dòng)時(shí)通過(guò)不同的配置文件啟動(dòng)蔬浙,所扮演的角色不同而已猪落。也就是說(shuō),安裝 tracker 和 storage 就是在安裝 fastdfs 畴博,然后通過(guò)每個(gè)角色具體的配置文件啟動(dòng)即可笨忌。
查看 /etc/fdfs 目錄下所有配置文件。
client.conf http.conf mime.types storage.conf storage_ids.conf tracker.conf
client.conf.sample :客戶端的配置文件俱病,測(cè)試用 storage.conf.sample :存儲(chǔ)器的配置文件 tracker.conf.sample :跟蹤器的配置文件
編輯 tracker.conf 配置文件
#允許訪問(wèn) tracker 服務(wù)器的 IP 地址官疲,為空則表示不受限制
bind_addr =
#tracker 服務(wù)監(jiān)聽(tīng)端口
port = 22122
#tracker 服務(wù)器的運(yùn)行數(shù)據(jù)和日志的存儲(chǔ)父路徑(需要提前創(chuàng)建好)
base_path = /fastdfs/tracker
#tracker 服務(wù)器 HTTP 協(xié)議下暴露的端口
http.server_port = 8080
啟動(dòng) tracker 服務(wù)
#創(chuàng)建 tracker 服務(wù)器的運(yùn)行數(shù)據(jù)和日志的存儲(chǔ)父路徑
mkdir -p /fastdfs/tracker
#啟動(dòng) tracker 服務(wù)
service fdfs_trackerd start
#查看 tracker 服務(wù)狀態(tài)
service fdfs_trackerd status
#重啟 tracker 服務(wù)
service fdfs_trackerd restart
#停止 tracker 服務(wù)
service fdfs_trackerd stop
啟動(dòng) Storage
編輯 storage.conf 配置文件
#storage 組名/卷名,默認(rèn)為 group1
group_name = group1
#允許訪問(wèn) storage 服務(wù)器的 IP 地址亮隙,為空則表示不受限制
bind_addr =
#storage 服務(wù)器的運(yùn)行數(shù)據(jù)和日志的存儲(chǔ)父路徑(需要提前創(chuàng)建好)
base_path = /fastdfs/storage/base
#storage 服務(wù)器中客戶端上傳的文件的存儲(chǔ)父路徑(需要提前創(chuàng)建好)
store_path0 = /fastdfs/storage/store
#storage 服務(wù)器 HTTP 協(xié)議下暴露的端口
http.server_port = 8888
#tracker 服務(wù)器的 IP 和端口
tracker_server = 192.168.10.101:22122
啟動(dòng) storage 服務(wù)
#創(chuàng)建 storage 服務(wù)器的運(yùn)行數(shù)據(jù)和日志的存儲(chǔ)父路徑
mkdir -p /fastdfs/storage/base
#創(chuàng)建 storage 服務(wù)器中客戶端上傳的文件的存儲(chǔ)父路徑
mkdir -p /fastdfs/storage/store
#啟動(dòng) storage 服務(wù)
service fdfs_storaged start
#查看 storage 服務(wù)狀態(tài)
service fdfs_storaged status
#重啟 storage 服務(wù)
service fdfs_storaged restart
#停止 storage 服務(wù)
service fdfs_storaged stop
Client 操作
FastDFS 向使用者提供基本文件訪問(wèn)接口途凫,比如 upload、download溢吻、append维费、delete 等,以客 戶端庫(kù)的方式提供給用戶使用促王。
編輯 client.conf 配置文件
#client 客戶端的運(yùn)行數(shù)據(jù)和日志的存儲(chǔ)父路徑(需要提前創(chuàng)建好)
base_path = /fastdfs/client
#tracker 服務(wù)器的 IP(配置虛擬ip eth0) 和端口
tracker_server = 192.168.10.101:22122
記得 mkdir -p /fastdfs/client 創(chuàng)建 Client 目錄
注:
開(kāi)放22122和23000端口
上傳
1犀盟、進(jìn)入/usr/bin目錄
2、執(zhí)行上傳命令
./fdfs_upload_file /etc/fdfs/client.conf /usr/local/tool/FastDFS/libfastcommon-master.zip
3蝇狼、返回
group1/M00/00/00/MekNfmN9yjSAez-uAAVXdOvFp2k246.zip
注:
group1:卷名
M00:虛擬磁盤(pán)路徑且蓬。與 Storage 配置文件中磁盤(pán)選項(xiàng) store_path* 對(duì)應(yīng)。如果配置了store_path0 則是M00 题翰,如果配置了 store_path1 則是 M01 恶阴,以此類(lèi)推。比如:store_path0 =
00/00:文件路徑
下載
/usr/bin/fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/MekNfmN9yjSAez-uAAVXdOvFp2k246.zip
刪除
/usr/bin/fdfs_delete_file /etc/fdfs/client.conf group1/M00/00/00/MekNfmN9yjSAez-uAAVXdOvFp2k246.zip
Nginx 整合 FastDFS 時(shí) Nginx 需要添加 fastdfs-nginx-module 模塊
fastdfs-nginx-module-master.zip
cp src/mod_fastdfs.conf /etc/fdfs/
vim /etc/fdfs/mod_fastdfs.conf 編輯配置文件豹障,主要關(guān)注以下部分
#tracker 服務(wù)器的 IP 和端口
tracker_server = 192.168.10.101:22122
#url 地址是否包含組名/卷名
url_have_group_name = true
#數(shù)據(jù)組/卷對(duì)應(yīng)的路徑地址
store_path0 = /fastdfs/storage/store
復(fù)制 fastdfs 安裝包中的兩個(gè)配置文件 http.conf 和 mime.types 到 /etc/fdfs 目錄中
cp fastdfs-master/conf/http.conf /etc/fdfs/
cp fastdfs-master/conf/mime.types /etc/fdfs/
配置 Nignx
指定安裝模塊
--add-module=/usr/local/src/fastdfs-nginx-module-master/src
nginx.conf 編輯配置文件
location ~/group[0-9]/{
ngx_fastdfs_module;
}
項(xiàng)目使用
下載項(xiàng)目fastdfs-client-java并打成jar
pom
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.29-SNAPSHOT</version>
</dependency>
配置
添加配置文件fdfs_client.conf冯事,增加以下配置
connect_timeout = 2
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
http.anti_steal_token = no
http.secret_key = FastDFS1234567890
tracker_server = 192.168.56.10:22122
http.anti_steal_token:配置防盜鏈,no表示不開(kāi)啟(詳細(xì)參考FastDFS防盜鏈一節(jié)) http.secret_key:防盜鏈密碼 tracker_server:tracker連接信息血公,有多少tracker就配置幾個(gè)
工具類(lèi)
public class FastDfsUtil {
private static Logger logger = LoggerFactory.getLogger(FastDfsUtil.class);
// 獲取配置文件地址
private static final String CONF_FILENAME = Thread.currentThread() .getContextClassLoader().getResource("").getPath() + "fdfs_client.conf";
// Storage 存儲(chǔ)服務(wù)器客戶端
private static StorageClient storageClient = null;
static {
try {
// 加載配置文件
ClientGlobal.init(CONF_FILENAME);
// 初始化 Tracker 客戶端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
// 初始化 Tracker 服務(wù)端
TrackerServer trackerServer = trackerClient.getTrackerServer();
// 初始化 Storage 服務(wù)端
StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
// 初始化 Storage 客戶端
storageClient = new StorageClient(trackerServer, storageServer);
}catch (Exception e) {
logger.error("FastDfs初始化異常",e);
}
}
/**
* 文件上傳
* @param multipartFile
* @return
*/
public static String[] uploadFile(MultipartFile multipartFile){
InputStream inputStream=null;
try {
if(!multipartFile.isEmpty()){
//獲取流
inputStream = multipartFile.getInputStream();
String fileName=multipartFile.getOriginalFilename();
// 查看文件的長(zhǎng)度
int len = inputStream.available();
// 初始化元數(shù)據(jù)數(shù)組
NameValuePair[] metaList = new NameValuePair[2];
// 第一組元數(shù)據(jù)昵仅,文件的原始名稱
metaList[0] = new NameValuePair("file_name", fileName);
// 第二組元數(shù)據(jù),文件的長(zhǎng)度
metaList[1] = new NameValuePair("file_length",String.valueOf(len));
// 創(chuàng)建對(duì)應(yīng)長(zhǎng)度的字節(jié)數(shù)組
byte[] fileBuff = fileBuff = new byte[len];
// 將輸入流中的字節(jié)內(nèi)容累魔,讀到字節(jié)數(shù)組中
inputStream.read(fileBuff);
return storageClient.upload_file(fileBuff,getFileExt(fileName),metaList);
}
}catch (Exception e){
logger.error("FastDfs上傳異常",e);
}finally {
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
logger.error("FastDfs上傳關(guān)閉流異常",e);
}
}
}
return null;
}
/**
* 獲取文件后綴名(不帶點(diǎn))
*
* @param fileName
* @return 如:"jpg" or ""
*/
private static String getFileExt(String fileName) {
if (StringUtils.isBlank(fileName) || !fileName.contains(".")) {
return "";
}
return fileName.substring(fileName.lastIndexOf(".") + 1); // 不帶最后的點(diǎn)
}
/**
* 獲取文件詳情
*
* @param groupName 組/卷名摔笤,默認(rèn)值:group1
* @param remoteFileName 文件名,例
如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
* @return 文件詳情
*/
public static FileInfo getFileInfo(String groupName, String remoteFileName){
try {
return storageClient.get_file_info(groupName == null ? "group1" :groupName, remoteFileName);
} catch (Exception e) {
logger.error("FastDfs獲取文件詳情異常",e);
}
return null;
}
/**
* 獲取元數(shù)據(jù)
*
* @param groupName 組/卷名垦写,默認(rèn)值:group1
* @param remoteFileName 文件名吕世,例
如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
* @return 文件的元數(shù)據(jù)數(shù)組
*/
public static NameValuePair[] getMetaData(String groupName, String remoteFileName) {
try {
// 根據(jù)組名和文件名通過(guò) Storage 客戶端獲取文件的元數(shù)據(jù)數(shù)組
return storageClient.get_metadata(groupName == null ? "group1" :groupName, remoteFileName);
} catch (Exception e) {
logger.error("FastDfs獲取文件的元數(shù)據(jù)異常",e);
}
return null;
}
/**
* 文件下載
*
* @param groupName 組/卷名,默認(rèn)值:group1
* @param remoteFileName 文件名梯投,例
如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
* @return 文件的字節(jié)輸入流
*/
public static InputStream downloadFile(String groupName, String remoteFileName) {
try {
// 根據(jù)組名和文件名通過(guò) Storage 客戶端獲取文件的字節(jié)數(shù)組
byte[] bytes = storageClient.download_file(groupName == null ? "group1" : groupName, remoteFileName);
// 返回字節(jié)流對(duì)象
InputStream inputStream = new ByteArrayInputStream(bytes);
return inputStream;
} catch (Exception e) {
logger.error("FastDfs下載異常",e);
}
return null;
}
/**
* 文件刪除
*
* @param groupName 組/卷名命辖,默認(rèn)值:group1
* @param remoteFileName 文件名况毅,例
如:"M00/00/00/wKgKZl9tkTCAJAanAADhaCZ_RF0495.jpg"
* @return 0為成功,非0為失敗
*/
public static int deleteFile(String groupName, String remoteFileName) {
int result = -1;
try {
// 根據(jù)組名和文件名通過(guò) Storage 客戶端刪除文件
result = storageClient.delete_file(groupName == null ? "group1" :groupName, remoteFileName);
} catch (Exception e) {
logger.error("FastDfs刪除異常",e);
}
return result;
}
}