Minio的元數據
數據存儲
MinIO對象存儲系統沒有元數據數據庫,所有的操作都是對象級別的粒度的,這種做法的優勢是:
-
個別對象的失效,不會溢出為更大級別的系統失效。
-
便於實現“強一致性”這個特性。此特性對於機器學習與大數據處理非常重要。
數據管理
元數據與數據一起存放在磁盤上:數據部分糾刪分片以后存儲在磁盤上,元數據以明文形式存放在元數據文件里(xl.json)。假定對象名字為obj-with-metadata, 它所在的桶的名字是bucket_name, disk是該對象所在糾刪組的任一個磁盤的路徑,如下目錄:
disk/bucket_name/obj-with-metadata
記錄了這個對象在此磁盤上的信息。其中的內容如下:
xl.json
xl.json即是此對象的元數據文件。對象的元數據文件xl.json的內容是如下這種形式的json字符串:
字段說明
format字段
該字段指明了這個對象的格式是xl,MinIO內部存儲數據主要有兩種數據格式:xl與fs。使用如下命令啟動的MinIO使用的存儲格式是fs:
這種模式主要用於測試, 對象存儲很多API都是並沒有真正實現的樁函數。在生產環境所用的部署方式(本地分布式集群部署、聯盟模式部署、雲網關模式部署)中,存儲格式都是xl。
part.1 :對象的第一個數據分片
stat字段
記錄了此對象的狀態,包括大小與修改時間,如下圖:
erasure字段
這個字段記錄此對象與糾刪碼有關的信息,如下圖:
其中的algorithm指明了此對象采用的是Klaus Post實現的糾刪碼,生成矩陣是范德蒙矩陣。
-
data,parity指明了糾刪組中數據盤、校驗盤的個數。
-
blockSize 指明了對象被分塊的大小,默認是5M(請參見上一節“數據分布與均衡”)。
-
index指明了當前磁盤在糾刪組中的序號。
-
distribution:每個糾刪組的數據盤、校驗盤的個數是固定的,但是不同的對象的分片寫入這個糾刪組的不同磁盤的順序是不同的。這里記錄了分布順序。
-
checksum:它下面的字段個數跟此對象的分片數量有關。在舊版本的MinIO對象存儲系統,每一個分片經過hash函數計算出的checksum會記錄在元數據文件的這個位置。最新版的MinIO會把checksum直接計入分片文件(即part.1等文件)的前32個字節。
此字段之下algorithm的值是”highwayhash256S”表明checksum值是寫入分片文件的。
Minio的整合Java客戶端
文件服務器在用minio,沒有獨立成微服務也沒有抽取starter,所以簡單測試一下集成和抽取starter,創建springboot項目集成minio把文件上傳成功
Maven環境的pom依賴
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>6.0.11</version>
</dependency>
spring的yml配置:
minio:
endpoint: http://192.168.8.50:9000
accessKey: admin
secretKey: 123123123
配置類 MinioProperties :
@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
//連接url
private String endpoint;
//用戶名
private String accessKey;
//密碼
private String secretKey;
}
工具類 MinioUtil
import cn.hutool.core.util.StrUtil;
import com.team.common.core.constant.enums.BaseResultEnum;
import com.team.common.core.exception.BusinessException;
import io.minio.MinioClient;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
@AllArgsConstructor
@Component
public class MinioUtil {
private final MinioClient minioClient;
private final MinioProperties minioProperties;
/**
* http文件上傳
* @param bucketName
* @param file
* @return 訪問地址
*/
public String putFile(String bucketName,MultipartFile file) {
return this.putFile(bucketName,null,file);
}
/**
* http文件上傳(增加根路徑)
* @param bucketName
* @param folder
* @param file
* @return 訪問地址
*/
public String putFile(String bucketName,String folder,MultipartFile file) {
String originalFilename = file.getOriginalFilename();
if (StrUtil.isNotEmpty(folder)){
originalFilename = folder.concat("/").concat(originalFilename);
}
try {
InputStream in = file.getInputStream();
String contentType= file.getContentType();
minioClient.putObject(bucketName,originalFilename,in,null, null, null, contentType);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException(BaseResultEnum.SYSTEM_EXCEPTION.getCode(),"文件上傳失敗");
}
String url = minioProperties.getEndpoint().concat("/").concat(bucketName).concat("/").concat(originalFilename);
return url;
}
/**
* 創建bucket
* @param bucketName
*/
public void createBucket(String bucketName){
try {
minioClient.makeBucket(bucketName);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException(BaseResultEnum.SYSTEM_EXCEPTION.getCode(),"創建bucket失敗");
}
}
@SneakyThrows
public String getBucketPolicy(String bucketName){
return minioClient.getBucketPolicy(bucketName);
}
}
裝配類:
import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioAutoConfiguration {
private final MinioProperties minioProperties;
@Bean
public MinioClient minioClient() throws InvalidPortException, InvalidEndpointException {
MinioClient client = new MinioClient(minioProperties.getEndpoint(),minioProperties.getAccessKey(),minioProperties.getSecretKey());
return client;
}
@ConditionalOnBean(MinioClient.class)
@Bean
public MinioUtil minioUtil(MinioClient minioClient,MinioProperties minioProperties) {
return new MinioUtil(minioClient,minioProperties);
}
}
spring.factories配置文件
去掉主入口函數,去掉application.properties配置文件(新建一個測試用的springboot項目,把配置文件拿過去)
剩下最重要的一步:在resources下創建META-INF/spring.factories文件,配置文件中加入需要自動裝配的類
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.*(你的路徑).MinioAutoConfiguration
demo:
import com.team.common.core.web.Result;
import com.team.common.minio.MinioUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@Api(value = "uploadFile", tags = "文件上傳")
@RequestMapping("uploadFile")
@RestController
public class UploadFileController {
@Autowired
private MinioUtil minioUtil;
@ApiOperation(value = "通用文件上傳")
@PutMapping("/upload")
public Result uploadFile(@ApiParam("存儲桶名稱") String bucketName,@ApiParam("文件") MultipartFile file) {
String url = null;
try {
url = minioUtil.putFile(bucketName,file);
} catch (Exception e) {
e.printStackTrace();
}
return Result.success(url);
}
}
打包安裝到maven倉庫,本地測試用的同一倉庫地址的話可以直接maven install,新建一個springboot項目,填入application.properties,pom中增加starter的依賴。
<dependency>
<groupId>com.jxwy</groupId>
<artifactId>minio-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
其他OSS服務對比
廠商支持
國內使用Ceph的廠商、基於Ceph進行自研的存儲廠商都比較多,在使用過程中遇到的問題(有些時候,甚至需要修改、增強乃至重新實現Ceph本身的功能),可以向相關廠商尋求支持。國際方面,Ceph早已被紅帽收購,而紅帽近期又被IBM收購。
MinIO開發與支持的廠商只有MinIO公司。由於架構比較先進,語言高級,MinIO本身的程序比較容易讀懂、修改。招聘Golang程序員來 維護MinIO所花費的成本,顯然低於招聘c++程序員來維護Ceph。
多語言客戶端SDK
二者均有常見編程語言的客戶端,比如:python, java等。MinIO對象存儲軟件的開發SDK另外支持純函數式的語言Haskell。
技術文檔
內部實現的文檔MinIO基本不存在。想要了解內部實現乃至參與開發的技術人員,只能到如下社區:http://minio.slack.com/ ,與MinIO的開發人員直接交流,或者自己閱讀代碼。Ceph的各種實現文檔、算法說明文檔非常豐富。這方面Ceph要比MinIO成熟很多。
Ceph和MinIO的對比
開源對象存儲軟件以MinIO,Ceph為典型代表。為幫助相關人員在選擇對象存儲系統之時選擇合適的產品,此處對二者的特點、特性做一定討論。
MinIO優勢
部署極其簡單
MinIO系統的服務程序僅有minio一個可執行文件,基本不依賴其它共享庫或者rpm/apt包。minio的配置項很少(大部分都是內核之類系統級的設置),甚至不配置也可以正常運行起來。百度、google、bing等搜索引擎上基本沒有關於MinIO部署問題的網頁,可見在實踐中,很少有使用者遇到這方面的問題。
相比之下,Ceph系統的模塊,相關的rpm、apt包眾多,配置項非常多,難以部署,難調優。某些Linux發行版的Ceph安裝包甚至有bug,需要使用者手動改動Ceph的python腳本,才能安裝完畢。
二次開發容易
MinIO對象存儲系統除了極少數代碼使用匯編實現以外,全部使用Golang語言實現。Ceph系統是使用業界聞名的難學難用的c++語言編寫的。Golang語言由於產生較晚,吸收了很多語言尤其是c++的教訓,語言特性比較現代化。
相對而言,MinIO系統的維護、二次開發比較容易。
網管模式支持多種其他存儲
通過網關模式,MinIO對象存儲后端,可以對接各種現有的常見其它存儲類型,比如的NAS系統,微軟Azure Blob 存儲、Google 雲存儲、HDFS、阿里巴巴OSS、亞馬遜S3等,非常有利於企業復用現有資源,有利於企業低成本(硬件成本約等於零,部署MinIO對象存儲軟件即可)地從現有系統平滑升級到對象存儲。
Ceph優勢
數據冗余策略更加豐富,Ceph同時支持副本、糾刪碼,而MinIO只支持糾刪碼。對於個別的對於數據可靠性要求極高的單位,Ceph對象存儲更加合適。
參考硬件
MinIO是符合軟件定義存儲SDS理念的,兼容主流X86服務器以及ARM/飛騰平台,同時也可以移植到諸如申威(Alpha架構)和龍芯(Mips架構)等硬件平台。
下面這些符合工業標准的、廣泛采用的服務器是經過MinIO inc.優化測試過的、MinIO對象存儲軟件表現優異的服務器:
結論
由以上討論,可見作為對象存儲軟件來說,MinIO, Ceph都非常優秀,各自有各自的優勢。准備使用對象存儲軟件的用戶,應該根據自己單位的需求、技術儲備等實際情況,選擇適當的軟件。
參考資料
-
https://github.com/krishnasrinivas/wikinotes/wiki/minio-scaling
-
https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/dev/Welcome.html
-
Klaus Post官網:https://klauspost.com/
-
https://min.io/resources/docs/MinIO-throughput-benchmarks-on-NVMe-SSD.pdf
-
https://github.com/minio/minio/blob/master/cmd/admin-heal-ops.go
-
https://github.com/klauspost/reedsolomon/blob/master/options.go
-
https://min.io/resources/docs/CPG-MinIO-implementation-guide.pdf
-
https://docs.min.io/docs/minio-bucket-notification-guide.html