本节主要是讲解的是分布式文件存储,主要介绍了阿里云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;每个索引被拆分成多个主分片❌ 索…