文章目录
- [一、MinIO 简介](#一、MinIO 简介)
- [二、MinIO 的核心特点](#二、MinIO 的核心特点)
- [三、Docker 安装 MinIO](#三、Docker 安装 MinIO)
- 四、时间同步问题
- [五、Spring Boot 文件上传到 MinIO](#五、Spring Boot 文件上传到 MinIO)
- 六、总结
一、MinIO 简介
MinIO 是一个基于 Apache License v3.0 的开源对象存储服务,兼容 Amazon S3 API ,非常适合存储大规模 非结构化数据,例如:
- 图片
- 视频
- 日志文件
- 备份数据
- 容器 / 虚拟机镜像
单个对象大小可从 KB 级别到最大 5TB。
与传统的存储服务相比,MinIO 非常 轻量级 ,可以像 Redis、MySQL、Node.js 一样轻松集成到各种系统中。
👉 官方文档(英文):
https://docs.min.io/
二、MinIO 的核心特点
1. 高性能
在标准硬件环境下,MinIO 可达到:
- 55 GB/s 读取速度
- 35 GB/s 写入速度
非常适合高并发、大文件读写场景。
2. 高可扩展
- 支持多个 MinIO 集群组成 联邦
- 形成 全局命名空间
- 支持跨数据中心部署
3. 云原生
- 支持容器化部署
- 可运行在 Kubernetes
- 支持多租户
4. 完全兼容 Amazon S3
-
支持 S3 v2 / v4 API
-
可直接使用:
- MinIO SDK
- AWS SDK
- AWS CLI
5. 多种后端存储
- 本地文件系统
- DAS / JBOD
- NAS
- Google Cloud Storage
- Azure Blob Storage
6. SDK 与生态完善
支持多种语言 SDK:
- Java
- Python
- Go 等
7. 事件与 Lambda 计算
支持通过 事件通知 触发 Lambda,兼容 AWS SNS / SQS,可对接:
- Kafka
- Redis
- MySQL
- Elasticsearch
- WebHook 等
8. 纠删码机制(Erasure Code)
MinIO 使用 纠删码 + 校验和:
即使丢失 一半磁盘(N/2),仍然可以恢复数据
这是基于数学算法的数据容错机制,极大提高了数据安全性。
三、Docker 安装 MinIO
1. 拉取镜像
bash
docker pull minio/minio
2. 启动容器
bash
docker run \
-p 9000:9000 \
-p 9001:9001 \
--name minio \
-d --restart=always \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=admin123456" \
-v /home/data:/data \
-v /home/config:/root/.minio \
minio/minio server /data --console-address ":9001"
3. 访问控制台
浏览器访问:
http://IP:9001/minio/login
登录账号:
- 用户名:
admin - 密码:
admin123456
四、时间同步问题
在上传文件时,如果 Linux 服务器时间与 Windows 时间不一致,可能会导致 MinIO 访问异常。
使用 NTP 同步时间
bash
# 1. 安装 ntp
yum -y install ntp
# 2. 设置开机启动
systemctl enable ntpd
# 3. 启动服务
systemctl start ntpd
# 4. 设置时区
timedatectl set-timezone Asia/Shanghai
# 5. 启用 NTP
timedatectl set-ntp yes
# 6. 查看同步状态
ntpq -p
五、Spring Boot 文件上传到 MinIO
1. 控制器(Controller)
java
package com.donglin.file.controller;
import com.donglin.file.entity.BucketType;
import com.donglin.file.service.FileUploadService;
import com.donglin.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class FileController {
@Autowired
private FileUploadService fileUploadService;
@PostMapping("/upload/public")
public String uploadPublic(@RequestParam MultipartFile file) {
return fileUploadService.upload(file, BucketType.PUBLIC);
}
@PostMapping("/upload/private")
public String uploadPrivate(@RequestParam MultipartFile file) {
return fileUploadService.upload(file, BucketType.PRIVATE);
}
}
2. Service 接口
java
package com.donglin.file.service;
import com.donglin.file.entity.BucketType;
import org.springframework.web.multipart.MultipartFile;
public interface FileUploadService {
String upload(MultipartFile file, BucketType aPrivate);
}
3. Service 实现类
java
package com.donglin.file.service.impl;
import com.donglin.file.entity.BucketType;
import com.donglin.file.entity.MinioConstantProperties;
import com.donglin.file.service.FileUploadService;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.UUID;
@Service
public class FileUploadServiceImol implements FileUploadService {
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConstantProperties prop;
@Override
public String upload(MultipartFile file, BucketType bucketType) {
try {
// 1. 选择 bucket
String bucket = bucketType == BucketType.PUBLIC
? prop.getPublicBucket()
: prop.getPrivateBucket();
// 2. 文件后缀
String ext = FilenameUtils.getExtension(file.getOriginalFilename());
// 3. 对象名(分目录)
String objectName = String.format(
"%s/%s/%s.%s",
bucketType.name().toLowerCase(),
java.time.LocalDate.now(),
UUID.randomUUID().toString().replace("-", ""),
ext
);
// 4. 上传
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucket)
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build()
);
// 5. public:返回直链
if (bucketType == BucketType.PUBLIC) {
return prop.getEndpointUrl()
+ "/" + bucket
+ "/" + objectName;
}
// 6. private:返回预签名 URL
return minioClient.getPresignedObjectUrl(
io.minio.GetPresignedObjectUrlArgs.builder()
.method(io.minio.http.Method.GET)
.bucket(bucket)
.object(objectName)
.expiry(1 * 60)
.build()
);
} catch (Exception e) {
throw new RuntimeException("文件上传失败", e);
}
}
}
4. MinIO 配置类
java
package com.donglin.file.entity;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioConstantProperties {
// MinIO 服务地址
private String endpointUrl;
// AccessKey
private String accessKey;
// SecretKey
private String secretKey;
// Bucket 名称
private String bucketName;
// public / private bucket
private String publicBucket;
private String privateBucket;
}
csharp
package com.donglin.file.entity;
public enum BucketType {
PUBLIC,
PRIVATE
}
config配置类
csharp
package com.donglin.file.config;
import com.donglin.file.entity.MinioConstantProperties;
import io.minio.MinioClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MinioConfig {
@Bean
public MinioClient minioClient(MinioConstantProperties prop) {
return MinioClient.builder()
.endpoint(prop.getEndpointUrl())
.credentials(prop.getAccessKey(), prop.getSecretKey())
.build();
}
}
yml
csharp
minio:
endpoint-url: http://192.168.121.140:9000
access-key: admin
secret-key: admin123456
public-bucket: sky-public
private-bucket: sky-private
server:
port: 9600
把sky-public设置成public公有

结果
公共存储,一直能看
私有存储,目前设置的只能看1分钟

六、总结
-
MinIO 是一个 高性能、轻量级、S3 兼容 的对象存储服务
-
非常适合:
- 微服务项目
- 图片 / 音视频存储
- 日志与备份系统
-
使用 Docker + Spring Boot 可快速落地
-
注意 服务器时间同步,否则容易踩坑