1. 程式人生 > >分散式檔案系統FastDFS簡介、搭建、與SpringBoot整合實現圖片上傳

分散式檔案系統FastDFS簡介、搭建、與SpringBoot整合實現圖片上傳

之前大學時搭建過一個FastDFS的圖片伺服器,當時只是抱著好奇的態度搭著玩一下,當時搭建採用了一臺虛擬機器,tracker和storage服務在一臺機器上放著,最近翻之前的部落格突然想著在兩臺機器上搭建試一下,順便整合了SpringBoot實現了一下圖片的上傳服務。

新的閱讀體驗地址:http://www.zhouhong.icu/post/140 

使用舊版本的在一臺機器上搭建可以參考之前的那篇文章:https://www.cnblogs.com/Tom-shushu/p/10603723.html

一、傳統檔案上傳問題:

 

  如果我們現在使用者使用的是第一胎伺服器Tomcat1上傳了檔案,然後當用戶訪問Tomcat1時候可以訪問到上傳的檔案、圖片等等,但是如果當用戶訪問到Tomcat2和Tomcat3的時候,由於檔案資源在Tomcat1上面,所以他是訪問不到對應的資源的;這時就可以使用到分散式檔案系統FastDFS了。

二、什麼是分散式檔案系統

  • 隨著檔案資料的越來越多,通過tomcat或nginx虛擬化的靜態資原始檔在單一的一個伺服器節點內是存不下的,如果用多個節點來儲存也可以,但是不利於管理和維護,所以我們需要一個系統來管理多臺計算機節點上的檔案資料,這就是分散式檔案系統。
  • 分散式檔案系統是一個允許檔案通過網路在多臺節點上分享的檔案系統,多臺計算機節點共同組成一個整體,為更多的使用者提供分享檔案和儲存空間。比如常見的網盤,本質就是一個分散式的檔案儲存系統。雖然我們是一個分散式的檔案系統,但是對使用者來說是透明的,使用者使用的時候,就像是訪問本地磁碟一樣。
  • 分散式檔案系統可以提供冗餘備份,所以容錯能力很高。 系統中有某些節點宕機,但是整體檔案服務不會停止,還是能夠為使用者提供服務,整體還是運作的,資料也不會丟失。
  • 分散式檔案系統的可擴充套件性強,增加或減少節點都很簡單,不會影響線上服務,增加完畢後會釋出到線上,加入到叢集中為使用者提供服務。
  • 分散式檔案系統可以提供負載均衡能力,在讀取檔案副本的時候可以由多個節點共同提供服務,而且可以通過橫向擴充套件來確保效能的提升與負載。

三、為什麼要使用分散式檔案系統

  使用分散式檔案系統可以解決如下幾點問題:
  1. 海量檔案資料儲存
  2. 檔案資料高可用(冗餘備份)
  3. 讀寫效能和負載均衡
  以上3點都是我們之前使用tomcat或nginx所不能夠實現的,這也是我們為什麼要使用分散式檔案系統的原因

四、FastDFS 與 HDFS

  說到分散式檔案儲存,肯定會有人想到HDFS,他們兩者主要定位和應用場景是不一樣的。
  1. Hadoop中的檔案系統HDFS主要解決平行計算中分散式儲存資料的問題。其單個數據檔案通常很大,採用了分塊(切分)儲存的方式,所以是大資料大檔案儲存來使用的場景。
  2. FastDFS主要用於網際網路網站,為檔案上傳和下載提供線上服務。所以在負載均衡、動態擴容等方面都支援得比較好,FastDFS不會對檔案進行分快儲存。FastDFS用於儲存中小檔案都是不錯的,比如使用者頭像啊,一些較小的音視訊檔案啊等等都行。

五、FastDFS常見術語

  1. tracker:追蹤者伺服器,主要用於協調排程,可以起到負載均衡的作用,記錄storage的相關狀態資訊。
  2. storage:儲存伺服器,用於儲存檔案以及檔案的元資料資訊
  3. group:組,同組節點提供冗餘備份,不同組用於擴容
  4. mata data: 檔案的元資料資訊,比如長寬資訊、圖片字尾,視訊幀數等

六、FastDFS架構

 

  tracker和storage是有心跳資訊的,需要先啟動tracker

七、FasfDFS檔案上傳過程

八、FastDFS下載過程

九、FastDFS搭建:

  準備:
  • 安裝包準備
連結:https://pan.baidu.com/s/1Lic4JfUT4a8YdYmqJ5_vcQ 
提取碼:bm0a 
複製這段內容後開啟百度網盤手機App,操作更方便哦

  兩臺伺服器

  • tracker服務:192.168.2.120 、storage服務:192.168.2.121,如下圖:

 

 

1、基本環境搭建:
  • 安裝基礎環境
yum install -y gcc gcc-c++
yum -y install libevent
  • 安裝libfastcommon函式庫
# 1.解壓
tar -zxvf libfastcommon-1.0.42.tar.gz
# 2.進入解壓後的資料夾編譯並安裝
cd libfastcommon-1.0.42/
./make.sh
./make.sh install
  • 安裝FastDFS主程式檔案
# 1.解壓
tar -zxvf fastdfs-6.04.tar.gz
# 2.進入到fastdfs目錄,檢視fastdfs安裝配置
cd fastdfs-6.04/
vim make.sh
# 3.安裝fastdfs
./make.sh
./make.sh install 
# 4.將FastDFS中conf中的檔案拷貝到 /etc/fdfs下
cp /software/FastDFS/fastdfs-6.04/conf/*  /etc/fdfs/
2、配置tracker服務
  進入 /etc/fdfs 修改配置檔案 tracker.conf
# 1.修改檔案路徑
base_path=/usr/local/fastdfs/tracker
# 2.建立檔案路徑
mkdir /usr/local/fastdfs/tracker -p
# 3.啟動
/usr/bin/fdfs_trackerd  /etc/fdfs/tracker.conf
# 4.檢視服務
ps -ef|grep tracker
# 5.停止tracker
/usr/bin/stop.sh /etc/fdfs/tracker.conf
3.配置storage服務
  進入 /etc/fdfs 修改配置檔案 storage.conf
# 1.修改配置檔案 storage.conf
# 修改組名
group_name=zhouhong
# 修改storage的工作空間
base_path=/usr/local/fastdfs/storage
# 修改storage的儲存空間
store_path0=/usr/local/fastdfs/storage
# 修改tracker的地址和埠號,用於心跳
tracker_server=192.168.2.120:22122
# 後續結合nginx的一個對外服務埠號
http.server_port=8888
# 2.建立目錄 
mkdir /usr/local/fastdfs/storage -p
# 3.啟動
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf
4.檢視
ps -ef|grep storage
4、測試
  修改 /etc/fdfs 下 client.conf檔案
  # 1.修改client.conf檔案
  base_path=/usr/local/fastdfs/client
  tracker_server=192.168.2.120:22122
# 2.建立目錄
mkdir /usr/local/fastdfs/client
# 3.準備一張圖片測試
/usr/bin/fdfs_test /etc/fdfs/client.conf  upload  zhouhong.jpg

  成功!
5、配置 nginx fastdfs 實現檔案伺服器
  Nginx需要跟storage安裝在同一臺伺服器上面
fastdfs安裝好以後是無法通過http訪問的,這個時候就需要藉助nginx了,所以需要安裝fastdfs的第三方模組到nginx中,就能使用了。
  • 安裝nginx外掛
# 1.解壓
tar -zxvf fastdfs-nginx-module-1.22.tar.gz
# 2.複製配置檔案
cp /software/FastDFS/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf  /etc/fdfs/
# 3.修改/fastdfs-nginx-module/src/config檔案
修改/fastdfs-nginx-module/src/config檔案,主要是修改路徑,把local刪除,
因為fastdfs安裝的時候我們沒有修改路徑,原路徑是/usr

  如圖所示,將local刪除即可

  • 安裝Nginx
# 1.環境安裝
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y gcc-c++
yum install -y openssl openssl-decel
# 2.解壓
tar -zxvf nginx-1.16.1.tar.gz
# 3.建立目錄
mkdir /var/temp/nginx -p
# 4.進入解壓目錄、最後一個為fastdfs-nginx-module-1.22解壓目錄
./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/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=/software/FastDFS/fastdfs-nginx-module-1.22/src
# 5.安裝
make
make install
# 6.修改 /etc/fdfs/mod_fastdfs.conf
base_path=/usr/local/fastdfs/tmp
tracker_server=192.168.2.120:22122
group_name=zhouhong
url_have_group_name = true
store_path0=/usr/local/fastdfs/storage
# 7.建立目錄
mkdir /usr/local/fastdfs/tmp
# 8.修改/usr/local/nginx/conf/nginx.conf
server {
        listen       8888;
        server_name  localhost;
        location /zhouhong/M00 {
            ngx_fastdfs_module;
        }
    }
  • 訪問
  找到剛才上傳的圖片
cd  /usr/local/fastdfs/storage/data/00/00 
ls

十、FastDFS與SpringBoot整合實現檔案上傳

1、引入依賴
       <dependency>
        <groupId>com.github.tobato</groupId>
        <artifactId>fastdfs-client</artifactId>
        <version>1.26.7</version>
    </dependency>        
2、配置檔案
############################################################
#
# fdfs 配置
#
############################################################
fdfs:
  connect-timeout: 30   # 連線的超時時間
  so-timeout: 30        # 讀取的超時時間
  tracker-list: 192.168.2.120:22122   # tracker服務所在的ip地址和埠號
3、FileService主要邏輯程式碼
    @Autowired
    private FastFileStorageClient fastFileStorageClient;
    @Override
    public String upload(MultipartFile file, String fileExtName) throws Exception {
        StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(),
                                file.getSize(),
                                fileExtName,
                                null);
        String path = storePath.getFullPath();
        return path;
    }
4、FileController主要邏輯程式碼
@RestController
@RequestMapping("fdfs")
public class CenterUserController  {
    @Autowired
    private FileResource fileResource;    
    @Autowired
    private CenterUserService centerUserService;
    @Autowired
    private FileService fdfsService;
    @PostMapping("uploadFace")
    public JSONResult uploadFace(
            String userId,
            MultipartFile file,
            HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        String path = "";
        // 開始檔案上傳
        if (file != null) {
            // 獲得檔案上傳的檔名稱
            String fileName = file.getOriginalFilename();
            if (StringUtils.isNotBlank(fileName)) {
                // 檔案重新命名  
                String fileNameArr[] = fileName.split("\\.");
                // 獲取檔案的字尾名
                String suffix = fileNameArr[fileNameArr.length - 1];
                if (!suffix.equalsIgnoreCase("png") &&
                        !suffix.equalsIgnoreCase("jpg") &&
                        !suffix.equalsIgnoreCase("jpeg") ) {
                    return JSONResult.errorMsg("圖片格式不正確!");
                }
                path = fdfsService.upload(file, suffix);
                System.out.println(path);
            }
        } else {
            return JSONResult.errorMsg("檔案不能為空!");
        }
        if (StringUtils.isNotBlank(path)) {
            String finalUserFaceUrl = fileResource.getHost() + path;
            //更新圖片地址到資料庫
            Users userResult = centerUserService.updateUserFace(userId, finalUserFaceUrl);
            UsersVO usersVO = conventUsersVO(userResult);
            CookieUtils.setCookie(request, response, "user",
                    JsonUtils.objectToJson(usersVO), true);
        } else {
            return JSONResult.errorMsg("上傳頭像失敗");
        }
        return JSONResult.ok();
    }
}
5、對映
@Component
@PropertySource("classpath:file.properties")
@ConfigurationProperties(prefix = "file")
public class FileResource {
    private String host;
        public String getHost() {
        return host;
    }
    public void setHost(String host) {
        this.host = host;
    }
}