第5節:分布式文件存儲

本節主要是講解的是分布式文件存儲,主要介紹了阿里云OSS云存儲和Minio文件存儲,本章重點主要是掌握怎么在SpringBoot項目里面接入文件存儲。

記錄、交流、實踐,讓每一份付出皆可看見,讓你我共同前行😁

1.分布式文件存儲高性能高可用講解

1.1 核心知識介紹

  • 數據存儲背景:數據量持續攀升,存儲單位從 KB、MB、GB、TB、PB 到 ZB 級別,涵蓋圖片、文檔、素材、靜態頁面、音視頻、安裝包等各類文件。
  • 業務應用內存儲問題:傳統 javaweb 項目文件量增長后,會占用大量內存、磁盤和帶寬,無法滿足海量請求,存在開發易但擴容難的問題。
  • 分布式文件系統(Distributed File System)
    • 定義:文件系統管理的物理存儲資源通過計算機網絡與節點相連,或由不同邏輯磁盤分區組合形成層次化文件系統。
    • 特點:自研的分布式文件系統擴容容易,但開發難度大。

1.2 如何保證分布式存儲的高性能與高可用?

  • 常見思路:采用副本備份、雙活、多活等架構,通過復制協議同步數據到多個存儲節點,確保數據一致性,故障時自動切換服務。
  • 性能與高可用的矛盾(基于 CAP 定理)
    • 異步復制:先寫一份數據到某機器并立即返回,再異步備份。性能好,但存在容錯風險(如未同步時節點宕機導致數據丟失)。
    • 同步多寫:同時寫多個副本,全部成功后返回。保證數據一致性,但性能受最慢機器影響,性能下降。
  • 選擇依據
    • 若要求高性能,可接受偶爾文件丟失或訪問出錯,選異步復制。
    • 若要求高可用,需保證數據一致性,選同步多寫,犧牲部分性能。
  • 類似案例:RocketMQ 消息高可用采用同步雙寫、異步刷盤策略,即同時寫到兩個節點內存后返回,再異步持久化到磁盤。

1.3 分布式文件存儲業界常見解決方案介紹

解決方案

特點

MinIO

Apache License v2.0 下的對象存儲服務器,學習、安裝運維簡單,支持主流語言客戶端整合,可與容器化技術結合,社區活躍但不夠成熟,參考資料少

FastDFS

開源輕量級分布式文件系統,客戶端少(主要 C 和 java),在互聯網創業公司應用較多,無官方文檔,社區不活躍,架構和部署復雜,問題定位難

云廠商(阿里云 OSS、七牛云、騰訊云、亞馬遜云等)

優點:開發簡單,功能強大,易維護(支持不同網絡下圖片質量、水印、加密、擴容、加速等);缺點:收費,個性化處理和未來轉移復雜(部分廠商提供一鍵遷移)

CDN(Akamai)

在 CDN 領域表現突出

2.Minio

官方網站: MinIO | 企業級高性能對象存儲 - MinIO 對象存儲

2.1 環境安裝

docker run -d -p 9111:9111 -p 9112:9112 --name guslegend_minio \
-e "MINIO_ROOT_USER=XXX" \
-e "MINIO_ROOT_PASSWORD=XXX" \
-v /dev-ops/minio/data:/data \
-v /dev-ops/minio/config:/root/.minio \
minio/minio:RELEASE.2025-04-22T22-12-26Z server /data --console-address ":9112" --address ":9111"

步驟

  1. 訪問控制臺
  2. 創建 bucket
  3. 上傳文件
  4. 預覽

總結

MinIO 操作流暢,支持單機和集群部署。對于不能或不使用云廠商存儲服務的場景,可自建 MinIO 對象存儲集群。

2.2 項目配置

在父文件夾的pom文件中添加maven依賴,并且在用戶服務里面也添加。

 <!-- Minio各個項目單獨加依賴,根據需要進行添加--><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.2</version></dependency>

微服務配置minio

minio:endpoint: http://localhost:9111accesskey: secretKey: bucketname: 

創建MinioConfig配置類

@Data
@ConfigurationProperties(prefix = "minio")
@Component
public class MinioConfig {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketname;
}

2.3 編碼實戰

service層開發

    @Overridepublic String uploadFileByMinio(MultipartFile file) {try {MinioClient minioClient = MinioClient.builder().endpoint(minioConfig.getEndpoint()).credentials(minioConfig.getAccessKeyId(), minioConfig.getAccessKeySecret()).build();//判斷桶是否存在boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioConfig.getBucketname()).build());if (!found) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConfig.getBucketname()).build());}else {log.info("{}桶,存在",minioConfig.getBucketname());}//設置存儲對象的名稱String folder= String.format("%s",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")));String fileName = CommonUtil.generateUUID();String newFileName = folder+fileName+file.getOriginalFilename();PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(minioConfig.getBucketname()).stream(file.getInputStream(), file.getSize(),-1).object(newFileName).build();minioClient.putObject(putObjectArgs);String imgUrl =minioConfig.getEndpoint()+"/"+minioConfig.getBucketname()+"."+newFileName;log.info("文件上傳地址為:{}",imgUrl);return imgUrl;} catch (Exception e) {log.error("文件上傳失敗:{}",e);}return null;}

controller層開發

    @PostMapping("upload_by_minio")public JsonData uploadHearImgByMinio(MultipartFile file){String result = fileService.uploadFileByMinio(file);return result!=null?JsonData.buildSuccess(result):JsonData.buildResult(BizCodeEnum.FILE_UPLOAD_USER_IMG_FAIL);}

3.阿里云OSS

官方網站:對象存儲_云存儲服務_企業數據管理_存儲-阿里云

3.1 項目配置

在父文件夾的pom文件中添加maven依賴,并且在用戶服務里面也添加。

 <!-- OSS各個項目單獨加依賴,根據需要進行添加--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.10.2</version></dependency>

在用戶服務配置配置文件

aliyun:oss:endpoint: XXXaccess-key-id: XXXaccess-key-secret: XXXbucketname: XXX

創建OSSConfig配置類

@ConfigurationProperties(prefix = "aliyun.oss")
@Configuration
@Data
public class OSSConfig {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;
}

3.2 編碼實戰

UUID隨機生成工具類開發

   /*** UUID* @return*/public static String generateUUID() {return UUID.randomUUID().toString().replace("-", "");}

service層編寫

@Slf4j
@Service
public class FileServiceImpl implements FileService {@Autowiredprivate OSSConfig ossConfig;@Overridepublic String uploadFile(MultipartFile file) {String originalFileName = file.getOriginalFilename();//相關配置String endpoint = ossConfig.getEndpoint();String accessKeyId = ossConfig.getAccessKeyId();String accessKeySecret = ossConfig.getAccessKeySecret();String bucketName = ossConfig.getBucketName();//創建OSS對象OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");String folder = localDateTime.format(formatter);String fileName = CommonUtil.generateUUID();String extension = originalFileName.substring(originalFileName.lastIndexOf("."));//在OSS創建shop-user文件夾String newFileName = "shop-user/"+folder+"/"+fileName+"."+extension;try {PutObjectResult result = ossClient.putObject(bucketName, newFileName, file.getInputStream());//訪問路徑if (null!=result){String imgUrl = "https://"+bucketName+"."+endpoint+"/"+newFileName;return imgUrl;}} catch (Exception e) {log.error("頭像上傳失敗",e);}finally {//關閉OSS對象ossClient.shutdown();}return null;}
}

controller層編寫

@RestController
@RequestMapping("/api/user/v1")
public class UserController {@Autowiredprivate FileService fileService;/*** 上傳用戶頭像* @param file* @return*/@PostMapping("upload")public JsonData uploadHearImg(MultipartFile file){String result = fileService.uploadFile(file);return result!=null?JsonData.buildSuccess(result):JsonData.buildResult(BizCodeEnum.FILE_UPLOAD_USER_IMG_FAIL);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95460.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95460.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95460.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

當 GitHub 宕機時,我們如何協作?

一、引言1.1 GitHub 的重要性及宕機影響在當今軟件開發的生態系統中&#xff0c;GitHub 已然成為全球開發者不可或缺的核心平臺。它為無數開源項目與企業級開發團隊提供了高效的代碼托管、版本控制、協作開發以及項目管理等服務。然而&#xff0c;2025 年 8 月那場波及全球的 G…

Ansible 常用模塊歸納總結

[studentmaster ansible]$ ansible-galaxy collection install http://ansible.example.com/materials/community-general-6.3.0.tar.gz -p collections/##將第三方模塊下載到collections下 [studentmaster ansible]$ ansible-galaxy collection install http://ansible.exampl…

計算機網絡:概述層---TCP/IP參考模型

&#x1f310; TCP/IP四層模型詳解&#xff1a;互聯網的核心協議架構深度剖析 &#x1f4c5; 更新時間&#xff1a;2025年9月3日 &#x1f3f7;? 標簽&#xff1a;TCP/IP模型 | 互聯網協議 | 四層模型 | 計算機網絡 | 協議棧 | 網絡通信 | 王道考研 摘要: 本文將深入淺出地解析…

打工人日報#20250902

打工人日報#20250902 今天晚上去了玄武湖&#xff0c;來南京三次了&#xff0c;終于來了一次知識點 不確定度 “不確定度” 是測量領域的核心概念&#xff0c;用于量化測量結果的可靠性與分散程度—— 簡單來說&#xff0c;它回答了 “這個測量值有多可信&#xff1f;真實值可能…

告別手動復制粘貼:C# 實現 Excel 與 TXT 文本文件高效互轉

在日常辦公和數據處理工作中&#xff0c;Excel 和 TXT文本文件是兩種常見的數據存儲格式。Excel文件適合進行復雜的數據分析、公式運算和圖表生成&#xff0c;而 TXT文件則更適合用于存儲和傳輸純文本數據&#xff0c;如日志、配置文件或簡單的數據列表。很多時候&#xff0c;我…

elasticsearch學習(二)插件安裝

目錄上一篇文章查看插件安裝分詞器analysis-icu重啟實例重新查看插件上一篇文章 elasticsearch學習&#xff08;一&#xff09; 下載、安裝和初次部署 查看插件 ? bin elasticsearch-plugin list warning: ignoring JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_…

(原創)SAP ATP可用量檢查 OPJJ功能配置說明(900+字!)

前言&#xff1a;經常在ATP遇到問題&#xff0c;每次上網找都沒有相關資料&#xff0c;一氣之下直接在官網找資料收集&#xff0c;已整理相關字段與大家分享&#xff0c;避免大家走彎路附上我個人很久之前的的測試結果&#xff1a;具體字段控制說明檢查不考慮補貨提前期關聯字段…

Unity資源管理——操作一覽(編輯器下 運行時)

本文由 NRatel 歷史筆記整理而來&#xff0c;如有錯誤歡迎指正。 資源管理是Unity游戲開發中的重頭工作之一。 以下按【編輯器下】和 【運行時】&#xff0c;共十多個步驟&#xff0c;一覽總體流程&#xff08;內容巨大&#xff0c;不細展開&#xff09;。 一、資源導入Unity【…

Sentinel vs Resilience4j vs Bucket4j:分布式限流方案對比與實戰

Sentinel vs Resilience4j vs Bucket4j&#xff1a;分布式限流方案對比與實戰 在高并發微服務架構中&#xff0c;合理的限流策略是保護系統穩定性與可用性的關鍵。本文將從問題背景入手&#xff0c;對 Sentinel、Resilience4j 和 Bucket4j 三種常見的分布式限流方案進行對比&am…

Spring Boot 3.5.3 集成 Log4j2 日志系統

在 Spring Boot 3.5.3 中&#xff0c;要將默認的 Logback 替換為 Log4j2&#xff0c;需要以下步驟&#xff1a;1. 添加 Log4j2 依賴在 pom.xml中排除默認的 Logback 依賴并添加 Log4j2 依賴&#xff1a;<dependencies><!-- 排除默認的 Logback --><dependency&g…

ADB圖片上傳輪播

可以通過ADB在機器中進行上傳照片&#xff0c;進行其他圖片播放 當前系統架構分析 1. 現有組件結構 ImageCarouselActivity: 主要的輪播Activity&#xff0c;繼承自BaseBindingActivity 實現全屏顯示和沉浸式體驗使用ViewPager2進行圖片輪播支持自動輪播&#xff08;5秒間隔&…

異常處理小妙招——2.代碼的韌性:如何實現操作的原子性回滾

一、核心思想&#xff1a;什么叫“失敗原子性”&#xff1f; 想象一下你在玩一個闖關游戲&#xff0c;有一關需要你連續跳過三個平臺。 不具有原子性&#xff1a;你跳過了第一個和第二個平臺&#xff0c;但在跳第三個時失敗了、掉下去了。結果你不僅沒過關&#xff0c;連之前跳…

Crawl4AI:為LLM而生的下一代網頁爬蟲框架

在當今AI驅動的信息處理時代&#xff0c;從網頁中高效提取高質量、結構化的數據已成為連接互聯網與大語言模型&#xff08;LLM&#xff09;的關鍵橋梁。Crawl4AI作為一款開源的LLM友好型網頁爬蟲與刮板工具&#xff0c;正迅速成為開發者處理這一任務的首選解決方案。本文將深入…

輸出一個愛心

輸出效果&#xff1a;代碼實現&#xff1a;#include<iostream> #include<iomanip> #include<algorithm> using namespace std; int main() {int n;cin>>n;char a[8] {I,L,O,V,E,Y,O,U};int j 1;int k n*21;int o n*2-2;int aa 0; for(int i 0;i&…

深度集成Dify API:企業級RAG知識庫管理平臺解決方案

&#x1f3af; 需求和概述 當前基于Dify實現企業級的智能問答系統需求日益增長&#xff0c;Dify的低代碼開發框架和功能完整、靈活適應各種需求的特色得到廣大大模型和RAG開發著的歡迎。但是Dify在落地企業級應用時候&#xff0c;也面臨不少的問題&#xff0c;最突出的就是Dif…

C++循環越界問題

for (int i 0; i < historyTableList.size() - 1; i) {historyList2.push_back(historyTableList[i]); } historyList.size()0時&#xff0c;為什么會異常historyTableList.size() 返回的是 size_t 類型&#xff08;無符號整數&#xff09;當 size() 0 時&#xff0c;size…

MongoDB 從零到入門:實用指南

什么是 MongoDB&#xff1f; MongoDB 是一個流行的非關系型數據庫&#xff08;NoSQL&#xff09;&#xff0c;它使用類似 JSON 的文檔來存儲數據&#xff0c;而不是傳統的表格形式。這使得 MongoDB 非常靈活&#xff0c;特別適合處理半結構化數據和快速迭代的開發場景。 核心概…

WebRTC音頻QoS方法五(音頻變速算法之Expand算法實現)

一、概述介紹在WebRTC中&#xff0c;存在兩種擴展算法&#xff1a;PreemptiveExpand和Expand。盡管這兩種算法的目標都是擴展音頻信號&#xff0c;但它們的實現原理和應用場景卻有所不同。PreemptiveExpand&#xff08;預防性擴張&#xff09;主動擴展策略&#xff0c;旨在防止…

【Python - 基礎 - 工具】解決pycharm“No Python interpreter configured for the project”問題

解決pycharm“No Python interpreter configured for the project”問題 當你在 PyCharm 中遇到“No Python interpreter configured for the project”錯誤時&#xff0c;意味著你的項目沒有配置 Python 解釋器。以下是解決該問題的步驟。 示例 # 嘗試運行代碼時出現錯誤 prin…

Elasticsearch創建索引分片和副本大小建議

在Elasticsearch中&#xff0c;?分片(shard)和副本(replica)? 的設置直接影響集群性能、容錯能力和擴展性。以下是最佳實踐指南&#xff1a;核心概念?類型??描述??是否可修改??主分片(Primary Shard)?數據的最小存儲單元&#xff0c;每個索引被拆分成多個主分片? 索…