CentOS7_2單機環境部署FastDFS文件系統

CentOS7_2單機環境部署FastDFS文件系統

一、下載FastDFS所需包(重要,版本親測有效,切不可更換)

安裝Fastdfs文件系統軟件.rar 

二、下載完成後,統一將文件放入/usr/local/src目錄下

cd /usr/local/src/glibc
rpm -ivh --nodeps --force *.rpm
安裝完
cd /usr/local/src/Basic_package
rpm -ivh --nodeps --force *.rpm
安裝完
cd /usr/local/src/gcc-etc
rpm -ivh --nodeps --force *.rpm
安裝完

三、安裝FastDFS環境

vim /etc/hosts

增加如下一行,這是我的IP
192.168.0.222 file.luda.com

如果要本機訪問虛擬機,在C:\Windows\System32\drivers\etc\hosts中同樣增加一行

   3.1、安裝 libfastcommon

解壓
cd /usr/local/src/
tar -zxvf libfastcommon-1.0.7.tar
cd libfastcommon-1.0.7

編譯、安裝
./make.sh
./make.sh install

注:libfastcommon.so 安裝到了/usr/lib64/libfastcommon.so,但是FastDFS主程序設置的lib目錄是/usr/local/lib,所以需要創建軟鏈接。
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so 

   3.2、安裝FastDFS

解壓
tar -zxvf V5.05.tar.gz
cd fastdfs-5.05

編譯、安裝
./make.sh
./make.sh install

建立 /usr/bin 到 /usr/local/bin 的軟鏈接。  
ln -s /usr/bin/fdfs_trackerd   /usr/local/bin
ln -s /usr/bin/fdfs_storaged   /usr/local/bin
ln -s /usr/bin/stop.sh         /usr/local/bin
ln -s /usr/bin/restart.sh      /usr/local/bin

  3.3、配置FastDFS跟蹤器(Tracker)

進入 /etc/fdfs,複製 FastDFS 跟蹤器樣例配置文件 tracker.conf.sample,並重命名爲 tracker.conf。
cd /etc/fdfs
cp tracker.conf.sample tracker.conf
vim tracker.conf

編輯tracker.conf ,下面的需要修改下,其它的默認即可。
base_path=/luda/fastdfs/tracker
http.server_port=80
創建tracker基礎數據目錄,即base_path對應的目錄
mkdir -p /luda/fastdfs/tracker
查看防火牆狀態
systemctl status firewalld.service
關閉防火牆
systemctl stop firewalld.service
移除開機自啓
systemctl disable firewalld.service
啓動Tracker
初次成功啓動,會在 /luda/fdfsdfs/tracker/ (配置的base_path)下創建 data、logs 兩個目錄。

可以用這種方式啓動
/etc/init.d/fdfs_trackerd start

也可以用這種方式啓動,前提是上面創建了軟鏈接,後面都用這種方式
service fdfs_trackerd start
查看 FastDFS Tracker 是否已成功啓動 ,22122端口正在被監聽,則算是Tracker服務安裝成功。
netstat -unltp|grep fdfs

關閉Tracker命令:
service fdfs_trackerd stop

設置Tracker開機啓動
chkconfig fdfs_trackerd on

 3.4、配置 FastDFS 存儲 (Storage)

進入 /etc/fdfs 目錄,複製 FastDFS 存儲器樣例配置文件 storage.conf.sample,並重命名爲 storage.conf
cd /etc/fdfs
cp storage.conf.sample storage.conf
vim storage.conf
編輯storage.conf,下面的需要修改,其它的默認即可。
base_path=/luda/fastdfs/storage
store_path0=/luda/fastdfs/file
tracker_server=file.luda.com:22122
http.server_port=80

創建Storage基礎數據目錄,對應base_path目錄
mkdir -p /luda/fastdfs/storage

這是配置的store_path0路徑
mkdir -p /luda/fastdfs/file
啓動 Storage
啓動Storage前確保Tracker是啓動的。初次啓動成功,會在 /luda/fastdfs/storage 目錄下創建 data、 logs 兩個目錄。

可以用這種方式啓動
/etc/init.d/fdfs_storaged start

也可以用這種方式,後面都用這種
service fdfs_storaged start
查看 Storage 是否成功啓動,23000 端口正在被監聽,就算 Storage 啓動成功。
netstat -unltp|grep fdfs

關閉Storage命令:(先別執行)
service fdfs_storaged stop
查看Storage和Tracker是否在通信:
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf

 

設置 Storage 開機啓動
chkconfig fdfs_storaged on

  3.5、文件上傳測試

修改 Tracker 服務器中的客戶端配置文件 
cd /etc/fdfs
cp client.conf.sample client.conf
vim client.conf
修改如下配置即可,其它默認。
base_path=/luda/fastdfs/client
tracker_server=file.luda.com:22122
mkdir -p /luda/fastdfs/client
上傳測試
在linux內部執行如下命令上傳 namei.jpeg 圖片
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf namei.jpeg

上傳成功後返回文件ID號:group1/M00/00/00/wKgz6lnduTeAMdrcAAEoRmXZPp870.jpeg

返回的文件ID由group、存儲目錄、兩級子目錄、fileid、文件後綴名(由客戶端指定,主要用於區分文件類型)拼接而成。

 四、安裝Nginx

上面將文件上傳成功了,但我們無法下載。因此安裝Nginx作爲服務器以支持Http方式訪問文件。同時,後面安裝FastDFS的Nginx模塊也需要Nginx環境。
Nginx只需要安裝到StorageServer所在的服務器即可,用於訪問文件。我這裏由於是單機,TrackerServer和StorageServer在一臺服務器上。
1、安裝nginx所需環境  
① gcc
② PCRE pcre-devel
③ zlib 安裝
④ OpenSSL 安裝
已經在第一步裝好了
安裝Nginx
解壓
cd /usr/local/src/
tar -zxvf nginx-1.12.0.tar.gz
cd nginx-1.12.0

使用默認配置
./configure

編譯、安裝
make
make install

啓動nginx
cd /usr/local/nginx/sbin/
./nginx 

設置開機啓動
vim /etc/rc.local

添加一行:
/usr/local/nginx/sbin/nginx

設置執行權限
chmod 755 rc.local

查看nginx的版本及模塊
/usr/local/nginx/sbin/nginx -V
修改nginx.conf

vim /usr/local/nginx/conf/nginx.conf
添加如下行,將 /group1/M00 映射到 /luda/fastdfs/file/data
location /group1/M00 {
    alias /luda/fastdfs/file/data;
}

重啓nginx
/usr/local/nginx/sbin/nginx -s reload
在瀏覽器訪問之前上傳的圖片、成功。
http://file.luda.com/group1/M00/00/00/wKgz6lnduTeAMdrcAAEoRmXZPp870.jpeg

五、FastDFS 配置 Nginx 模塊

fastdfs-nginx-module 模塊說明
  FastDFS 通過 Tracker 服務器,將文件放在 Storage 服務器存儲, 但是同組存儲服務器之間需要進行文件複製, 有同步延遲的問題。
  假設 Tracker 服務器將文件上傳到了 192.168.0.222,上傳成功後文件 ID已經返回給客戶端。
  此時 FastDFS 存儲集羣機制會將這個文件同步到同組存儲 192.168.0.15,在文件還沒有複製完成的情況下,客戶端如果用這個文件 ID 在 192.168.0.15 上取文件,就會出現文件無法訪問的錯誤。
  而 fastdfs-nginx-module 可以重定向文件鏈接到源服務器取文件,避免客戶端由於複製延遲導致的文件無法訪問錯誤。
fastdfs-nginx-module、解壓
cd usr/local/src/
tar -zxvf fastdfs-nginx-module_v1.15.tar.gz

配置Nginx
在nginx中添加模塊
先停掉nginx服務
/usr/local/nginx/sbin/nginx -s stop
進入解壓包目錄
cd /usr/local/src/nginx-1.12.0/

添加模塊
./configure --add-module=../fastdfs-nginx-module/src

重新編譯、安裝
make && make install

如果報錯了:
編輯 fastdfs-nginx-module-1.20/src/config 文件  
修改文件內容(去掉路徑中的local)

ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/"
查看Nginx的模塊
/usr/local/nginx/sbin/nginx -V

複製 fastdfs-nginx-module 源碼中的配置文件到/etc/fdfs 目錄, 並修改
cd /usr/local/src/fastdfs-nginx-module/src
cp mod_fastdfs.conf /etc/fdfs/
修改如下配置,其它默認
connect_timeout=10
tracker_server=file.luda.com:22122
url_have_group_name = true
store_path0=/luda/fastdfs/file
複製 FastDFS 的部分配置文件到/etc/fdfs 目錄
cd /usr/local/src/fastdfs-5.05/conf/
cp anti-steal.jpg http.conf mime.types /etc/fdfs/

配置nginx,修改nginx.conf
vim /usr/local/nginx/conf/nginx.conf
修改配置,其它的默認
在80端口下添加fastdfs-nginx模塊
location ~/group([0-9])/M00 {
    ngx_fastdfs_module;
}
在/luda/fastdfs/file 文件存儲目錄下創建軟連接,將其鏈接到實際存放數據的目錄,這一步可以省略。
ln -s /luda/fastdfs/file/data/ /luda/fastdfs/file/data/M00 
啓動nginx
/usr/local/nginx/sbin/nginx
在地址欄訪問。
能下載文件就算安裝成功。注意和第三點中直接使用nginx路由訪問不同的是,這裏配置 fastdfs-nginx-module 模塊,可以重定向文件鏈接到源服務器取文件。
http://file.ljzsg.com/group1/M00/00/00/wKgz6lnduTeAMdrcAAEoRmXZPp870.jpeg

六、最終部署結構圖(盜的圖):可以按照下面的結構搭建環境。

 七、Java對接

一、添加依賴:
<!-- 文件服務系統 -->
<dependency>
    <groupId>com.github.tobato</groupId>
    <artifactId>fastdfs-client</artifactId>
    <version>1.25.2-RELEASE</version>
</dependency>

二、添加配置:
#文件服務器
fdfs.soTimeout=1500
fdfs.connectTimeout= 600
#縮略圖生成參數
fdfs.thumbImage.width=150
fdfs.thumbImage.height=150
#TrackerList參數,支持多個
fdfs.trackerList[0]=192.168.0.222:22122
fdfs.configPath=file.luda.com
fdfs.domainPath=file.luda.com
Java代碼接口:
    /**
     * 上傳文件
     * 無大小限制
     * @param file
     * @return
     */
    public Result<String> uploadFile(MultipartFile file);

    public Result<String> uploadFile(File file) throws IOException;

    /**
     * 上傳圖片文件(5M限制)
     * @param file
     * @return
     */
    public Result<String> uploadImage(MultipartFile file);

    /**
     * 上傳聲音文件(5M限制)
     * @param file
     * @return
     */
    public Result<String> uploadVoice(MultipartFile file);

    /**
     * 上傳視頻文件(10M限制)
     * @param file
     * @return
     */
    public Result<String> uploadVideo(MultipartFile file);

    /**
     * 刪除文件
     * @param fileUrl
     */
    public void deleteFile(String fileUrl);

    /**
     * 下載文件至服務器臨時文件夾
     * @param fileUrl
     * @return
     */
    public File downloadFileForTemp(String fileUrl);

    /**
     * 下載文件至服務器永久文件夾
     * @param fileUrl
     * @return
     */
    public File downloadFileForForever(String fileUrl);
Java代碼接口實現:
    private static Logger logger=LoggerFactory.getLogger(FileUtilServiceImpl.class);

    @Autowired
    private FastFileStorageClient storageClient;

    //ip地址
    @Value("${fdfs.configPath}")
    String configPath;

    //域名地址
    @Value("${fdfs.domainPath}")
    String domainPath;

    @Override
    public Result<String> uploadFile(MultipartFile file) {
        Result result = new Result();
        if (file != null && !file.isEmpty()) {
            try {

                StorePath storePath = storageClient.uploadFile((InputStream)file.getInputStream(),file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()),null);
                String fileUrl=getResAccessUrl(storePath);
                result.setType(FileReturnEnum.UploadEnum.success.value);
                result.setData(fileUrl);
                result.setMessage(FileReturnEnum.UploadEnum.success.name);

            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage(),e);
                result.setType(FileReturnEnum.UploadEnum.fail.value);
                result.setMessage(FileReturnEnum.UploadEnum.fail.name);
            }
        } else {
            result.setType(FileReturnEnum.UploadEnum.lose.value);
            result.setMessage(FileReturnEnum.UploadEnum.lose.name);
        }
        return result;

    }

    /**
     * 上傳文件
     * @param file 文件對象
     * @return 文件訪問地址
     * @throws IOException
     */
    @Override
    public Result<String> uploadFile(File file) throws IOException {
        Result result = new Result();
        if (file != null) {
            try {

                FileInputStream inputStream = new FileInputStream (file);
                StorePath storePath = storageClient.uploadFile(inputStream,file.length()
                        , FilenameUtils.getExtension(file.getName()),null);
                String fileUrl=getResAccessUrl(storePath);
                result.setType(FileReturnEnum.UploadEnum.success.value);
                result.setData(fileUrl);
                result.setMessage(FileReturnEnum.UploadEnum.success.name);

            } catch (Exception e) {
                //e.printStackTrace();
                logger.error(e.getMessage(),e);
                result.setType(FileReturnEnum.UploadEnum.fail.value);
                result.setMessage(FileReturnEnum.UploadEnum.fail.name);
            }
        } else {
            result.setType(FileReturnEnum.UploadEnum.lose.value);
            result.setMessage(FileReturnEnum.UploadEnum.lose.name);
        }
        return result;
    }

    // 封裝文件完整URL地址
    private String getResAccessUrl(StorePath storePath) {
        String fileUrl = domainPath + "/" + storePath.getFullPath();
        return fileUrl;
    }

    @Override
    public Result<String> uploadImage(MultipartFile file){
        Result result = new Result();
        if(file.isEmpty()){
            //空文件
            result.setType(FileReturnEnum.UploadEnum.fail.value);
            result.setMessage("空文件");
        }else if(file.getSize()>0 && file.getSize()<=5*1024*1024){
            result=uploadFile(file);
        }else{
            //圖片文件超過規定的大小5M
            result.setType(FileReturnEnum.UploadEnum.fail.value);
            result.setMessage("圖片文件超過規定的大小5M");
        }

        return result;
    }

    @Override
    public Result<String> uploadVoice(MultipartFile file){
        Result result = new Result();
        if(file.isEmpty()){
            //空文件
            result.setType(FileReturnEnum.UploadEnum.fail.value);
            result.setMessage("空文件");
        }else if(file.getSize()>0 && file.getSize()<=5*1024*1024){
            result=uploadFile(file);
        }else{
            //音頻文件超過規定的大小5M
            result.setType(FileReturnEnum.UploadEnum.fail.value);
            result.setMessage("音頻文件超過規定的大小5M");
        }

        return result;
    }

    @Override
    public Result<String> uploadVideo(MultipartFile file){
        Result result = new Result();
        if(file.isEmpty()){
            //空文件
            result.setType(FileReturnEnum.UploadEnum.fail.value);
            result.setMessage("空文件");
        }else if(file.getSize()>0 && file.getSize()<=10*1024*1024){
            result=uploadFile(file);
        }else{
            //視頻文件超過規定的大小10M
            result.setType(FileReturnEnum.UploadEnum.fail.value);
            result.setMessage("視頻文件超過規定的大小10M");
        }

        return result;
    }


    @Override
    public void deleteFile(String fileUrl){
        if (StringUtils.isEmpty(fileUrl)) {
            return;
        }
        try {
            fileUrl = getFastDFSPath(fileUrl);
            storageClient.deleteFile(fileUrl);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 根據文件url獲取fastDFS返回的path(組名+文件名)
     * @param fileUrl
     * @return
     */
    public String getFastDFSPath(String fileUrl){
        if(fileUrl.indexOf(domainPath)!=-1){
            fileUrl = fileUrl.replace(domainPath+"/","");
        }else if(fileUrl.indexOf(configPath)!=-1){
            fileUrl = fileUrl.replace(configPath+"/","");
        }
        return fileUrl;
    }

    //@Value("${eaqulFile.tempPath}")
    @Value("D:\\file\\temp\\")
    String tempPath;
    @Override
    public File downloadFileForTemp(String fileUrl){
        return downloadFile(fileUrl,tempPath);
    }

    //@Value("${eaqulFile.foreverPath}")
    @Value("D:\\file\\forever\\")
    String foreverPath;
    @Override
    public File downloadFileForForever(String fileUrl){
        return downloadFile(fileUrl,foreverPath);
    }

    /**
     * 下載文件
     * @param fileUrl 路徑地址如:http://file.luda.com/group1/M01/00/01/ooYBAFqzF3qAPcJrAADyr9_6_Js731.jpg
     * @return
     */
    public File downloadFile(String fileUrl,String parentPath) {
        //byte[] b = storageClient.download_file(group, path);
        File file = new File(parentPath+fileUrl.substring(fileUrl.lastIndexOf("/"),fileUrl.length()));
        try {
            //判斷文件夾是否存在
            File fileParent = file.getParentFile();
            if(!fileParent.exists()){
                fileParent.mkdirs();//創建文件夾
            }
            // 判斷文件是否存在
            if (!file.exists()){
                System.out.println("文件不存在");
                file.createNewFile();    // 不存在,則創建文件
            }

            OutputStream output = new FileOutputStream(file);
            BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);

            String fastDFSPath=getFastDFSPath(fileUrl);
            //String groupName=path.split("/")[0];

            StorePath storePath = StorePath.praseFromUrl(fastDFSPath);
            String groupName=storePath.getGroup();//group1
            String remoteFilename=storePath.getPath();//M01/00/01/ooYBAFqzF3qAPcJrAADyr9_6_Js731.jpg
            //FileInfo fileInfo= storageClient.queryFileInfo(groupName, remoteFilename);//獲取文件信息
            byte[] b = storageClient.downloadFile(groupName,remoteFilename, new DownloadCallback<byte[]>() {
                @Override
                public byte[] recv(InputStream ins) throws IOException {
                    byte[] in2b=IOUtils.toByteArray(ins);
                    /*ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
                    byte[] buff = new byte[100000];
                    int rc = 0;
                    while ((rc = ins.read(buff, 0, 100)) > 0) {
                        swapStream.write(buff, 0, rc);
                    }
                    byte[] in2b = swapStream.toByteArray();
                    swapStream.close();*/
                    ins.close();
                    return in2b;
                }
            });
            logger.info(String.valueOf(b.length));
            try{
                if(b != null){
                    bufferedOutput.write(b);
                }
            }catch (Exception e){
                logger.error(e.getMessage(),e);
            } //用戶可能取消了下載
            finally {
                if (output != null)
                    try {
                        bufferedOutput.close();
                        output.close();
                    } catch (IOException e) {
                        logger.error(e.getMessage(),e);
                    }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
        return file;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章