浅谈minio关键流程

1.官方定义

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中存储的层级关系如下

  1. 0层:driver,即磁盘,具体体现就是一个目录
  2. 1层:erasure set:纠删集,多个driver组成的一组磁盘集,其中会存储原始数据切片+纠删码数据,存储规则如前介绍。erasure set在minio中以ErasureObject来表示。
  3. 2层:ErasureSets:多个erasure set组成的集合,或者说就是一个pool
  4. 3层:cluster:多个pool组成的集群/簇

而以上的存储结构最终是由ObjectLayer来体现的,minio通过ObjectLayer来操纵整个集群,比如关机、返回所有bucket信息、读写删除对象等等。
minio中创建ObjectLayer的代码位于erasure-server-pool.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中的规格与前一条启动命令相同。

下面是创建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关键流程_第1张图片
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/[email protected]

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 

你可能感兴趣的:(对象存储)