最近突然想搞一下对象存储,搜了搜发现博客上的都是旧写法,踩了好多坑,所以写了这篇博客。本人是菜鸟一个如果有错望指正。
- 1.分布式文件系统应用场景
- 1.1 Minio介绍(http://www.minio.org.cn/)
- 1.2 基础概念
- 1.3 纠删码EC(Erasure Code)
- 1.4 存储形式
- 1.5 存储方案
- 2. 环境搭建(单机部署)
- 3. java aip
- 版本查看
- 4. springBoot 整合
互联网海量非结构化数据的存储需求
- 电商网站:海量商品图片
- 视频网站:海量视频文件
- 网盘:海量文件
- 社交网站:海量图片
MinIO是一个基于Apache License v2.O开源协议的对象存储服务。它兼容亚马逊s3云存储服务接口,非常适合于存储大容量非结构化的
数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似NodeJS,Redis或者MySQL。
优点: 高性能,可扩展性,开放全部源代码 + 企业级支持,云的原生支持,与Amazon S3 兼容,简单
1.2 基础概念- Object:存储到Minio的基本对象,如文件、字节流,Anything
- Bucket:用来存储Object的逻辑空间。每个Bucket之间的数据是相互隔离的。对于客户端而言,就相当于一个存放文件的顶层文
件夹。
I - Drive:即存储数据的磁盘,在MinlO启动时,以参数的方式传入。Minio中所有的对象数据都会存储在Drive里。
- Set:即一组Drive的集合,分布式部署根据集群规模自动划分一个或多个Set,每个Set中的Drive分布在不同位置。一个对象存
储在-个Set上。(For example:{1.64}is divided into4 sets each of size16.)- 一个对象存储在一个Set上
- 一个集群划分为多个Set
- 一个Set包含的Drive数量是固定的,默认由系统根据集群规模自动计算得出
- 一个SET中的(Drive)尽可能分布在不同的节点上
MinIO使用纠删码机制来保证高可靠性,使用highwayhash来处理数据损坏(Bit Rot Protection)。关于纠删码,简单来说就是可以
通过数学计算,把丢失的数据进行还原,它可以将n份原始数据,增加m份数据,并能通过n+m份中的任意n份数据,还原为原始数据。
即如果有任意小于等于份的数据失效,仍然能通过剩下的数据还原出来。
文件对象上传到MilO,会在对应的数据存储磁盘中,以Bucket名称为目录,文件名称为下一级目录。
1.5 存储方案 2. 环境搭建(单机部署)学习:win https://dl.minio.io/server/minio/release/windows-amd64/minio.exe
- 启动 .minio.exe server D:.data
https://docs.min.io/docs/java-client-api-reference.html
- 依赖
io.minio minio 8.4.2 me.tongfei progressbar 0.9.3 com.squareup.okhttp3 okhttp junit junit 4.13.2
- 常用API
package com.wx;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import io.minio.messages.VersioningConfiguration;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@SpringBootTest
class SptingbootMinioApplicationTests {
private static MinioClient minioClient;
private static String bucketName = "text01";
private static String filePath = "E:\图\wallhaven-vmxxm8.jpg";
private static String endPoint = "http://192.168.2.248:9000 ";
private static String accessKey = "minioadmin";
private static String secretKey = "minioadmin";
//上传文件大小限制5M
private static long limitSize = 5242880L;
private void init() {
minioClient = MinioClient
.builder()
.endpoint(endPoint)
.credentials(accessKey, secretKey)
.build();
}
private void version() throws Exception {
init();
// Enable versioning on 'my-bucketname'.
minioClient.setBucketVersioning(
SetBucketVersioningArgs.builder()
.bucket(bucketName)
.config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null))
.build());
System.out.println("Bucket versioning is enabled successfully");
//
// // Suspend versioning on 'my-bucketname'.
// minioClient.setBucketVersioning(
// SetBucketVersioningArgs.builder()
// .bucket("my-bucketname")
// .config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null))
// .build());
// System.out.println("Bucket versioning is suspended successfully");
}
@Test
public void testCreateBucket() throws Exception {
init();
boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (isExist) {
System.out.println(bucketName + "已经存在!");
} else {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
System.out.println("创建了一个名字是" + bucketName + "的bucket");
}
}
@Test
public void testListBuckets() throws Exception {
init();
List bucketList = minioClient.listBuckets();
bucketList.forEach(p -> {
System.out.println(p.name());
});
}
@Test
public void testUploadFile() throws Exception {
init();
version();
for (int i = 0; i < 10; i++) {
minioClient.uploadObject(
UploadObjectArgs
.builder()
.bucket(bucketName)
.object("text.jpg")//上传的名
.filename(filePath)//本地磁盘地址
.build());
}
System.out.println("上传完毕,请刷新minio的web页面,查看上传文件");
}
@Test
public void testDownloadFile() throws Exception {
init();
minioClient.downloadObject(
DownloadObjectArgs
.builder()
.bucket(bucketName)
.object("text.jpg")//minio上的文件名
.filename("text.jpg")//下载的文件名
.build()
);
System.out.println("下载完毕");
}
@Test
public void testRemoveBucket() throws Exception {
init();
boolean isExist = minioClient.bucketExists(
BucketExistsArgs
.builder()
.bucket(bucketName)
.build()
);
if (isExist) {
//桶不空,删不掉,所以清桶的objects
Iterable> iterable = minioClient.listObjects(
ListObjectsArgs
.builder()
.bucket(bucketName)
.build()
);
for (Result- o : iterable) {
System.out.println("当前objectname---->>>>>>>" + o.get().objectName());
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(o.get().objectName())
.versionId(o.get().versionId())
.build());
System.out.println("清理---->>>>>>>" + o.get().objectName());
}
System.out.println("清理" + bucketName + "下的object完毕");
minioClient.removeBucket(
RemoveBucketArgs
.builder()
.bucket(bucketName)
.build()
);
if (!minioClient.bucketExists(
BucketExistsArgs.
builder()
.bucket(bucketName)
.build()
)) {
System.out.println("删除" + bucketName + "完毕,刷新minio的web页面");
}
} else {
System.out.println("没有这个bucket,无需操作");
}
}
}
版本查看
4. springBoot 整合
- 依赖
- 配置文件
server:
port: 8082
spring:
application:
name: minio
thymeleaf:
cache: false #关闭缓存
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100 MB
minio:
endpoint: http://192.168.2.248:9000
accesskey: minioadmin
secretKey: minioadmin
- 连接 MinIO 配置(实体类) 与公共返回类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@ConfigurationProperties(prefix = "minio")
@Component
public class MinioProp {
private String endpoint;
private String accesskey;
private String secretKey;
}
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Res implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code;
private Object data = "";
private String message = "";
}
- 创建 MinioClient
@Configuration
public class MinioConfiguration {
@Autowired
private MinioProp minioProp;
@Bean
public MinioClient minioClient() throws Exception {
MinioClient minioClient = MinioClient
.builder()
.endpoint(minioProp.getEndpoint())
.credentials(minioProp.getAccesskey(), minioProp.getSecretKey())
.build();
return minioClient;
}
}
- MinIO 查看桶列表,存入,删除 操作 MinioController
package com.wx.controller;
import com.alibaba.fastjson.JSON;
import com.wx.pojo.Res;
import io.minio.*;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;
@Slf4j
@RestController
public class MinioController {
@Autowired
private MinioClient minioClient;
private static final String MINIO_BUCKET = "text01";
@GetMapping("/list")
public List
- 路由文件 RouterController
@Controller
public class RouterController {
@GetMapping({"/", "https://blog.csdn.net/index.html"})
public String index() {
return "index";
}
@GetMapping({"/upload.html"})
public String upload() {
return "upload";
}
}
- 前端 列表页面 srcmainresourcestemplatesindex.html
图片列表
- 前端上传页面 srcmainresourcestemplatesupload.html
图片上传
选择图片
返回图片列表页面
- 测试
http://127.0.0.1:8082
#本人个人博客 https://www.wyxyg.top



