1.Erasure Set
An Erasure Set is a group of drives onto which MinIO writes erasure coded objects.
以上是minio官网对erasure set下的定义。首先,Erasure Set就是一组磁盘的指代,这一组磁盘用于存储minio对象及其纠删码,当然存储是随机且均匀的。比如如果这组Erasure Set的数量是12(最大是16,最小是2),那么一个object根据配置(Erasure Code Parity,EC:N,N是纠删码的数量),如果N是4,那么,原始的object会被分成8份(12-4),然后再计算出4份的纠删码,随机且均匀的存储到12(Erasure Set)个driver上。
2.存储层级关系及初始化流程
minio中存储的层级关系如下
- 0层:driver,即磁盘,具体体现就是一个目录
- 1层:erasure set:纠删集,多个driver组成的一组磁盘集,其中会存储原始数据切片+纠删码数据,存储规则如前介绍。erasure set在minio中以ErasureObject来表示。
- 2层:ErasureSets:多个erasure set组成的集合,或者说就是一个pool
- 3层:cluster:多个pool组成的集群/簇
而以上的存储结构最终是由ObjectLayer来体现的,minio通过ObjectLayer来操纵整个集群,比如关机、返回所有bucket信息、读写删除对象等等。
minio中创建ObjectLayer的代码位于server-main.go的go的newObjectLayer函数,该函数传入EndPointsServerPools,然后进行整个存储结构的构建。
EndPointsServerPools的结构是一个二维数组,其将所有的EndPoint分成多个Pool,每个Pool中又包含若干个EndPoint。EndPointServerPools系统初始化时,在server-main.go文件中通过createServerEndpoints函数创建。minio会根据传入参数的不同创建1~N个EndPointsServerPool(注意是Pool而不是Pools)。
如以下启动命令
minio server https://minio{1...4}.example.net/mnt/disk{1...4}
上述命令将会启动一个包含四节点,每个节点包含四个driver总共16个driver的server pool。如果系统设定的erasure set为8的话,那么这个16个driver会被重新划分为2个erasure sets,每个erasure set里面8个driver。
再比如以下启动命令
minio server https://minio{1...4}.example.net/mnt/disk{1...4} https://minio{5...8}.example.net/mnt/disk{1...4}
上述命令会启动包含两个pool,每个pool中的规格与前一条启动命令相同的cluster。
下面是创建EndPointsServerPools的调用栈
serverMain
serverHandleCmdArgs
createServerEndpoints
CreateEndpoints(参数无 ... 模式)
CreatePoolEndpoints(参数有 ... 模式)
再之后会通过EndPointServerPools创建ObjectLayer,创建ObjectLayer的过程是创建EndPointServerPools中的EndPoint对应的Client,并进行磁盘初始化,而磁盘初始化则是对齐一个Pool的磁盘中的索引、纠删码算法、部署类型等信息。一个Pool中的磁盘是由该Pool中第一个磁盘所在那个节点执行的(见prepare-storage.go的waitForFormatErasure函数)。
3 数据操作核心流程
3.1 Minio URL规范
在minio中主要涉及两类URL,分别是对内和对外,对内的接口用于Minio集群中各个节点之间进行信息交换,对外则是用户对整个Minio集群的操作。本章主要介绍对外的操作,在此之前,我们首先了解一下minio中如何注册http接口。minio的http服务器部分整体上沿用go的原生http库,minio在此基础上重写了请求路由。minio中http服务器整体结构如下所示
minio的Router实现了go的http.Handler接口,并使用Router替换http.Server默认的httpMux,以实现minio自身的路由算法。
minio在注册http handler时比较灵活且简洁,以下是注册一个http handler的示例
// 创建一个路由,mux库在minio中是公开的,我们可以直接
// 在自己的项目中import使用
router := mux.NewRouter()
// 表示/helloMinio这个URI 使用handler函数来处理
router.Path("/helloMinio").HandleFunc(handler)
// 表示对http 的method进行匹配, “.(...)”是省略写法,以下均用此种写法代替完成写法
router.Methods("Post").(...)
// 表示匹配以 “/” 为前缀的URI
router.PathPrefix("/”)
// 此外对于一部分重复度较高的路由,还可以使用子路由来表示,比如
subRouter := router.PathPrefix("/api/v1").subRouter()
更多使用可以参见minio的mux库,https://pkg.go.dev/github.com/minio/mux@v1.9.0
Minio在api-router.go中的registerAPIRouter函数注册S3兼容的接口,其接口定义规则如下
basePrefix = "/{bucket:.+}.{globalDomainNames...}"
备注:{bucket:.+}的含义是匹配 “:” 后面的模式即 “.+”,至于:前的bucket此处只起到备注作用
1.object相关的api
"/{object:.+}"
2.bucket相关的api
直接使用basePrefix
其他类型的API不再列举
3.2 上传Object流程
代码位于cmd/erasure-server-pool.go, PutObject函数
1. 选择pool
1.1 如果只有一个pool,直接调用pool(erasureSets)的PutObject函数,将该对象存入pool中
1.2 如果不止一个pool
1.2.1 检查上传的对象是否在于某个pool中(即便该对象的之前最新的版本显示它被删除,也返回对应的pool index),如果存在的话,返回这个pool index
1.2.2 如果待上传的对象在任何一个pool中都不存在的话,从所有的pool中选择能承载该对象大小的pool集合,并且过滤掉剩余空间不足15%的pool,之后minio使用一个hash算法选取最终的pool,选取的策略在erasure-server-pool.go的getAvailablePoolIdx中,该策略更容易选择大容量的pool。
2. 选择pool中的set
2.1 会根据object name作为输入,并用hash算法决定选择哪个set,此处有两种hash算法,分别是crcHash和sipHash
3. 上传对象
3.1 确定纠删盘和数据盘的数量(纠删盘最大不超过一个纠删集硬盘数量的一半,数据盘最小要比纠删盘大1,并且需要保证一个纠删集中故障盘数量不能超过一半,)
3.2 将数据分片与所存储的磁盘进行shuffle(数据分片随机存储到一个纠删集的磁盘中)
3.3
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。