【工具类】分布式文件存储-FastDFS
FastDFS簡介
FastDFS體系結構
FastDFS是一個開源的輕量級分布式文件系統,它對文件進行管理,功能包括:文件存儲、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲和負載均衡的問題。特別適合以文件為載體的在線服務,如相冊網站、視頻網站等等。
FastDFS為互聯網量身定制,充分考慮了冗余備份、負載均衡、線性擴容等機制,并注重高可用、高性能等指標,使用FastDFS很容易搭建一套高性能的文件服務器集群提供文件 上傳、下載等服務。
FastDFS 架構包括 Tracker server 和 Storage server。客戶端請求 Tracker server 進行文件上傳、下載,通過Tracker server 調度最終由 Storage server 完成文件上傳和下載。
Tracker server 作用是負載均衡和調度,通過 Tracker server 在文件上傳時可以根據一些策略找到Storage server 提供文件上傳服務。可以將 tracker 稱為追蹤服務器或調度服務器。Storage server 作用是文件存儲,客戶端上傳的文件最終存儲在 Storage 服務器上,Storageserver 沒有實現自己的文件系統而是利用操作系統的文件系統來管理文件??梢詫torage稱為存儲服務器。
上傳流程
客戶端上傳文件后存儲服務器將文件 ID 返回給客戶端,此文件 ID 用于以后訪問該文件的索引信息。文件索引信息包括:組名,虛擬磁盤路徑,數據兩級目錄,文件名。
組名:文件上傳后所在的 storage 組名稱,在文件上傳成功后有storage 服務器返回,需要客戶端自行保存。
虛擬磁盤路徑:storage 配置的虛擬路徑,與磁盤選項store_path*對應。如果配置了 store_path0 則是 M00,如果配置了 store_path1 則是 M01,以此類推。
數據兩級目錄:storage 服務器在每個虛擬磁盤路徑下創建的兩級目錄,用于存儲數據文件。
文件名:與文件上傳時不同。是由存儲服務器根據特定信息生成,文件名包含:源存儲服務器 IP 地址、文件創建時間戳、文件大小、隨機數和文件拓展名等信息。
FastDFS搭建
使用Docker搭建FastDFS的開發環境
拉取鏡像 docker pull morunchang/fastdfs
運行tracker docker run ‐d ‐‐name tracker ‐‐net=host morunchang/fastdfs sh tracker.sh
運行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的組
- 如果想要增加新的storage服務器,再次運行該命令,注意更換 新組名
修改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; }退出容器 exit
重啟storage容器
文件存儲微服務
修改pom.xml,引入依賴
<dependency> <groupId>net.oschina.zcx7878</groupId><artifactId>fastdfs‐client‐java</artifactId> <version>1.27.0.0</version> </dependency>在resources文件夾下創建fasfDFS的配置文件fdfs_client.conf
connect_timeout = 60 network_timeout = 60 charset = UTF‐8 http.tracker_http_port = 8080 tracker_server = 192.168.200.128: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是單個文件大小# max-request-size是設置總上傳的數據大小 max‐file‐size: 10MB max‐request‐size: 10MB server: port: 9008 eureka: client: service‐url: defaultZone: http://127.0.0.1:6868/eureka instance: prefer‐ip‐address: true feign: hystrix: enabled: true創建file包,創建啟動類FileApplication
@SpringBootApplication @EnableEurekaClient public class FileApplication { public static void main(String[] args) { SpringApplication.run(FileApplication.class); } }文件上傳
文件信息封裝:文件上傳一般都有文件的名字、文件的內容、文件的擴展名、文件的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 ...文件操作:創建工具類,在該類中實現FastDFS信息獲取以及文件的相關操作, 代碼如下:
import org.csource.common.NameValuePair; import org.csource.fastdfs.*; 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 org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);/**** 初始化加載FastDFS的TrackerServer配置*/static {try {String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();ClientGlobal.init(filePath);} catch (Exception e) {logger.error("FastDFS Client Init Fail!",e);}}/**** 文件上傳* @param file* @return 1.文件的組名 2.文件的路徑信息*/public static String[] upload(FastDFSFile file) {//獲取文件的作者NameValuePair[] meta_list = new NameValuePair[1];meta_list[0] = new NameValuePair("author", file.getAuthor());//接收返回數據String[] uploadResults = null;StorageClient storageClient=null;try {//創建StorageClient客戶端對象storageClient = getTrackerClient();/**** 文件上傳* 1)文件字節數組* 2)文件擴展名* 3)文件作者*/uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), null);} catch (Exception e) {logger.error("Exception when uploadind the file:" + file.getName(), e);}if (uploadResults == null && storageClient!=null) {logger.error("upload file fail, error code:" + storageClient.getErrorCode());}//獲取組名String groupName = uploadResults[0];//獲取文件存儲路徑String remoteFileName = uploadResults[1];return uploadResults;}/**** 獲取文件信息* @param groupName:組名* @param remoteFileName:文件存儲完整名* @return*/public static FileInfo getFile(String groupName, String remoteFileName) {try {StorageClient storageClient = getTrackerClient();return storageClient.get_file_info(groupName, remoteFileName);} catch (Exception e) {logger.error("Exception: Get File from Fast DFS failed", e);}return null;}/**** 文件下載* @param groupName* @param remoteFileName* @return*/public static InputStream downFile(String groupName, String remoteFileName) {try {//創建StorageClientStorageClient storageClient = getTrackerClient();//下載文件byte[] fileByte = storageClient.download_file(groupName, remoteFileName);InputStream ins = new ByteArrayInputStream(fileByte);return ins;} catch (Exception e) {logger.error("Exception: Get File from Fast DFS failed", e);}return null;}/**** 文件刪除* @param groupName* @param remoteFileName* @throws Exception*/public static void deleteFile(String groupName, String remoteFileName)throws Exception {//創建StorageClientStorageClient storageClient = getTrackerClient();//刪除文件int i = storageClient.delete_file(groupName, remoteFileName);}/**** 獲取Storage組* @param groupName* @return* @throws IOException*/public static StorageServer[] getStoreStorages(String groupName)throws IOException {//創建TrackerClientTrackerClient trackerClient = new TrackerClient();//獲取TrackerServerTrackerServer trackerServer = trackerClient.getConnection();//獲取Storage組return trackerClient.getStoreStorages(trackerServer, groupName);}/**** 獲取Storage信息,IP和端口* @param groupName* @param remoteFileName* @return* @throws IOException*/public static ServerInfo[] getFetchStorages(String groupName,String remoteFileName) throws IOException {TrackerClient trackerClient = new TrackerClient();TrackerServer trackerServer = trackerClient.getConnection();return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);}/**** 獲取Tracker服務地址* @return* @throws IOException*/public static String getTrackerUrl() throws IOException {return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ClientGlobal.getG_tracker_http_port()+"/";}/**** 獲取Storage客戶端* @return* @throws IOException*/private static StorageClient getTrackerClient() throws IOException {TrackerServer trackerServer = getTrackerServer();StorageClient storageClient = new StorageClient(trackerServer, null);return storageClient;}/**** 獲取Tracker* @return* @throws IOException*/private static TrackerServer getTrackerServer() throws IOException {TrackerClient trackerClient = new TrackerClient();TrackerServer trackerServer = trackerClient.getConnection();return trackerServer;} }文件上傳
創建一個FileController,在該控制器中實現文件上傳操作,代碼如下:
@RestController @RequestMapping("/file") public class FileController {@PostMapping("/upload")public Result uploadFile(MultipartFile file){try{//判斷文件是否存在if (file == null){throw new RuntimeException("文件不存在");}//獲取文件的完整名稱String originalFilename = file.getOriginalFilename();if (StringUtils.isEmpty(originalFilename)){throw new RuntimeException("文件不存在");}//獲取文件的擴展名稱 abc.jpg jpgString extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);//獲取文件內容byte[] content = file.getBytes();//創建文件上傳的封裝實體類FastDFSFile fastDFSFile = new FastDFSFile(originalFilename,content,extName);//基于工具類進行文件上傳,并接受返回參數 String[]String[] uploadResult = FastDFSClient.upload(fastDFSFile);//封裝返回結果String url = FastDFSClient.getTrackerUrl()+uploadResult[0]+"/"+uploadResult[1];return new Result(true,StatusCode.OK,"文件上傳成功",url);}catch (Exception e){e.printStackTrace();}return new Result(false, StatusCode.ERROR,"文件上傳失敗");} }總結
以上是生活随笔為你收集整理的【工具类】分布式文件存储-FastDFS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【消息中间件】AMQPRabbitMQ工
- 下一篇: 【分布式】分布式事务解决方案概述