天天看點

分布式檔案存儲-FastDFS一、FastDFS介紹二、docker下搭建FastDFS3、檔案存儲微服務

整理知識點時翻出來的,想想還是發個部落格好了,圖檔來源的部落格找不到了,隻能厚顔上個原創…

一、FastDFS介紹

FastDFS是一個開源的輕量級分布式檔案系統

功能:

檔案存儲、檔案同步、檔案通路(檔案上傳、檔案下載下傳)等,解決了大容量存儲和負載均衡的問題。特别适合以檔案為載體的線上服務,如相冊網站、視訊網站等等。

FastDFS為網際網路量身定制,充分考慮了備援備份、負載均衡、線性擴容等機制,并注重高可用、高性能等名額,使用FastDFS很容易搭建一套高性能的檔案伺服器叢集提供檔案上傳、下載下傳等服務。

備援備份:同組不同伺服器存儲的内容一樣。多準備一份或者幾分,以備不時之需.

負載均衡:高并發時,将通路配置設定給同一組的不同伺服器

線性擴容:多個組,剩餘容量不足時,就加一個組

高可用:某台機器當機後,同組的其他機器還能繼續支援業務

高性能:機器多,分散存儲,避免通路集中在某一台機器

分布式檔案存儲-FastDFS一、FastDFS介紹二、docker下搭建FastDFS3、檔案存儲微服務
分布式檔案存儲-FastDFS一、FastDFS介紹二、docker下搭建FastDFS3、檔案存儲微服務

FastDFS 架構包括 Tracker server 和 Storage server。用戶端請求 Tracker server 進行檔案上傳、下載下傳,通過Tracker server 排程最終由 Storage server 完成檔案上傳和下載下傳。

Tracker server 作用是負載均衡和排程(相當于倉庫管理者),通過 Tracker server 在檔案上傳時可以根據一些政策找到Storage server 提供檔案上傳服務。可以将 tracker 稱為追蹤伺服器或排程伺服器。需要搭叢集,避免一台當機後服務癱瘓。

Storage server 作用是檔案存儲(相當于倉庫),用戶端上傳的檔案最終存儲在 Storage 伺服器上,Storageserver 沒有實作自己的檔案系統而是利用作業系統的檔案系統來管理檔案。可以将storage稱為存儲伺服器。

組名:檔案上傳後所在的 storage 組名稱,在檔案上傳成功後有storage 伺服器傳回,需要用戶端自行儲存。

虛拟磁盤路徑:storage 配置的虛拟路徑,與磁盤選項store_path*對應。如果配置了store_path0 則是 M00,如果配置了 store_path1 則是 M01,以此類推。

資料兩級目錄:storage 伺服器在每個虛拟磁盤路徑下建立的兩級目錄,用于存儲資料檔案。

檔案名:與檔案上傳時不同。是由存儲伺服器根據特定資訊生成,檔案名包含:源存儲伺服器 IP 位址、檔案建立時間戳、檔案大小、随機數和檔案拓展名等資訊。

二、docker下搭建FastDFS

1:拉取鏡像

docker pull morunchang/fastdfs
           

2:運作tracker

docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
           

3:運作storage

docker run -d --name storage --net=host -e TRACKER_IP=<your tracker server address>:22122 -e GROUP_NAME=<group name> morunchang/fastdfs sh storage.sh
           
  • 使用的網絡模式是–net=host, 替換為你伺服器的Ip即可
  • 是組名,即storage的組 (例:group01)
  • 如果想要增加新的storage伺服器,再次運作該指令,注意更換 新組名

4:修改nginx的配置

進入storage的容器内部,修改nginx.conf

docker exec -it storage  /bin/bash
           

進入後

vi /data/nginx/conf/nginx.conf
           

添加以下内容

location /group1/M00 {
       proxy_next_upstream http_502 http_504 error timeout invalid_header;
         proxy_cache http-cache;
         proxy_cache_valid  200 304 12h;
         proxy_cache_key $uri$is_args$args;
         proxy_pass http://fdfs_group1;
         expires 30d;
     }
           

5:修改檔案存儲配置storage.conf

修改檔案存儲路徑

進入storage的容器内部,修改storage.conf //檔案存儲伺服器配置檔案

docker exec -it storage  /bin/bash
           

進入後

vi storage.conf 
 base_path=/data/fast_data
 store_path0=/data/fast_data
 tracker_server=伺服器ip位址:22122
           

6:退出并重新開機容器

exit
 docker restart storage
           

3、檔案存儲微服務

springboot+springclooud

1:依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>
    </dependencies>
           

2:配置檔案

在resources檔案夾下建立fasfDFS的配置檔案fdfs_client.conf

connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 8080
tracker_server = 伺服器ip:22122
           
  • connect_timeout:連接配接逾時時間,機關為秒。
  • network_timeout:通信逾時時間,機關為秒。發送或接收資料時。假設在逾時時間後還不能發送或接收資料,則本次網絡通信失敗
  • charset: 字元集
  • http.tracker_http_port :.tracker的http端口
  • tracker_server: tracker伺服器IP和端口設定

在resources檔案夾下建立application.yml

spring:
  servlet:
    multipart:
      max-file-size: 10MB  #單個檔案大小
      max-request-size: 10MB #設定總上傳檔案大小
  application:
    name: file  #微服務的應用名稱
server:
  port: 9007
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true
           

3:檔案資訊封裝

檔案上傳一般都有檔案的名字、檔案的内容、檔案的擴充名、檔案的md5值、檔案的作者等相關屬性,我們可以建立一個對象封裝這些屬性

public class FastDFSFile {
	//檔案名字
	private String name;
	//檔案内容
	private byte[] content;
	//檔案擴充名
	private String ext;
	//檔案MD5摘要值
	private String md5;
	//檔案建立作者
	private String author;

	public FastDFSFile(String name, byte[] content, String ext, String height,
					   String width, String author) {
		super();
		this.name = name;
		this.content = content;
		this.ext = ext;
		this.author = author;
	}

	public FastDFSFile(String name, byte[] content, String ext) {
		super();
		this.name = name;
		this.content = content;
		this.ext = ext;
	}

	// getter and setter ...
}
           

4:檔案操作

工具類,實作FastDFS資訊擷取以及檔案的相關操作

package com.laoshentou.file.utils;

import com.laoshentou.file.pojo.FastDFSFile;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FastDFSClient {
    private static Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
    private static TrackerServer trackerServer = null;
    private static TrackerClient trackerClient = null;
    private static StorageServer storageServer = null;
    private static StorageClient1 storageClient1 = null;

    /**
     * 靜态代碼塊
     * 為了上傳檔案,初始化加載檔案的上傳配置檔案(檔案中包含:上傳檔案的位址/連接配接時間/讀取時間/編碼集等
     */
    static {
        try {
            //擷取fdfs_client.conf的絕對路徑
            String absolutePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
            ClientGlobal.init(absolutePath);
            trackerClient = new TrackerClient();
            trackerServer = trackerClient.getConnection();
            storageClient1 = new StorageClient1(trackerServer, storageServer);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ClientGlobal is fail:{}", e.getMessage());
        }
    }

    /**
     * 上傳檔案
     *
     * @param file
     * @return 檔案的路徑
     */
    public static String uploadFile(FastDFSFile file) {
        System.out.println("上傳檔案");
        NameValuePair[] nameValuePairs = new NameValuePair[1];
        nameValuePairs[0] = new NameValuePair(file.getAuthor());
        try {
            return storageClient1.upload_file1(file.getContent(), file.getExt(), nameValuePairs);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("upload file is fail: {} ", e.getMessage());
        }
        return null;
    }

    /**
     * 下載下傳檔案
     *
     * @param path
     * @return 檔案對象
     */
    public static InputStream downFile(String path) {
        try {
            byte[] bytes = storageClient1.download_file1(path);
            return new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            e.getStackTrace();
            logger.error("download file is fail : {}", e.getMessage());
        }
        return null;
    }


    /**
     * 删除檔案
     *
     * @param path
     */
    public static void deleteFile(String path) {
        try {
            storageClient1.delete_file1(path);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("delete file is fail : {}", e.getMessage());
        }
    }

    /***
     * 擷取Tracker服務位址
     * @return
     * @throws IOException
     */
    public static String getTrackerUrl() throws IOException {
        return "http://" + trackerServer.getInetSocketAddress().getHostString() + ":" + ClientGlobal.getG_tracker_http_port() + "/";
    }
}
           

檔案上傳控制器

package com.laoshentou.file.controller;

import com.laoshentou.Result;
import com.laoshentou.StatusCode;
import com.laoshentou.file.pojo.FastDFSFile;
import com.laoshentou.file.utils.FastDFSClient;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("/file")
public class FastDFSFileController {
    private Logger logger = LoggerFactory.getLogger(FastDFSFileController.class);

    /**
     * 上傳檔案
     *
     * @param file
     * @return 傳回對象
     */
    @PostMapping("/uploadFile")
    public Result uploadFile(MultipartFile file) {
        //建立檔案對象
        try {
            FastDFSFile fastDFSFile = new
                    FastDFSFile(file.getOriginalFilename(), file.getBytes(), FilenameUtils.getExtension(file.getOriginalFilename()));
            //上傳檔案
            String path = FastDFSClient.uploadFile(fastDFSFile);
            //擷取檔案的通路路徑
            return new Result(true, StatusCode.OK, "上傳成功", FastDFSClient.getTrackerUrl() + path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
           

5:Postman測試檔案上傳

選擇post請求

填寫headers

Key:Content-Type
Value:multipart/form-data
           

填寫body

選擇form-data,然後選擇檔案file

分布式檔案存儲-FastDFS一、FastDFS介紹二、docker下搭建FastDFS3、檔案存儲微服務

linux中檔案存儲路徑

docker exec -it storage  /bin/bash
cd /data/fast_data/data/00/00/
ll
           

浏覽器中檢視上傳的圖檔

http://122.51.207.162:8080/group1/M00/00/00/rBEACF3so9SAK91PAAmPA24UZhs566.jpg