一、體系結構
二、上傳流程
什么是fastDFS:
fastDFS是一個底層使用C語言編寫的, 開源的免費的分布式文件系統
fastDFS作用:
fastDFS主要作用就是上傳文件, 下載文件, 刪除文件等對文件的管理存儲.
fastDFS運行原理:
1. fastDFS分為三部分: 客戶端, 是指我們的購物項目。
tracker端, 也就是管理端是指管理服務器, 管理服務器不存儲文件, 只負責管理存儲端服務器。
storage端, 也就是存儲端, 負責存儲具體文件內容。
2. 存儲端啟動后會到管理端注冊, 告訴管理端他的ip, 端口和狀態, 我們需要存儲文件的時候, 連接管理端,管理端會給我們返回具體服務器的ip地址, 端口號, 客戶端就拿着ip和端口去調用存儲端服務器存儲文件,存儲后會返回文件存儲的路徑和文件名, 存儲端服務器會對文件自動重命名, 防止文件重名。
3. 管理端: 一台主機, 多台備機, 主備之間有心跳檢測機制, 可以高可用,管理端有負載均衡的功能, 可以將請求均勻的分配給每一台存儲端服務器處理。
存儲端: 一台主機, 一台備機, 主備之間有心跳檢測機制, 高可用, 存儲的時候, 向主機中存儲內容。
主機會將內容同步到備機, 主備之間存儲的內容一樣, 叫做冗余備份功能, 容災效果強,存儲端服務器可以理論上無限擴容, 擴展性強。
優點:
1. 管理端有高可用, 負載均衡功能, 可以承載高並發
2. 存儲端冗余備份, 高可用, 無限擴容
缺點:
服務器集群需要企業自行搭建運維, 成本比較高.
使用場景:
適合大型互聯網公司, 大規模存儲任務使用.
fastDFS硬件服務器:
fastDFS服務器叫做存儲服務器: 要求讀寫效率高
1. 如果經費充足: 可以購買ibm的nas服務器
2. 如果經費不夠充足: 一般可以使用8塊硬盤組成raid10磁盤陣列系統
硬盤分類: 5400轉
7200轉
12000轉 讀最快500多兆每秒, 寫最快300多兆每秒
我們使用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
-
-
<group name> 是組名,即storage的組
-
如果想要增加新的storage服務器,再次運行該命令,注意更換 新組名
修改nginx的配置
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容器
docker restart storage
四、
創建文件管理微服務changgou_service_file,該工程主要用於實現文件上傳以及文件刪除等功能。
(1)修改pom.xml,引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>changgou_service</artifactId> <groupId>com.changgou</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>changgou_service_file</artifactId> <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> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou_common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
(2)在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和端口設置
(3)在resources文件夾下創建application.yml
spring:
servlet:
multipart:
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
max-file-size是單個文件大小,max-request-size是設置總上傳的數據大小
(4)啟動類 創建com.changgou包,創建啟動類FileApplication
@SpringBootApplication
@EnableEurekaClient
public class FileApplication {
public static void main(String[] args) {
SpringApplication.run(FileApplication.class);
}
}
五、
文件上傳一般都有文件的名字、文件的內容、文件的擴展名、文件的md5值、文件的作者等相關屬性,我們可以創建一個對象封裝這些屬性,代碼如下:
創建com.changgou.file.pojo.FastDFSFile
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 ... }
2.
創建FastDFSClient類,放在com.itheima.file.util下在該類中實現FastDFS信息獲取以及文件的相關操作,
代碼如下:
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 */ 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(), meta_list); } 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 { //創建StorageClient StorageClient 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 { //創建StorageClient StorageClient storageClient = getTrackerClient(); //刪除文件 int i = storageClient.delete_file(groupName, remoteFileName); } /*** * 獲取Storage組 * @param groupName * @return * @throws IOException */ public static StorageServer[] getStoreStorages(String groupName) throws IOException { //創建TrackerClient TrackerClient trackerClient = new TrackerClient(); //獲取TrackerServer TrackerServer 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; } }
3.
@RestController @CrossOrigin public class FileController { @PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) { String path =""; try { path=saveFile(file); System.out.println(path); } catch (Exception e) { e.printStackTrace(); } return path; } /** * @param multipartFile * @return * @throws IOException */ public String saveFile(MultipartFile multipartFile) throws IOException { //1. 獲取文件名 String fileName = multipartFile.getOriginalFilename(); //2. 獲取文件內容 byte[] content = multipartFile.getBytes(); //3. 獲取文件擴展名 String ext = ""; if (fileName != null && !"".equals(fileName)) { ext = fileName.substring(fileName.lastIndexOf(".")); } //4. 創建文件實體類對象 FastDFSFile fastDFSFile = new FastDFSFile(fileName, content, ext); //5. 上傳 String[] uploadResults = FastDFSClient.upload(fastDFSFile); //6. 拼接上傳后的文件的完整路徑和名字, uploadResults[0]為組名, uploadResults[1]為文件名稱和路徑 String path = FastDFSClient.getTrackerUrl() + uploadResults[0] + "/" + uploadResults[1]; //7. 返回 return path; } }
六、Postman測試文件上傳
1、選擇post請求方式,輸入請求地址 http://localhost:9007/upload
2、填寫Headers
Key:Content-Type
Value:multipart/form-data
3、填寫body
選擇form-data 然后選擇文件file 點擊添加文件,最后發送即可。