天天看點

分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路

網頁右邊,向下滑有目錄索引,可以根據标題跳轉到你想看的内容
如果右邊沒有就找找左邊
分布式檔案系統分類
  1. 通用分布式檔案系統
和傳統的本地檔案系統(ext3,NTFS等)相對應。典型代表Iustre、MooseFS
  1. 優點:表中檔案系統操作方式,對開發者門檻較低
  2. 缺點:系統複雜性較高,需要支援若幹标準的檔案操作,如:目錄結構、檔案讀寫權限、檔案鎖等。複雜性更高,系統整體性能有所降低,因為要支援POSIX标準(表示可移植作業系統接口,POSIX标準定義了作業系統應該為應用程式提供的接口标準)
  1. 專用分布式檔案系統
基于google File System的思想,檔案上傳後不能修改。需要使用專有API對檔案進行通路,也可稱作分布式檔案存儲服務。典型代表:MogileFS、FastDFS、TFS。
  1. 優點:系統複雜性較低,不需要支援若幹标準的檔案操作,如:目錄結構、檔案讀寫權限、檔案鎖等,系統比較簡潔。系統整體性能較高,因為無需支援POSIX标準,可以省去支援POSIX引入的環節,系統更加高效
  2. 缺點:采用專用API,對開發者門檻較高(直接封裝成工具類)
Google FS 體系結構
  1. 兩個角色
  1. 名字伺服器(索引伺服器)
  2. 存儲伺服器
  1. 架構特點
  1. 不支援檔案修改功能
  2. 檔案分塊存儲,需要索引伺服器
  3. 一個檔案可以存儲多份,一個檔案存儲到哪些存儲伺服器,通常采用動态配置設定的方式
FastDFS簡介
  1. FastDFS是一個輕量級的開源分布式檔案系統。2008年4月份開始啟動。類似google FS的一個輕量級分布式檔案系統,存C語言實作,支援Linux、FreeBSD、AIX等UNIX系統
  2. 主要解決了大容量的檔案存儲和高并發通路的問題,檔案存取時實作了負載均衡。實作了軟體方式的磁盤陣列(RAID),可以使用廉價IDE硬碟進行存儲。并且支援存儲伺服器線上擴容。支援相同内容的檔案隻儲存一份,節約磁盤空間。
  3. FastDFS隻能通過ClientAPI通路,不支援POSIX通路方式。
  4. FastDFS特别适合大中型網站使用,用來存儲資源檔案(如:圖檔、文檔、音頻、視訊等等)
FastDFS文檔和下載下傳位址
  1. FastDFS沒有官網,但是作者happy_fish100餘慶擔任chinaunix中FastDFS闆塊版主。并且會不定期更新闆塊中内容。http://bbs.chinaunix.net
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  2. FastDFS軟體可以在sourceforge中下載下傳https://sourceforge.net/projects/fastdfs/files/(不推薦使用這種下載下傳方式,具體下載下傳請看下面環境搭建内容)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
FastDFS架構
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. Client:用戶端。使用java語言編寫的項目屬于用戶端
  2. Tracker Server:跟蹤伺服器,主要做排程工作,在通路上起均衡負載的作用。在記憶體中記錄叢集中group和storage server的狀态資訊,是連接配接Client和Storage server的樞紐
  3. Storage Server:存儲伺服器,檔案和檔案屬性(meta data)都儲存到存儲伺服器上,按組group存儲,就是上圖白色的框框,有若幹組,不同組之間不會互相通信
  1. 架構解讀
  1. 隻有兩個角色,tracker server和storage server,不需要存儲檔案索引資訊。
  2. 所有伺服器都是對等的,不存在Master-Slave關系。
  3. 不同組中storage server之間不會相信通信。
  4. 由storage server主動向tracker server報告狀态,tracker server之間不會互相通信。

一、環境搭建

先下載下傳好相關資源
  1. libfastcommon 下載下傳位址: https://github.com/happyfish100/libfastcommon/releases
  1. libfastcommon是FastDFS官方提供的,libfastcommon包含了FastDFS運作所需要的一些c語言基礎庫
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. FastDFS 下載下傳位址 https://github.com/happyfish100/fastdfs/releases

注意:請大家下載下傳6.4以上版本,推薦6.4,因為和nginx做整合時,低版本會發生沖突問題

分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
開始搭建環境
  1. 打開Linux,安裝c語言環境,不會Linux請參考文章https://blog.csdn.net/grd_java/article/details/115676099
FastDFS 是C語言開發的應用。安裝必須使用make,cmake和gcc編譯器
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
//安裝
yum install -y make cmake gcc gcc-c++
           
  1. 安裝libfastcommon
  1. 将兩個包傳過去
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  2. 解壓
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 編譯
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  2. 執行安裝(有固定的預設安裝位置。在/usr/lib64和/usr/include/fastcommon兩個目錄中)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  3. 建立軟連接配接(因為FastDFS主程式設定的lib目錄是/usr/local/lib是以需要建立軟連接配接,就是快捷方式)
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/local/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
           
  1. 解壓FastDFS
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 檔案解析
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 配置tracker
  1. 複制配置檔案(進入/etc/fdfs中,把tracker配置檔案複制一份)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
cp tracker.conf.sample tracker.conf
           
  1. 建立資料目錄(建立放置tracker資料的目錄)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
mkdir -p /usr/local/fastdfs/tracker
           
  1. 修改配置檔案(修改tracker.conf設定tracker内容存儲目錄)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  2. 啟動服務(啟動成功後,配置檔案中指定的目錄出現data目錄和logs目錄)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
service fdfs_trackerd start
           
  1. 檢視服務運作狀态
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
service fdfs_trackerd status
           
  1. 配置storage(可以和tracker不在同一台伺服器)
  1. 複制配置檔案(進入/etc/fdfs,把storage配置檔案複制一份)
[root@hadoop105 tracker]# cd /etc/fdfs/
[root@hadoop105 fdfs]# cp storage.conf.sample storage.conf
           
  1. 建立目錄(建立兩個,base用于存儲基礎資料和日志,store用于存儲上傳資料)
[root@hadoop105 fdfs]# mkdir -p /user/local/fastdfs/storage/base
[root@hadoop105 fdfs]# mkdir -p /user/local/fastdfs/storage/store
           
  1. 修改配置檔案(storage.conf配置檔案用于描述存儲服務的行為,需要進行如下修改)
[root@hadoop105 fdfs]# vim /etc/fdfs/storage.conf
# 基礎路徑,用于儲存storage server基礎資料内容和日志内容的目錄
base_path=/user/local/fastdfs/storage/base
#存儲路徑,用于儲存FastDFS中存儲檔案的目錄,就是要建立256*256個子目錄位
store_path0=/user/local/fastdfs/storage/store
# tracker服務的ip和端口,注意ip寫你自己虛拟機或伺服器ip,22122是tracker的預設端口,可以在上面tracker.conf檔案中配置
tracker_server=192.168.10.105:22122
           
  1. 啟動(成功後,指定目錄出現data和logs,path0指定目錄,隻出現data,第一次啟動需要建立256*256子目錄,會比較慢)
[root@hadoop105 fdfs]# service fdfs_storaged start
[root@hadoop105 fdfs]# service fdfs_storaged status
           

二、檔案上傳

流程說明
  1. 用戶端通路Tracker
  2. Tracker傳回Storage的ip和端口
  3. 用戶端直接通路Storage,把檔案内容和中繼資料發送過去
  4. Storage傳回檔案存儲id,包含了組名和檔案名
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 建立maven項目添加依賴
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
<dependencies>
    <!--這個依賴,作者沒有寫,是以很多人提供了很多版本,内容都一樣,如果這個失效,請去maven倉庫換一個fastdfs-client-java-->
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>
</dependencies>
           
  1. 編寫配置檔案
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8080
tracker_server = 192.168.10.105:22122
           
  1. 工具類
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
import org.apache.commons.lang3.StringUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import java.io.*;

/**
 * FastDFS 分布式檔案系統操作用戶端
 */
public class FastDFSClient {
    private static final String CONF_FILENAME=Thread.currentThread().getContextClassLoader().getResource("").getPath()+"fdfs_client.conf";

    private static StorageClient storageClient = null;
    /**
     * 隻加載一次
     */
    static{
        try {
            ClientGlobal.init(CONF_FILENAME);
            TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
            TrackerServer trackerServer = trackerClient.getConnection();
            StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
            storageClient = new StorageClient(trackerServer,storageServer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static String[] uploadFile(InputStream inputStream,String fileName){

        try {
            //檔案的中繼資料
            NameValuePair[] meta_list = new NameValuePair[2];
            //第一組中繼資料,檔案的原始名稱
            meta_list[0] = new NameValuePair("file name",fileName);
            //第二組中繼資料
            meta_list[1] = new NameValuePair("file length",inputStream.available()+"");
            //準備位元組數組
            byte[] file_buff = null;
            if (inputStream != null){
                //檢視檔案長度
                int len = inputStream.available();
                //建立對應長度的位元組數組
                file_buff = new byte[len];
                //将輸入流中的位元組内容,讀到位元組數組中
                inputStream.read(file_buff);
            }
            //上傳檔案。參數含義:要上傳的檔案内容(使用位元組數組傳遞),上傳的檔案的類型(擴充名),中繼資料
            String[] fileids = storageClient.upload_appender_file(file_buff,getFileExt(fileName),meta_list);
            return fileids;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String[] uploadFile(File file,String fileName){
        FileInputStream fis = null;
        try {
            NameValuePair[] meta_list = null;
            fis = new FileInputStream(file);
            byte[] file_buff = null;
            if(fis != null){
                int len = fis.available();
                file_buff = new byte[len];
                fis.read(file_buff);
            }
            String[] fileids = storageClient.upload_file(file_buff,getFileExt(fileName),meta_list);
            return fileids;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally {
            if(fis != null){
                try{
                    fis.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 根據組名和遠端檔案名來删除一個檔案
     * @param groupName
     * @param remoreFileName
     * @return
     */
    public static int deleteFile(String groupName,String remoreFileName){
        try {
            int result = storageClient.delete_file(groupName == null ? "group1" : groupName, remoreFileName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 修改一個已經存在的檔案
     * @param oldGroupName
     * @param oldFileName
     * @param file
     * @param fileName
     * @return
     */
    public static String[] modifyFile(String oldGroupName,String oldFileName,File file,String fileName){
        String[] fileids = null;
        try{
            //先上傳
            fileids = uploadFile(file,fileName);
            if(fileids == null){
                return null;
            }
            //再删除
            int delResult = deleteFile(oldGroupName,oldFileName);
            if(delResult != 0){
                return null;
            }
        }catch (Exception e){
            return null;
        }
        return fileids;

    }

    /**
     * 檔案下載下傳
     * @param groupName
     * @param remoteFileName
     * @return
     */
    public static InputStream downloadFile(String groupName,String remoteFileName){
        try{
            byte[] bytes = storageClient.download_file(groupName, remoteFileName);
            InputStream inputStream = new ByteArrayInputStream(bytes);
            return inputStream;
        }catch (Exception e) {
            return null;
        }
    }

    public static NameValuePair[] getMetaDate(String groupName,String remoteFileName){
        try{
            NameValuePair[] nvp = storageClient.get_metadata(groupName, remoteFileName);
            return nvp;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 擷取檔案字尾名,不帶點
     */
    private static String getFileExt(String fileName){
        if(StringUtils.isBlank(fileName)||!fileName.contains(".")){
            return "";
        }else{
            return fileName.substring(fileName.lastIndexOf(".")+1);//不帶最後的點
        }
    }
}
           
  1. 編寫用戶端代碼,上傳一張圖檔測試(上傳後的檔案名,是FastDFS自動生成,和我們代碼設定的檔案名沒啥關系)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
import com.yzpnb.utils.FastDFSClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.UUID;
public class MyClient {
    public static void main(String[] args) {
        try{
            File file = new File("D:/a.jpg");
            InputStream inputStream = new FileInputStream(file);
            String fileName = UUID.randomUUID().toString()+ ".jpg";

            String[] result = FastDFSClient.uploadFile(inputStream, fileName);

            System.out.println(Arrays.toString(result));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
           

三、下載下傳

  1. 編寫代碼并運作
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
import com.yzpnb.utils.FastDFSClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.UUID;
public class MyClient {
    public static void main(String[] args) {
        try{
            //[group1, M00/00/00/wKgKaWENAOWEMeDCAAAAAOFj66Y127.jpg]下載下傳這張圖檔
            InputStream is = FastDFSClient.downloadFile("group1", "M00/00/00/wKgKaWENAOWEMeDCAAAAAOFj66Y127.jpg");
            FileOutputStream os = new FileOutputStream(new File("D:/b.jpg"));
            int index = 0;
            while((index = is.read())!=-1){
                os.write(index);
            }
            os.flush();
            os.close();
            is.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
           

四、圖檔通路

問題
  1. FastDFS沒有提供圖檔通路功能
  2. 是以我們需要使用代理來實作
  3. nginx提供的代理功能可以實作圖檔通路,但隻支援http請求代理(隻要支援http協定通路的内容,nginx都可以代理),當接受到外部http請求,傳回本地檔案資源給用戶端
  4. 我們需要借助nginx來實作,外部請求圖檔,把圖檔資訊響應給請求方
  1. 上傳到虛拟機并安裝:
  1. fastdfs-nginx-module子產品 :https://github.com/happyfish100/fastdfs-nginx-module
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  2. nginx: http://nginx.org/en/download.html
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  3. 上傳兩個檔案,解壓
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 修改fastdfs-nginx-module配置檔案,在檔案中src目錄下的config檔案,因為配置檔案中指定的是fastDFS核心代碼位置,我們需要指定
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 安裝nginx
  1. 安裝一些c++之類的運作庫
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
yum install -y gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl openssl-devel
           
  1. 修改配置檔案之前,建立一個目錄(修改配置檔案中好多位置都使用了/var/temp/nginx目錄,我們需要手動建立這個目錄)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  2. 給nginx權重限
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  3. 進入nginx目錄,添加配置(

    你需要修改最後一行,指定路徑到你安裝fastdfs-nginx-module的src路徑

    )
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/local/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/temp/nginx/client \
--http-proxy-temp-path=/var/temp/nginx/proxy \
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
--http-scgi-temp-path=/var/temp/nginx/scgi \
--add-module=/opt/module/fastdfs-nginx-module-master/src
           
  1. 編譯并安裝(在nginx目錄下,執行make指令編譯安裝,make install運作)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 複制fastdfs-nginx-module/src/mod-fastdfs.conf配置檔案到/etc/fdfs目錄,并修改它
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
connect_timeout=10 # 連接配接逾時時間,機關秒
tracker_server=192.168.10.105:22122# tracker服務結點
url_have_group_name = true# URL是否包含group名稱
store_path0=/usr/loacl/fastdfs/storage/store#storage服務結點的存儲位置,配置與storage結點一緻
           
  1. 提供FastDFS需要的HTTP配置檔案(複制FastDFS安裝包中兩個配置檔案http.conf和mine.types到/etc/fdfs目錄中)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 建立網絡通路存儲服務的軟連接配接(在上傳檔案到FastDFS後,FastDFS會傳回group1/M00/00/00/xxxxx/xx其中group1是卷名,在mod_fastdfs.conf配置檔案中已配置了url_have_group_name,以保證URL解析正确。其中的M00是FastDFS儲存資料時使用的虛拟目錄,需要将這個虛拟目錄定位到真實資料目錄上)
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
ln -s /usr/local/fastdfs/storage/store/data/ /usr/local/fastdfs/storage/store/data/M00
           
  1. 修改nginx配置檔案
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
  1. 啟動nginx
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
    分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
分布式檔案系統:FastDFS一、環境搭建二、檔案上傳三、下載下傳四、圖檔通路
到此,已經可以通過http請求擷取資源了,之後會單獨寫一篇文章,使用圖檔通路功能,因為需要寫一個web項目來測試,日後有時間再補充