FastDFS 分布式文件系統(tǒng)

簡(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ǔ)

fastDFS架構(gòu)圖.jpeg

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:文件路徑

下載

FASTDFS下載.jpeg
/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;
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尔艇,一起剝皮案震驚了整個(gè)濱河市尔许,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌终娃,老刑警劉巖味廊,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異棠耕,居然都是意外死亡毡们,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)昧辽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衙熔,“玉大人,你說(shuō)我怎么就攤上這事搅荞『炻龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵咕痛,是天一觀的道長(zhǎng)痢甘。 經(jīng)常有香客問(wèn)我,道長(zhǎng)茉贡,這世上最難降的妖魔是什么塞栅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮腔丧,結(jié)果婚禮上放椰,老公的妹妹穿的比我還像新娘。我一直安慰自己愉粤,他們只是感情好砾医,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著衣厘,像睡著了一般如蚜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上影暴,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天错邦,我揣著相機(jī)與錄音,去河邊找鬼型宙。 笑死撬呢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的早歇。 我是一名探鬼主播倾芝,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼箭跳!你這毒婦竟也來(lái)了晨另?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谱姓,失蹤者是張志新(化名)和其女友劉穎借尿,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屉来,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡路翻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茄靠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茂契。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖慨绳,靈堂內(nèi)的尸體忽然破棺而出掉冶,到底是詐尸還是另有隱情,我是刑警寧澤脐雪,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布厌小,位于F島的核電站,受9級(jí)特大地震影響战秋,放射性物質(zhì)發(fā)生泄漏璧亚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一脂信、第九天 我趴在偏房一處隱蔽的房頂上張望癣蟋。 院中可真熱鬧,春花似錦狰闪、人聲如沸梢薪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秉撇。三九已至,卻和暖如春秋泄,著一層夾襖步出監(jiān)牢的瞬間琐馆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工恒序, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘦麸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓歧胁,卻偏偏與公主長(zhǎng)得像滋饲,于是被迫代替她去往敵國(guó)和親厉碟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容