先说个结论MinIO 确实也是把数据落到硬盘上的这一点和普通文件存储没有任何区别。真正的区别在于普通文件存储是操作系统帮你组织数据而 MinIO 是在文件系统之上重新做了一套面向大规模对象数据的组织和管理方式。换句话说同一个硬盘你把它格式化成 ext4 然后往里丢文件和你跑一个 MinIO 服务让它来管这块盘二者在数据布局、访问方式、扩展能力、容错机制上是完全不同的套路。这篇文章我从底层原理讲到实际代码把 MinIO 和直接存硬盘这两种方案的差异拆开来看也会给出我的选型建议。适合正在纠结项目里文件到底该本地存还是上 MinIO的开发者也适合刚接触对象存储、想弄明白它到底比文件系统强在哪的同学。1. 先把普通的文件存储在硬盘上说清楚1.1 硬盘、分区和文件系统之间的关系很多人说文件存储就是存到硬盘上这话对但少了一层关键的东西硬盘本身只是一块能读写二进制数据的设备真正帮你把文件这种逻辑概念落到硬盘上的是文件系统。常见的有 Windows 的 NTFS、Linux 的 ext4 / XFS / BtrfsmacOS 的 APFS。文件系统要做的事情很多但核心之一是把文件路径转换成硬盘上的物理块地址。比如你存了一个文件/data/upload/photo1.jpgext4 不会在硬盘上有一个叫/data/upload的真实目录等你往里丢数据。实际上这个路径会被分解成目录项dentry和 inode 两层结构目录项记录文件名和 inode 编号的对应关系inode 里再记录这个文件的元数据权限、大小、时间戳以及它占用了哪些数据块。严格来说/data/upload/photo1.jpg 这个层级目录 文件名的路径结构是文件系统呈现给用户和应用程序的虚拟视图。在硬盘上数据可能是东一块西一块地放着中间还隔着其他文件的数据块。操作系统通过 inode 里的索引把这些散落的块串起来让你打开文件时感觉它是一段连续的内容。这里要理解一个关键点本地文件系统的一切设计都是围绕单机、单操作系统视角来做的。它假设只有一台机器一个内核一套挂载路径由这一个系统负责所有文件的增删改查。1.2 直接存硬盘在真实项目中会遇到什么瓶颈单机场景下把用户上传的图片、附件直接写到一个自定义目录里是最直观的做法。我早年做项目也是这么干的流程大约是这样服务器上建一个/data/files目录按日期分子目录比如/data/files/2024/07/18/文件名用 UUID 或时间戳重命名防止冲突把文件路径存进数据库访问时直接拼 URL 让 Nginx 或 Spring 静态资源映射去读。这个方案在初期非常香代码简单性能也不差毕竟本地文件读写有操作系统 Page Cache 加持。但一旦项目长大问题就一个个冒出来单机磁盘容量有上限。一块数据盘常见就是几个 T 到十几个 T就算上 RAID 列阵机器的硬盘托架和背板带宽也是有限的。等业务量上来你会发现自己不是在写业务代码而是在天天看磁盘水位。多台服务器之间共享文件是个大坑。今天很多应用是集群部署的Nginx 负载均衡后面挂好几台应用服务器。用户上传的文件落在 A 机器上下一个请求被分发到 B 机器B 机器上却没有这个文件。解决办法通常是搞 NFS 共享盘或者把文件推到独立的文件服务器。但 NFS 本身有单点风险性能一般而且要求所有服务器的文件系统权限映射一致否则会出现各种权限错乱。备份和容灾全靠自己写脚本。我见过很多项目用 crontab 定时 rsync 把数据目录同步到另一台机器这种方案能解决硬盘坏了的问题吗严格说只能解决一部分。rsync 同步过程中如果源端正在写入可能复制到不完整的文件同步本身也没有校验机制硬盘上的静默数据腐败Bit Rot根本发现不了。至于多副本、跨机房容灾那完全是另一个量级的工作量。权限体系和应用脱节。本地文件系统用的是 POSIX 权限模型user / group / other 三组权限位。但真实项目里权限往往是很细的某个用户的某个文件只允许他自己读你不可能为每个用户创建一个操作系统账号。所以最后代码里通常都是在 Controller 层判断完权限再决定要不要把文件路径暴露出去。文件本身躺在磁盘上是裸露的谁有服务器权限谁就能读。1.3 本地文件存储也不是一无是处说了这么多问题但我并不想劝退所有人。本地文件存储在特定场景下依然是最优解单机部署的小项目、内部管理系统日上传量不大对文件不需要多机共享不存在集群访问访问量高要求极低延迟文件又不需要跨网络传输数据敏感性一般丢了或者损坏了影响可控。这种场景下你非要上 MinIO 反而增加复杂度多一个服务要部署、要监控、要维护请求链路多了网络和 HTTP 开销还没有明显收益。2. MinIO 到底是什么它凭什么说自己不一样2.1 MinIO 是对象存储不是网络硬盘MinIO 是一个开源的对象存储服务完全兼容 Amazon S3 的 API。所谓对象存储核心抽象就两个概念Bucket存储桶和Object对象。你可以把 Bucket 理解成顶层目录把 Object 理解成文件。但注意对象存储中是没有子目录这种层级概念的。你在 MinIO 里看到一个 key 叫2024/07/18/photo1.jpg看起来像路径实际上它只是一个扁平的字符串也就是对象的完整名称。MinIO 内部不需要像文件系统那样去维护一棵目录树它只需要把这个字符串和一堆数据块关联起来就行。这个扁平命名空间的设计非常关键。本地文件系统要访问一个深层路径的文件需要逐级查找目录项目录层级越深、目录下文件越多查找开销越大。而对象存储直接通过 key 定位对象配合内部的元数据索引哪怕一个 bucket 里放几亿个对象也不存在单个目录文件过多的性能衰减问题。2.2 纠删码MinIO 在硬盘层面玩的魔术MinIO 最大的亮点之一是它默认用**纠删码Erasure Coding**来保护数据。这跟传统的 RAID 有本质区别。拿最常见的 RAID 5 举例它允许一块磁盘故障数据不丢RAID 6 允许两块。MinIO 用 Reed-Solomon 纠删码算法可以把一个对象切成 N 个数据分片再算出 M 个校验分片然后把 NM 个分片分散到不同硬盘甚至不同节点上。只要剩下的分片数大于等于 N整个对象就能完整恢复。举个具体的例子一个分布式 MinIO 集群有 12 块盘设置数据分片 8、校验分片 4简写为 EC:8,4那么每个对象都会被拆成 8412 个分片分别写到 12 块盘上。任意坏 4 块盘你仍然可以用剩下的 8 块盘完整还原数据。这个容错能力是 RAID 6 的两倍。更妙的是纠删码对空间利用率也比多副本高。同样允许坏 4 块盘如果是副本模式需要存 5 份完整数据1 个原始 4 个副本而纠删码只需要 1.5 倍存储开销8 份数据 4 份校验。这就是 MinIO 宣称自己用一半的存储成本达到更高的可靠性的原因。2.3 单机模式也是 MinIO和直接存硬盘又差在哪有人会说那如果我只在一台机器上跑一个 MinIO 单机实例底层不还是 ext4 / XFS这和直接存硬盘有啥区别区别在于抽象层。MinIO 单机模式下你的应用不再直接读写文件路径而是通过 S3 API 做上传、下载、删除、列出对象。这带来几个直接好处第一应用层和存储位置解耦以后想从单机迁移到分布式集群应用代码几乎不用改第二权限从操作系统账号权限变成了Access Key / Secret Key Bucket Policy应用可以自主控制谁能访问哪个对象第三你用上了签名 URL、预签名 URL、生命周期管理等能力这些是本地文件系统没有的。当然MinIO 底层还是需要一块格式化的硬盘来放数据。官方推荐底层文件系统用 XFS因为它对大规模并发写入和并发扩展支持更好。这一点也从侧面说明MinIO 并不是要替代文件系统而是建筑在文件系统之上的一套对象管理服务。3. 核心对比MinIO 和本地文件存储的实际差异这一节是重点我从七个维度做对比尽量用我实际经历来说明。3.1 数据组织与代码访问逻辑本地文件存储的访问逻辑是文件路径 系统调用。代码里一般是FileOutputStream写文件之后拼一个 URL 让外部访问。这里有个隐患应用服务器直接对外暴露文件目录路径一旦设计不好容易被人遍历到其他文件。我见过不少项目写String url http://xxx/download/ filename;然后 filename 被用户传成一个../../etc/passwd这种值虽然大部分框架会做过滤但属于典型的裸奔写法。MinIO 的访问逻辑是Bucket Object API。外部访问一个私有对象可以用预签名 URL比如生成一个 5 分钟有效的链接给前端下载。链接里带签名参数过期自动失效不用你去处理复杂的鉴权逻辑。这种模式天然避免了路径遍历问题因为对象 key 是经过编码的字符串不是文件系统的真实路径。3.2 扩容能力本地文件存储的扩容方式很朴素加硬盘、挂载、迁移数据。单机挂载点满了要么删数据要么换更大的盘。用了 LVM 可以在线扩容但本质上还是单机的容量上限。分布式 MinIO 的扩容思路完全不同。它支持横向扩展通过增加新的存储节点来扩展容量和性能。官方推荐的做法是新增一个 server pool新节点启动时指向原集群的地址数据会自动按照负载均衡策略分布到新 pool。整个过程不需要停机也不用手工迁移旧数据。要注意的是MinIO 扩容并不是简单地往集群里加一块盘就行。如果最初启动时节点只有一块盘那这个节点本身就不是为单节点多盘设计的后面不能随意给这个节点插新盘来扩容。正确的扩容姿势是加新节点、或者用多盘模式从一开就规划好。这个细节容易踩坑后面第 5 节我再细说。3.3 数据可靠性与容灾本地文件存储在可靠性上完全依赖你天然认为文件系统是可靠的——写进去了就能读出来。但实际上硬盘会出现坏道、静默数据损坏、断电导致文件系统不一致等问题。MinIO 的可靠性体系是分层的底层纠删码保证磁盘损坏时数据不丢数据自愈功能会定期扫描并自动修复损坏的分片版本控制能保留历史版本防止误删。分布式模式下数据分片还会分布到多台机器单台机器宕机不影响整体服务。我之前给一个客户做过一次迁移客户原来就是一台服务器两块盘 RAID 1 存文件。后来一块盘 SMART 报错虽然 RAID 还能撑但换盘期间所有人都提心吊胆。迁到三节点 MinIO 之后存储节点随便宕一台应用完全无感知这才体会到可维护性的价值。3.4 权限模型这个差异非常明显。本地文件系统的权限是 POSIX 用户/组模型权限粒度是文件级授权对象是操作系统账号。应用层要做更细的权限控制只能在业务代码里自己实现查了数据库发现没权限所以不给你返回文件。文件只要躺在磁盘上任何有服务器权限的进程都能读。MinIO 的权限体系是自带的应用级权限访问凭证Access Key 和 Secret Key相当于你的用户名密码Bucket Policy可以设置某个 bucket 是公开读、公开写、还是私有IAM Policy给不同用户/组分配不同的 action 权限比如只允许下载、不允许删除STS 临时凭证适合为移动端或临时用户生成短期有效的访问凭证。这套体系对开发者友好得多。前端上传时只需要给客户端一个临时上传凭证它只能往指定 bucket 传不能读别人的文件后端生成预签名 URL也能精确控制有效期。3.5 性能差异谁快谁慢要分场景关于性能很多人一上来就问MinIO 是不是比直接存硬盘慢答案是看场景。单机、单并发、小文件的读写本地文件路径访问最快毕竟是内核级别的成熟路径没有网络和 HTTP 开销也没有签名校验。大文件的顺序读写本地单块盘受限于单盘 IO 带宽可能只有一两百 MB/s分布式 MinIO 可以让数据分片分散在多块盘上并发读写整体吞吐容易做到更高。海量小文件的随机访问本地文件系统在目录下文件超过几十万之后目录项查找和 inode 缓存压力会明显上升MinIO 用扁平 key 设计配合多线程调度在管理海量小对象时更容易保持稳定的访问性能。视频播放 / 图片加载如果只是同一个机房内、同一个源站用 Nginx 直接 serve 静态目录通常比 MinIO 更快因为少一层对象存储的处理。但 MinIO 支持大文件的分段读取和 HTTP Range 请求配合 CDN 回源实际播放体验不会差而且更便于做访问控制。我还要说一个很多人忽略的点MinIO 是服务会占 CPU 和内存。你拿一台 2C4G 的小机器硬跑性能肯定不如直接在磁盘上读文件。性能对比要建立在恰当的资源配置上不然没有意义。3.6 运维与监控本地文件系统的运维手段大家都很熟df -h看磁盘空间smartctl看硬盘健康状态du -sh查目录大小。但这些都是被动的往往快满了、坏了才知道。MinIO 提供了完整的监控体系控制台可以看 bucket 容量、对象数量、每分钟请求量通过 Prometheus 接口导出指标官方有 Grafana Dashboard可以告警节点离线磁盘空间不足请求延迟飙升。我个人生产环境里一定会在监控面板上盯几个指标集群总容量、每节点数据量、上传/下载请求 QPS、5xx 错误数、健康检查失败次数。新版 MinIO 的监控接口有 v2 和 v3 两代命名和字段有差异配置 Prometheus 时要注意版本。这个也是热搜词里很多人问的我放到第 5 节详细说。3.7 成本与运维复杂度的账本地文件存储几乎没有额外成本就是硬盘钱。MinIO 单机版也是免费的但如果要上分布式集群至少得准备多台机器每台机器多块盘还要考虑网络、机房、监控告警体系。软件层面的运维复杂度也高一个档次服务升级、节点故障处理、重平衡、证书管理都得有人负责。有些公司规定禁用 MinIO我理解的原因大概是这几点一是 AGPL v3 开源许可证对部分有严格合规审计的公司不友好二是维护它需要专门的运维能力小团队扛不住三是某些云厂商已经提供了完全托管的 S3 兼容服务没必要自己折腾。说实话如果你们公司没有对象存储方面的运维经验我更建议先考虑托管云服务而不是自己搭集群。下面把这一节的要点压成一张表方便对照。对比项本地文件存储MinIO 对象存储数据模型目录树 文件名Bucket Object扁平 key访问方式文件路径 系统调用S3 API / HTTP 签名权限控制POSIX 账号权限与应用脱节内置用户/密钥/Bucket Policy/STS扩容方式加盘、换大盘、手工迁移分布式加节点自动重平衡数据冗余依赖 RAID / 手工备份纠删码 自愈多节点容灾典型性能单机低延迟单盘带宽有限分布式横向伸缩单机略慢运维成本低但被动高需要配套监控和运营能力适用场景小项目、单机、内网海量对象、集群共享、云原生4. 代码层集成从改路径到调 API到底要动多少代码光说概念没用我直接拿代码对比一下。假设场景是 Spring Boot 项目的一个文件上传接口前端传一个MultipartFile后端保存。4.1 传统本地文件存储的写法PostMapping(/upload) public String upload(RequestParam(file) MultipartFile file) { // 生成存储目录按日期分目录避免单目录文件过多 String dateDir LocalDate.now().format(DateTimeFormatter.ofPattern(yyyy/MM/dd)); // 生成唯一文件名防止重名和路径穿越 String ext FilenameUtils.getExtension(file.getOriginalFilename()); String objectName UUID.randomUUID().toString().replace(-, ) . ext; String filePath uploadRoot / dateDir / objectName; File dir new File(uploadRoot / dateDir); if (!dir.exists()) { dir.mkdirs(); } file.transferTo(new File(filePath)); // 返回给前端的访问 URL return https://static.example.com/ dateDir / objectName; }这段代码看起来简洁但后面隐藏着一堆问题uploadRoot 配置要每台机器保持一致多实例部署时文件只落到了当前节点磁盘空间满了没人知道备份要靠另外的脚本。4.2 换成 MinIO 的写法要集成 MinIO首先确认依赖。如果用的是 Mavendependency groupIdio.minio/groupId artifactIdminio/artifactId version8.5.7/version /dependency然后配置一个 MinioClient 的 BeanBean public MinioClient minioClient() { return MinioClient.builder() .endpoint(http://192.168.1.10:9000) .credentials(your-access-key, your-secret-key) .build(); }上传接口就会变成这样PostMapping(/upload) public String upload(RequestParam(file) MultipartFile file) throws Exception { String ext FilenameUtils.getExtension(file.getOriginalFilename()); String objectName uploads/ LocalDate.now() / UUID.randomUUID().toString().replace(-, ) . ext; // 检查 bucket 是否存在不存在则创建 boolean found minioClient.bucketExists( BucketExistsArgs.builder().bucket(app-files).build()); if (!found) { minioClient.makeBucket(MakeBucketArgs.builder().bucket(app-files).build()); } // 上传对象可以指定 Content-Type 和元数据 minioClient.putObject(PutObjectArgs.builder() .bucket(app-files) .object(objectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build()); // 生成一个 7 天内有效的下载链接或者直接返回对象路径 String url minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(app-files) .object(objectName) .expiry(60 * 60 * 24 * 7) .build()); return url; }可以看到代码结构和本地存储完全不同了不再关心文件最终落在哪块硬盘、哪个目录只关心 bucket 和 object key。MinioClient 封装了和服务的所有交互包括签名、重试、分片上传等。如果想让文件公开可访问可以通过 MinIO 控制台或命令行 mc 设置 bucket 策略mc anonymous set download myminio/app-files设置完之后所有对象都可以通过http://192.168.1.10:9000/app-files/objectName直接 GET 到不需要签名。4.3 上传视频、断点续传和前端接入有些场景需要上传大视频。虽然 MinIO 支持单次 putObject 上传大文件但更稳妥的是用分片上传Multipart Upload。MinIO SDK 里对应createMultipartUpload、uploadPart、completeMultipartUpload这套流程底层就是 S3 的分片协议天然支持断点续传。实现断点续传时客户端要做好分片的大小规划每个分片最小 5MB最多 10000 个分片所以文件超大时分片大小要相应调大避免超上限。前端如果直接对接推荐用 AWS S3 的 JavaScript SDK把 endpoint 指到 MinIO 地址代码可以复用云上 S3 的整套逻辑。我之前帮同事排查过一个 Vue 项目他用 axios 直接往 MinIO 的 URL 上传老是报签名错误后来换成 S3 SDK 的putObject方法就好了。因为 MinIO 的签名算法是 S3 SigV4手工拼请求头很容易漏字段。另外有一个高频问题前端从本地文件夹直接加载图片和通过 MinIO 加载图片哪个效率高如果图片是纯静态的、不需要鉴权、就在同一个站点下那肯定直接 Nginx 静态服务更快毕竟少一次 HTTP 跳转。但如果你要鉴权、要跨域、要后续上 CDN、要迁移到云端对象存储那 MinIO 的方案明显更合理而且它是标准 HTTP 协议浏览器直接支持前端代码用普通的img src签名URL就能显示。4.4 Windows 上快速体验 MinIO不少人想在本地 Windows 上先试试 MinIO。实际上很简单去 MinIO 官网下载 Windows 版的 exe然后打开命令行执行minio.exe server D:\minio-data启动的时候终端会打印出 Access Key 和 Secret Key以及控制台地址默认是http://127.0.0.1:9000。用浏览器打开控制台输入密钥就能操作。如果机器上有 Docker也可以直接docker run -p 9000:9000 -p 9001:9001 \ -e MINIO_ROOT_USERadmin \ -e MINIO_ROOT_PASSWORDpassword123 \ -v D:/minio-data:/data \ minio/minio server /data --console-address :9001本地体验单机版绰绰有余。但要上生产最好还是按官方推荐用 Linux XFS 文件系统 分布式部署别拿 Windows 跑生产节点。5. 常见问题与踩坑记录这里把我这些年实际遇到、以及社区里高频出现的问题整理成一个速查表都是能直接用的经验。常见问题原因与解决办法上传的视频在浏览器里无法播放多半是上传时没有指定 Content-Type默认返回 application/octet-stream。用 SDK 的 putObject 显式设置 contentType比如 video/mp4。另外确认服务端响应里能正确处理 Range 请求MinIO 默认支持但如果你在前面套了一层 Nginx 做转发要把 Range 头透传过去。MinIO 支持断点续传吗支持通过 Multipart Upload 实现。客户端要自己规划分片并记录已上传的分片重新上传时先 listParts 找出已完成的 Part继续传剩下的。注意每个分片最小 5MB最多 10000 个分片。监控指标用 v2 还是 v3新版强烈建议用 v3 指标接口命名更规范兼容性好官方 Grafana Dashboard 也基于 v3。拉取指标时通常需要带 token注意在 Prometheus 配置里配好鉴权信息。集群扩容只能加节点吗MinIO 支持增加 server pool 来扩容。单机多盘模式可以按官方要求扩充磁盘组但单机单盘模式不能简单地给原节点加盘正确方式是新增节点组成新的 pool新 pool 加入后数据会自动重平衡。minio.nosuchfielderror companion 报错一般是 Java SDK 版本与 JDK 或依赖冲突导致反射字段找不到。优先升级/对齐 minio SDK 版本检查项目里是否混用了不同版本的 aws-sdk 依赖。公司为什么要禁用 MinIO常见原因AGPL v3 许可证合规压力、对象存储运维成本、安全审计要求、以及对非必要引入开源组件的管控。如果你所在公司有这类政策建议先问清楚再引入。bucket 权限在哪里改控制台里选中 bucket 可以配置匿名策略也可以写 Bucket Policy JSON。命令行更快mc anonymous set download myminio/app-files设为公开读。前端加载 MinIO 图片很慢先确认是不是跨域和网络链路问题再检查 MinIO 是否限速或节点过载。如果是小图片高频访问建议前面加 CDN 或 Nginx 缓存MinIO 本身也是支持 HTTP 缓存头的。MinIO 启动时提示读取磁盘序列号失败常见于容器或虚拟化环境宿主没有提供硬盘序列号。MinIO 一般会降级为随机 UUID 作为节点标识不影响数据读写但可以检查是否属于硬件直通配置问题。单机版 MinIO 能扛住生产吗小规模、单机场景下可以跑但要注意它没有多节点容灾。如果盘坏了数据一样会丢。生产有可靠性要求的话还是老老实实部署分布式集群。5.1 关于版本控制的坑MinIO 的版本迭代很快官方对旧版本的维护周期也短。集成时建议固定一个大版本不要动不动就升级大版本因为 API 偶有破坏性调整。比如 Java SDK 从 7.x 升到 8.x一些方法的参数类型就变了。我的习惯是代码库和 MinIO 服务端版本都记录在项目的 README 里升级前先看 release notes。5.2 纠删码配置到底该怎么选纠删码的配比直接决定了容错能力和存储利用率。比如 12 块盘EC:8,4 意味着最多容忍 4 块盘故障空间利用率 8/1266.7%。如果改成 EC:10,2空间利用率 83.3%但只能容错 2 块盘。这是个典型的权衡要容错更多就要牺牲更多空间。我一般这样选型数据重要性高、集群规模小选择 NM 附近比如 EC:8,8容错很强但空间利用率只有 50%。常规生产环境EC:8,4 或 EC:10,2 比较均衡。对容量要求高、已经有备份体系EC:14,2 这类高数据占比配比。注意纠删码配比在启动集群时就要规划好后续加 pool 时通常要求新 pool 的盘数配置和原集群一致否则会创建出不同 EC 配比的 pool管理上更复杂。5.3 从直接存硬盘迁移到 MinIO 的成本如果你已经在项目里用了本地文件存储迁移到 MinIO 的成本主要在代码改造而不是数据迁移。核心思路是把文件存储抽象成一个接口比如FileStorageService下面有save(),download(),delete(),getUrl()四个方法。本地实现走 File 操作MinIO 实现走 SDK配置里给一个开关切换。很多后台框架比如 RuoYi若依其实已经内置了这种文件存储适配层支持本地路径和 MinIO 两种模式你只要改配置就能切换这也是它常被用在中小项目里的原因。数据迁移本身也不复杂可以用mc mirror命令把本地目录同步到 bucket 里mc mirror /data/files myminio/app-filesmc 会校验源和目标的元数据增量同步传完后再做一次校验。大量小文件建议先打包再传否则并发不够会慢。最后说一句我的体会我在实际项目里的选型原则很朴素如果只是单机小项目、文件量不大、没有多机共享需求我可能直接用本地存储配一个 rsync 定时备份就完事了。但一旦有任何一个将来可能需要多机共享、需要上云、需要更细权限的信号我会毫不犹豫上 MinIO。原因很简单对象存储的 S3 API 已经成了事实标准你早期在 MinIO 上写的那套存储抽象代码将来换到任何云厂商的对象存储服务改动成本都极低。这个抽象收益才是 MinIO 最大的价值不是那几块硬盘的可靠性。最后再分享一个小技巧不管选哪种方案记得在一开始就给存储层加个接口别把文件路径写死在业务代码里否则后面想切换你会恨不得把整个项目重写一遍。