4. MinIO 接口数据传输基础:PutObject / GetObject 接口详解、数据流与分块上传
本章是 MinIO 接口数据传输优化的基石。我们将深入剖析 PutObject 与 GetObject 两个核心接口的底层机制,对比 Streaming(数据流) 与 Multipart Upload(分块上传) 两种传输模式,为后续错误处理与中间件集成打下坚实的理论基础。
4.1 PutObject 接口:上传数据到 MinIO
PutObject 是向 MinIO 存储桶写入对象的标准接口。其核心参数包括:
| 参数 | 类型 | 说明 |
|---|---|---|
BucketName |
string | 目标存储桶名称 |
ObjectName |
string | 对象在桶中的键(Key) |
Reader |
io.Reader | 数据源,支持流式读取 |
ObjectSize |
int64 | 对象大小(-1 表示未知,用于流式上传) |
PutObjectOptions |
struct | 包含 Content-Type、元数据、进度回调等 |
关键点: 当
ObjectSize 设置为 -1 时,MinIO SDK 会自动启用 Streaming 模式,无需预先知道数据总长度。
4.1.1 标准 PutObject 示例(Go SDK)
// 标准上传:已知文件大小
file, err := os.Open("large-file.dat")
if err != nil {
log.Fatalln(err)
}
defer file.Close()
fileInfo, _ := file.Stat()
n, err := minioClient.PutObject(ctx, "my-bucket", "my-object",
file, fileInfo.Size(), minio.PutObjectOptions{
ContentType: "application/octet-stream",
})
if err != nil {
log.Fatalln(err)
}
log.Printf("上传成功,大小:%d 字节\n", n.Size)
4.2 GetObject 接口:从 MinIO 下载数据
GetObject 用于从存储桶中读取对象。它返回一个 io.ReadCloser,支持流式读取,非常适合大文件或实时处理场景。
| 参数 | 类型 | 说明 |
|---|---|---|
BucketName |
string | 存储桶名称 |
ObjectName |
string | 对象键 |
GetObjectOptions |
struct | 支持 Range 读取、版本 ID、SSE 等 |
4.2.1 流式读取 GetObject 示例
// 流式下载:边读边处理,无需加载到内存
object, err := minioClient.GetObject(ctx, "my-bucket", "my-object",
minio.GetObjectOptions{})
if err != nil {
log.Fatalln(err)
}
defer object.Close()
// 直接使用 io.Copy 写入本地文件
localFile, _ := os.Create("downloaded-file.dat")
defer localFile.Close()
written, err := io.Copy(localFile, object)
if err != nil {
log.Fatalln(err)
}
log.Printf("下载完成,大小:%d 字节\n", written)
最佳实践: 使用
GetObject 时,务必在读取完成后调用 Close(),否则会导致连接泄漏。推荐使用 defer object.Close() 确保资源释放。
4.3 数据流(Streaming)模式详解
Streaming 模式是 MinIO 接口的核心优化点之一。它允许数据以 分块传输编码(chunked transfer encoding) 的方式发送,无需在客户端或服务端缓冲整个对象。
- 优势: 内存占用低,支持无限大小对象,首字节延迟低。
- 适用场景: 实时日志上传、视频流、大文件备份、管道处理。
- 触发条件: PutObject 时
ObjectSize = -1,或使用PutObjectStreaming接口。
4.4 分块上传(Multipart Upload)详解
当对象大小超过 5 GiB 或网络不稳定时,推荐使用 Multipart Upload。它将大对象切分为多个 Part(每个 Part 5 MiB ~ 5 GiB),分别上传后再合并。
4.4.1 分块上传流程
- InitiateMultipartUpload:发起分块上传,获取 UploadID。
- UploadPart:按顺序上传每个 Part,记录 ETag。
- CompleteMultipartUpload:提交所有 Part,合并为完整对象。
- AbortMultipartUpload:取消未完成的上传,释放资源。
| 步骤 | API 名称 | 关键参数 | 说明 |
|---|---|---|---|
| 1 | NewMultipartUpload | Bucket, Object | 返回 UploadID |
| 2 | PutObjectPart | UploadID, PartNumber, Reader | 上传单个分片,返回 ETag |
| 3 | CompleteMultipartUpload | UploadID, Parts[] | 合并分片,生成最终对象 |
| 4 | AbortMultipartUpload | UploadID | 取消上传,清理临时分片 |
4.4.2 分块上传示例(Go SDK)
// 分块上传核心逻辑
uploadID, err := minioClient.NewMultipartUpload(ctx, "my-bucket", "large-object",
minio.PutObjectOptions{})
if err != nil {
log.Fatalln(err)
}
var parts []minio.CompletePart
for i := 1; i <= totalParts; i++ {
// 读取第 i 个分片
partData := readPart(i)
uploadInfo, err := minioClient.PutObjectPart(ctx, "my-bucket", "large-object",
uploadID, i, partData, partSize, minio.PutObjectPartOptions{})
if err != nil {
// 出错时中止上传
minioClient.AbortMultipartUpload(ctx, "my-bucket", "large-object", uploadID)
log.Fatalln(err)
}
parts = append(parts, minio.CompletePart{
PartNumber: i,
ETag: uploadInfo.ETag,
})
}
// 完成上传
_, err = minioClient.CompleteMultipartUpload(ctx, "my-bucket", "large-object",
uploadID, parts, minio.PutObjectOptions{})
if err != nil {
log.Fatalln(err)
}
注意: 分块上传的 Part 必须按顺序上传,但可以并发执行。并发上传时,需要确保 PartNumber 正确对应。推荐使用
errgroup 或 worker pool 控制并发度。
4.5 Streaming 与 Multipart Upload 对比
| 特性 | Streaming | Multipart Upload |
|---|---|---|
| 适用对象大小 | 任意大小(推荐 < 5 GiB) | > 5 MiB(推荐 > 5 GiB) |
| 是否需要预知大小 | 否 | 否(但需分片策略) |
| 内存占用 | 低(流式处理) | 中(需缓冲分片) |
| 并发上传 | 不支持 | 支持(多 Part 并发) |
| 断点续传 | 不支持 | 支持(可重试失败 Part) |
| 首字节延迟 | 低 | 高(需等待所有 Part 完成) |
| 典型场景 | 实时日志、视频流 | 大文件备份、数据迁移 |
选型建议: 对于小于 5 GiB 且网络稳定的场景,优先使用 Streaming 模式;对于大文件、弱网络或需要断点续传的场景,使用 Multipart Upload。实际生产环境中,两者可以结合使用:先尝试 Streaming,失败后自动降级为 Multipart Upload。
4.6 本章小结
- PutObject / GetObject 是 MinIO 数据传输的基础接口,支持流式读写。
- Streaming 模式 通过 chunked transfer encoding 实现低内存、低延迟传输。
- Multipart Upload 通过分片并发上传,解决大文件传输的可靠性和效率问题。
- 理解这两种模式的区别与适用场景,是后续实现错误处理、重试策略和中间件集成的前提。