What’s MinIO?
MinIO 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb 到最大 5T 不等。
MinIO Quick Guide
MinIO 对不同的操作系统都有支持,这里主要介绍 Linux 下 Docker 版的 MinIO 。
Install
下载 MinIO 的 Docker 镜像非常简单,只需要运行
|
|
即可。
Run
简单测试 MinIO 只需要运行
|
|
即可。
可以看到运行以后 MinIO 给出了两个端口,一个是 API 端口 9000
,一个是 Console 端口 38417
。这里的 API 端口指的是直接对 MinIO 进行操作的端口,而 Console 则是一个控制台 UI 。如果不进行指定,每次运行时 API 端口将默认为 9000
,而 Console 端口则会随机分配。为了实现稳定的端口服务,可以通过 --console-address ":xxxx"
指定 Console 端口,例如:
此时访问 127.0.0.1:9001
即可打开控制台。
在不设置账号密码的情况下,默认的账号密码均为 minioadmin
。登录后的界面如图,可以点击 Create Bucket 创建一个 Bucket (类似一个分类),然后在 Bucket 中进行文件的上传、下载等操作。
由于在启动 Docker 时, /data
这个目录创建在容器的文件系统中,因此所有的数据会在容器退出时消失。所以如果要创建一个永久存储的 MinIO 容器,需要使用 Docker 的 -v
参数将本机的目录挂在到容器的文件系统中。如:
|
|
要覆盖默认的密钥 minioadmin
,可以通过设置 MINIO_ACCESS_KEY
和 MINIO_SECRET_KEY
环境变量的方式 ,如:
|
|
Distributed Deployment
MinIO 支持分布式部署,避免出现单点故障导致整体宕机,同时利用纠错码来防范多个节点宕机和位衰减。分布式 MinIO 的部署需要至少 4 个硬盘,当然这些硬盘可以自由组合不同的节点和每个节点几块硬盘,例如对于 8 块硬盘的分布式部署,可以使用 2 个节点,每个节点 4 块硬盘,也可以使用 4 个节点,每个节点 2 块硬盘,诸如此类。
分布式 MinIO 的部署非常简单,只需要把硬盘位置作为参数传给 MinIO server 即可,即
|
|
需要注意的是:
- 分布式 MinIO 需要所有节点有同样的 Access Key 和 Secret Key ,这样这些节点才能建立连接。
- 分布式 MinIO 使用的磁盘必须是空磁盘。
- 分布式 MinIO 的节点时间差不能超过 3 秒,可以通过 NTP 来保证时间一致。
Storage
MinIO 最基本的存储结构是 /data_folder/bucket/file/meta_file
,其中 data_folder
是启动 MinIO 时指定的文件目录, bucket
是以创建的桶的名称命名的文件目录,file
是以存储的文件的名称命名的文件目录,meta_file
则是元文件信息。
如图是在 MinIO 中创建 document 桶,并向其中上传 hello.txt 文件后的目录结构。
Erasure Code
Principle
MinIO 使用纠错码 (Erasure Code) 来对数据进行保护,防止因硬盘故障等原因导致数据损失。通过使用纠错码,即使丢失了一半数量的硬盘,也可以恢复数据。
具体来讲,MinIO 使用的是 Reed-Solomon Code 算法来进行纠错码保护。RS code 的编码解码定义如下:
- 编码:给定 $n$ 个数据块 $D_1, D_2, D_3, …$ ,和一个正整数 $m$ ,RS 根据 $n$ 个数据块生成 $m$ 个编码块 $C_1, C_2, C_3, …$ 。
- 解码:对于任意的 $m$ 和 $n$ ,从 $n$ 个原始数据块和 $m$ 个编码块中任意取出 $n$ 个块就能解码出原始数据。即 RS code 最多能容忍 $m$ 个数据块或编码块同时丢失。
RS Code 对文件数据进行编码的具体过程如下:
-
将数据块拆分到字长为 $w$ (取值一般为 $8b$ 或 $16b$) 的 word ,称为 $D_1, D_2, D_3, …$ 。
-
将输入数据块视为向量,即 $$ D = \left[ \begin{matrix} D_1 \\ D_2 \\ D_3 \\ … \\ D_n \end{matrix} \right] $$
-
生成编码矩阵,编码矩阵需满足其任意的 $n \times n $ 子矩阵均可逆。为了方便,常用的编码矩阵形式为:
- 上部的 $n \times n$ 子矩阵为 $n$ 阶单位矩阵
- 下部的 $m \times n$ 子矩阵为范德蒙德矩阵或柯西矩阵。
即如下形式: $$ B = \left[ \begin{matrix} 1 & 0 & 0 & \cdots & 0 \\ 0 & 1 & 0 & \cdots & 0 \\ 0 & 0 & 1 & \cdots& 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 1 \\ B_{11} & B_{12} & B_{13} & \cdots &B_{1n} \\ B_{21} & B_{22} & B_{23} & \cdots &B_{2n} \\ \vdots & \vdots & \vdots & \ddots & \vdots\\ B_{m1} & B_{m2} & B_{m3} & \cdots &B_{mn} \\ \end{matrix} \right] $$
4.用编码矩阵和输入数据矩阵进行如下运算: $$ B \times D = \left[ \begin{matrix} D_1 \\ D_2 \\ D_3 \\ \vdots \\ D_n \\ C_1 \\ C_2 \\ \vdots \\ C_m \end{matrix} \right] $$ 即: $$ \left[ \begin{matrix} 1 & 0 & 0 & \cdots & 0 \\ 0 & 1 & 0 & \cdots & 0 \\ 0 & 0 & 1 & \cdots& 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 1 \\ B_{11} & B_{12} & B_{13} & \cdots &B_{1n} \\ B_{21} & B_{22} & B_{23} & \cdots &B_{2n} \\ \vdots & \vdots & \vdots & \ddots & \vdots\\ B_{m1} & B_{m2} & B_{m3} & \cdots &B_{mn} \\ \end{matrix} \right] \times \left[ \begin{matrix} D_1 \\ D_2 \\ D_3 \\ \cdots \\ D_n \\ \end{matrix} \right] = \left[ \begin{matrix} D_1 \\ D_2 \\ D_3 \\ \vdots \\ D_n \\ C_1 \\ C_2 \\ \vdots \\ C_m \end{matrix} \right] $$ 这样便得到了 $n$ 个数据块和 $m$ 个编码块。
RS Code 进行数据恢复利用的是 $B$ 矩阵的可逆性,具体而言,RS Code 对丢失数据进行恢复的过程如下:
-
假设编码结果矩阵中丢失的信息为第 $a_1, a_2, …, a_k$ 行,在 B 中将对应的行删去,得到一个新的矩阵 $B’$ 。
-
由编码计算式,可得 $$ B’ \times D = Survivors $$
-
由于 $B$ 是可逆的,故 $B’$ 也是可逆的,对 2 中的等式左右两边同时左乘 $B’^{-1}$ ,可得 $$ B’^{-1} \times B’ \times D = B’^{-1} \times Survivors $$ 即 $$ D = B’^{-1} \times Survivors $$
由此可以对原数据块进行恢复。
Usage
在 MinIO 中启用纠错码很简单,只需要在启动时指定多块硬盘,开启分布式部署,即可自动启用纠错码。例如,用如下命令启动 MinIO
|
|
就可以成功开启一个带有纠错码的分布式 MinIO 。
从 Status 中可以看到多块硬盘的状态。
创建 document 桶并上传 hello.txt 文件后,可以查看多块硬盘内的文件结构:
这四个元文件就是经过 RS Code 加密后的数据块和编码块文件。
Object Management
Bucket Versioning
创建 bucket 时可以选择开启 Versioning ,即在一个 bucket 内保存同一个文件的多个版本。开启 Versioning 后,对文件的覆盖操作会变成对象新版本的创建。如图为开启了 Versioning 的 bucket,可以看到在上传了两份 main.go 后,在其 Versions 中出现了 v1
和 v2
两个版本。
而在开启 Versioning 后,对文件的删除操作将会为其创建一个 0-byte 的新版本 DeleteMarker
作为最新版本。 DeleteMarker
不会作为获取操作(包括 Get, List 等)的返回结果。如图,在删除 main.go 文件并再次上传后,查看版本可以看到 v1
, v2
仍然存在,且在最新的 v4
和 v2
之间出现了一个 0-byte 的 v3
,且有标记 DELETED
,这个就是删除操作创建的 DeleteMarker
。
想要永久删除对象,在此交互界面可以选中删除的版本点击 Delete Version 删除特定版本,或选择 Delete Non-Current Versions 删除所有版本非最新版本,通过 MinIO 客户端则可以指定需要删除的版本 ID。
Object Locking
在开启了 Versioning 后,可以选择开启 Object Locking 来保证多版本文件的 Write-Once Read-Many(WORM) 不变性,也就是不能删除。
这里的不能删除指的是不能对文件进行彻底的删除,也即指定版本的删除方式;而对于删除文件,即打删除标记的删除方式,由于这种方式的本质是创建一个新的版本,因此 Object Locking 并不阻止。
当删除版本时,可以看到提示文件被 WORM 保护不能删除。
而当删除文件时,可以看到删除标记被正常打上了。
Quota
开启 Quota 后可以限制 bucket 中上传的文件数量。
MinIO Golang Client SDK
MinIO 为主流的 Web 开发语言提供了 SDK ,通过这套 SDK 可以简单的实现一个对象存储客户端。
Download
|
|
Quick Start
初始化一个 Minio Client 需要调用 minio-go 包中的 New 方法,这个方法需要接收四个参数:
参数 | 类型 | 描述 |
---|---|---|
endpoint | string | 对象存储服务的URL |
opts | minio.Options | 创建一个客户端实例所需的配置 |
其中,minio.Options 类型包含以下字段:
字段 | 类型 | 描述 |
---|---|---|
Creds | *credentials.Credentials | 对象存储服务的访问凭据 |
Secure | bool | 是否开启 HTTPS |
Transport | http.RoundTripper | 用于执行 HTTP 事务的自定义传输(机翻,这块还不太懂,先挖坑qwq) |
Region | string | 存储桶所在地区(可在创建时选择) |
BucketLookup | BucketLookupType | 可选值为:- minio.BucketLookupDNS- minio.BucketLookupPath- minio.BucketLookupAuto表示服务器是否支持 DNS 或 路径样式 URL 请求。默认为 Auto ,会自动选择。 |
对 credentials.Credentials 的具体解释将在后文展开,这里将仅仅简单给出一个快速上手的例子。
|
|
这里使用的是运行在 https://play.min.io
上的 MinIO 服务,在测试中可以使用这个服务。示例中的访问凭据是公开的。如此,即可创建一个 MinIO 服务端,并通过这个服务端,在 MinIO 服务器上进行上传下载文件等操作。
Structs About Initialization
前文提到的 credentials.Credentials 结构体所含字段如下:
字段 | 类型 | 描述 |
---|---|---|
creds | credentials.Value | 凭据信息 |
forceRefresh | bool | 下一次 Get() 操作是否强制刷新 |
provider | credentials.Provider | 凭据信息提供接口 |
其中的 credentials.Value 和 credentials.Provider 类型分别为:
-
credentials.Value:
一个结构体,包含以下字段:
字段 | 类型 | 描述 |
---|---|---|
AccessKeyID | string | MinIO AccessKeyID |
SecretAccessKey | string | MinIO Secret Access Key |
SessionToken | string | MinIO 服务 session token |
SignerType | SignatureType | 签名类型 |
-
credentials.Provider:
一个接口,包含以下两个无参方法:
方法 返回值 描述 Retrieve() (value, error) 获取凭据 IsExpired() bool 凭据是否过期
这一套结构和接口的逻辑是, credentials.Value 存储访问 MinIO 服务的凭据信息,而 MinIO 服务的 AccessKeyID 和 SecretAccessKey token 可能会有修改,有一个过期信息。于是就有了 credentials.Provider 接口,提供检查凭据是否过期的 IsExpired 方法和获取凭据的 Retrieve 方法。那么这里 forceRefresh 的作用是什么呢?我们已知 provider.IsExpired() 会检查访问凭据是否过期,那如果在没有过期的情况下想要强制刷新一下 credentials.Value 信息,就可以通过设置 forceRefresh 字段为 true
,然后调用 Credentials.Get() 方法便可以刷新凭据。
在 Quick Start
部分中,可以看到创建 MinIO 客户端实例的时候 Creds 字段用到了 NewStaticV4 方法,这里实际上是用到了 SDK 中的另一个类型 Static 。 Static 类型是对 Value 类型的封装,或者说,是不会过期的凭据。因此,对于凭证不会改变的 MinIO 服务,只需要传递一次 AccessKeyID 和 SecretAccessKey 即可,且也不需要提供 provider 。
Bucket API
对 Bucket 进行操作的 API 主要有 Bucket 的创建查找删除, Bucket 内文件的查找, Bucket 标签的设置等。这里对一些有代表意义的结构体和 API 进行说明,更多详细信息可见参考文档中的 MinIO Golang SDK 官方文档。
MakeBucket(ctx context.Context, bucketName string, opts MakeBucketOptions)
创建一个 bucket 。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 bucketName string bucket 名称 opts minio.MakeBucketOptions bucket 属性 其中 minio.MakeBucketOptions 包含两个字段
字段 类型 描述 Region string bucket 位置,包含 us-east-1
,eu-west-1
等ObjectLocking bool 是否开启 Object Locking -
返回值:
类型 描述 error 错误信息
示例:
|
|
ListBuckets(ctx context.Context) ([]BucketInfo, error)
列举所有 bucket 。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 -
返回值:
类型 描述 []minio.BucketInfo 所有的 bucket 信息 error 错误信息 其中 minio.BucketInfo 包含以下两个字段
字段 类型 描述 Name string bucket 名称 CreationDate time.Time bucket 创建时间
示例:
|
|
ListObjects(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo
列举 bucket 中的所有文件。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 bucketName string bucket 名称 opts minio.ListObjectsOptions 列举文件配置 其中 minio.ListObjectsOptions 包含以下字段:
字段 类型 描述 WithVersions bool 在列举中包含文件版本 WithMetadata bool 在列举中包含文件元文件信息 Prefix string 只列举此前缀的文件 Recursive bool 是否递归查找 MaxKeys int 单批请求的最大对象数量,大多数情况下无用 StartAfter string 只列举文件名字典序在此之后的文件 -
返回值:
类型 描述 chan minio.ObjectInfo 一个 channel ,用于读取所有文件信息 其中 minio.ObjectInfo 包含以下字段(由于完整的结构体较为复杂且有些内容暂时还不太懂,表格中只列举一些比较重要的字段,完整的结构体定义就简单贴在下面):
字段 类型 描述 ETag string 文件的 md5sum 编码 Key string 文件名 LastModified time.Time 最近修改时间 Size int64 文件大小(单位:Byte) ContentType string 文件类型 Expires time.Time 文件过期时间 MetaData http.Header 文件元文件信息 IsLatest bool 是否是最新版 IsDeleteMarker bool 是否是删除标记 VersionID string 版本号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
type ObjectInfo struct { // An ETag is optionally set to md5sum of an object. In case of multipart objects, // ETag is of the form MD5SUM-N where MD5SUM is md5sum of all individual md5sums of // each parts concatenated into one string. ETag string `json:"etag"` Key string `json:"name"` // Name of the object LastModified time.Time `json:"lastModified"` // Date and time the object was last modified. Size int64 `json:"size"` // Size in bytes of the object. ContentType string `json:"contentType"` // A standard MIME type describing the format of the object data. Expires time.Time `json:"expires"` // The date and time at which the object is no longer able to be cached. // Collection of additional metadata on the object. // eg: x-amz-meta-*, content-encoding etc. Metadata http.Header `json:"metadata" xml:"-"` // x-amz-meta-* headers stripped "x-amz-meta-" prefix containing the first value. UserMetadata StringMap `json:"userMetadata,omitempty"` // x-amz-tagging values in their k/v values. UserTags map[string]string `json:"userTags"` // x-amz-tagging-count value UserTagCount int // Owner name. Owner Owner // ACL grant. Grant []Grant // The class of storage used to store the object. StorageClass string `json:"storageClass"` // Versioning related information IsLatest bool IsDeleteMarker bool VersionID string `xml:"VersionId"` // x-amz-replication-status value is either in one of the following states // - COMPLETED // - PENDING // - FAILED // - REPLICA (on the destination) ReplicationStatus string `xml:"ReplicationStatus"` // set to true if delete marker has backing object version on target, and eligible to replicate ReplicationReady bool // Lifecycle expiry-date and ruleID associated with the expiry // not to be confused with `Expires` HTTP header. Expiration time.Time ExpirationRuleID string Restore *RestoreInfo // Checksum values ChecksumCRC32 string ChecksumCRC32C string ChecksumSHA1 string ChecksumSHA256 string // Error Err error `json:"-"` }
示例:
|
|
Object API
GetObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error)
获取一个文件并返回文件流。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 bucketName string bucket 名称 objectName string 文件名称 opts minio.GetObjectOptions 获取文件设置 其中 minio.GetObjectOptions 包含以下字段:
字段 类型 描述 ServerSideEncryption encrypt.ServerSide 服务端的加密类型 VersionID string 版本 ID PartNumber int 分块数(没找到关于这个的描述qwq) Checksum bool 包含 checksums Internal AdvancedGetOptions 高级设置 -
返回值:
类型 描述 *minio.Object 包含文件信息,实现了 io.Reader,io.Seeker ,io.ReaderAt 和 io.Closer。 error 错误信息
示例:
|
|
FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error
与 GetObject 方法非常类似,区别在于 GetObject 返回数据流,而 FGetObject 直接将文件保存到本地。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 bucketName string bucket 名 objectName string 文件名 filePath string 本地保存路径 opts minio.GetObjectOptions 获取文件设置 -
返回值:
类型 描述 error 错误信息
示例:
|
|
Bucket Policy API
这一部分主要设计 bucket policy 的设置,包括 object lock, life cycle, versioning 等。
SetBucketLifecycle(ctx context.Context, bucketname, config *lifecycle.Configuration) error
设置 Bucket life cycle 政策,即 bucket 中文件的过期失效规则。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 bucketName string bucket 名称 config lifecycle.Configuration life cycle 配置 其中 lyfecycle.Configuration 含以下关键字段:
字段 类型 描述 Rules []lifecycle.Rule 策略信息 而 lifecycle.Rule 中包含以下关键字段:
字段 类型 描述 ID string 策略名 Expiration lifecycle.Expiration 策略信息 lifecycle.Expiration 中包含以下关键字段:
字段 类型 描述 Date lifecycle.ExpirationDate(time.Time) 过期日期 Days lifecycle.ExpirationDays(int) 过期时长 -
返回值:
类型 描述 error 错误信息
示例:
|
|
SetObjectLockConfig(ctx context.Context, bucketname, mode *RetentionMode, validity *uint, unit *ValidityUnit) error
用于设置 bucket object locking 信息。
-
参数:
参数 类型 描述 ctx context.Context 自定义上下文来设置超时时间等 bucketName string bucket 名称 mode minio.RetentionMode retention mode ,可选值包含 minio.Governance 和 minio.Compliance ,两者分别表示管理员可修改与管理员不可修改 validity uint locking 时长 unit ValidityUnit locking 时长单位,可选值包含 minio.Days 和 minio.Years -
返回值:
类型 描述 error 错误信息
示例:
|
|