📍 导航:返回目录 | 上一节:RabbitMQ
高性能、S3兼容的对象存储系统
特点:
- 兼容AWS S3 API
- 支持分布式部署
- 开源免费
- Go语言编写
docker run -p 9000:9000 -p 9001:9001 \
-e "MINIO_ROOT_USER=minioadmin" \
-e "MINIO_ROOT_PASSWORD=minioadmin" \
minio/minio server /data --console-address ":9001"package main
import (
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"log"
)
func NewMinIOClient() (*minio.Client, error) {
return minio.New("localhost:9000", &minio.Options{
Creds: credentials.NewStaticV4("minioadmin", "minioadmin", ""),
Secure: false,
})
}func CreateBucket(client *minio.Client, bucketName string) error {
ctx := context.Background()
exists, err := client.BucketExists(ctx, bucketName)
if err != nil {
return err
}
if !exists {
err = client.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})
if err != nil {
return err
}
log.Printf("Bucket %s created", bucketName)
}
return nil
}func UploadFile(client *minio.Client, bucketName, objectName, filePath string) error {
ctx := context.Background()
info, err := client.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{
ContentType: "application/octet-stream",
})
if err != nil {
return err
}
log.Printf("Uploaded %s of size %d", objectName, info.Size)
return nil
}func DownloadFile(client *minio.Client, bucketName, objectName, savePath string) error {
ctx := context.Background()
return client.FGetObject(ctx, bucketName, objectName, savePath, minio.GetObjectOptions{})
}func GeneratePresignedURL(client *minio.Client, bucketName, objectName string, expiry time.Duration) (string, error) {
ctx := context.Background()
// 生成下载URL(有效期7天)
presignedURL, err := client.PresignedGetObject(ctx, bucketName, objectName, expiry, nil)
if err != nil {
return "", err
}
return presignedURL.String(), nil
}func UploadLargeFile(client *minio.Client, bucketName, objectName, filePath string) error {
ctx := context.Background()
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
fileStat, _ := file.Stat()
// 分片上传(自动处理)
_, err = client.PutObject(ctx, bucketName, objectName, file, fileStat.Size(), minio.PutObjectOptions{
ContentType: "application/octet-stream",
PartSize: 10 * 1024 * 1024, // 10MB分片
})
return err
}# 4节点集群
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=password
# 节点1
minio server http://node{1...4}/data{1...4}
# 自动实现:
# - 数据分片(Erasure Coding)
# - 高可用(N/2节点故障仍可用)
# - 负载均衡// 设置生命周期规则(30天后删除)
config := lifecycle.NewConfiguration()
config.Rules = []lifecycle.Rule{
{
ID: "expire-old-logs",
Status: "Enabled",
Expiration: lifecycle.Expiration{
Days: 30,
},
Filter: lifecycle.Filter{
Prefix: "logs/",
},
},
}
client.SetBucketLifecycle(ctx, bucketName, config)type ImageService struct {
minio *minio.Client
}
// 上传图片
func (is *ImageService) UploadImage(imageFile multipart.File, filename string) (string, error) {
ctx := context.Background()
// 生成唯一文件名
objectName := fmt.Sprintf("images/%s-%s", uuid.New().String(), filename)
// 上传
_, err := is.minio.PutObject(ctx, "my-bucket", objectName, imageFile, -1, minio.PutObjectOptions{
ContentType: "image/jpeg",
})
if err != nil {
return "", err
}
// 生成访问URL
url, _ := is.GenerateURL(objectName, 7*24*time.Hour)
return url, nil
}
// HTTP Handler
func (is *ImageService) HandleUpload(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("image")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
url, err := is.UploadImage(file, header.Filename)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(map[string]string{
"url": url,
})
}| 特性 | MinIO | 阿里云OSS | AWS S3 |
|---|---|---|---|
| 部署 | 自建 | 云服务 | 云服务 |
| 成本 | 低(硬件成本) | 按量计费 | 按量计费 |
| 可控性 | 高 | 低 | 低 |
| 运维 | 需要 | 无需 | 无需 |
| API | S3兼容 | 兼容S3 | 原生 |
关键要点:
- ✅ MinIO提供S3兼容的对象存储
- ✅ 适合存储图片、视频、文件
- ✅ 支持分布式部署
- ✅ 预签名URL实现安全访问
💡 思考题:
- 对象存储和文件存储的区别?
- 如何实现断点续传?
- 如何保证上传的安全性?
⏮️ 上一节:RabbitMQ |
⏏️ 返回目录