• MinIO的基础概念和用法大全


    MinIO说明

    MinIO是一款高性能、分布式的开源对象存储系统, 它是一款软件产品。 MinIO公司旨在解决非结构化数据增长的需求, 开发了流行于业界的开源云存储软件MinIO。
    虽然MinIO是100%开源的, 但它既是一家公司又是一个开源项目。它采用GNU AGPL v3开源证书, 拥有GNU AGPL代码的版权, 同时还是MinIO项目的主要贡献者, 可独立对MinIO进行维护。

    MinIO特点

    1.分布式对象存储: MinIO 是一个高度可扩展的对象存储系统, 旨在存储大规模的非结构化数据, 如图像、视频、文档等。它将数据以对象的形式存储在分布式集群中。
    2.高度可扩展: MinIO 可以轻松地扩展以适应不断增长的存储需求。您可以通过添加新的存储节点来增加存储容量和性能, 从而实现横向扩展。
    3.高性能: MinIO 针对读取和写入对象进行了优化,具有出色的性能。它采用并发处理和多线程等技术来提高吞吐量, 使其非常适合需要快速存取大量对象的应用。
    4.S3兼容: MinIO 提供了与 Amazon S3 兼容的 API, 这意味着您可以使用现有的 S3 客户端和工具来与 MinIO 进行交互。这种兼容性使得迁移现有 S3 数据和应用程序变得容易。
    5.安全性: MinIO 提供了多种安全性功能, 包括数据加密、访问控制列表 (ACLs)、策略管理和身份验证, 以确保存储的数据得到保护。
    6.开源和免费: MinIO 是开源软件, 根据Apache License 2.0许可证发布, 可以免费使用和修改。

    MinIO和常规数据库的区别

    1.数据类型: MinIO 主要用于存储非结构化数据, 如文件、图片和视频等二进制数据。关系型数据库, 用于存储结构化数据, 例如表格数据。
    2.数据模型: MinIO 使用对象存储模型, 将数据存储为对象, 每个对象可以包含元数据和二进制数据。关系型数据库使用表格模型, 数据以表格的形式进行组织。
    3.用途: MinIO 通常用于存储大规模的文件和媒体数据, 用于构建数据湖、媒体存储、备份和归档等场景。关系型数据库主要用于事务性应用程序, 如电子商务、金融系统和业务应用的数据存储。
    4.性能和扩展性: MinIO 针对大规模对象存储进行了优化, 支持高并发和横向扩展。MySQL 针对事务性操作进行了优化, 不同于对象存储的性能和扩展性需求。

    MinIO中的基本概念

    Object: 存储到 Minio 的基本对象, 如文件、字节流, 视频、音频、日志、镜像等等
    Bucket: 用来存储 Object 的逻辑空间。每个 Bucket 之间的数据是相互隔离的。对于客户端而言, 就相当于一个存放文件的顶层文件夹。
    Drive: 即存储数据的磁盘,在 MinIO 启动时,以参数的方式传入。Minio 中所有的对象数据都会存储在Drive里。
    Set: 即一组 Drive 的集合, 分布式部署根据集群规模自动划分一个或多个Set, 每个Set中的 Drive 分布在不同位置。

    创建桶时指定域的作用
    Minio桶的法定区域是一个可选项,它用于指定桶中对象的数据存储位置。这对于遵守数据存储的法规和合规性非常重要。
    当你在创建Minio桶时指定了域,实际上是在告诉Minio系统将该桶的数据存储在特定的地理区域内。这有助于确保你的数据存储符合特定国家或地区的法规和政策。这也可能涉及到数据本地化的需求,即确保数据存储在特定的地理位置,以满足法规或组织内部政策的要求。

    桶的概念理解
    MinIO中的桶(Bucket)是一种顶层容器,用于组织和存储对象(Object),而桶本身是不能嵌套的。MinIO的桶结构是扁平的, 也就是说MinIO不支持在一个桶内创建子桶或嵌套桶。
    如果你需要对对象进行更细粒度的组织,可以使用对象键(Object Key)的命名约定,通常使用斜杠(/)或其他字符来模拟目录结构,以实现对象的逻辑组织。例如,你可以创建类似于"folder/object"的键,来模拟文件夹结构,但实际上这只是使用键来模拟目录结构,而不是实际的嵌套桶。

    Java中调用MinIO

    使用Maven添加依赖

    <dependency>
        <groupId>io.miniogroupId>
        <artifactId>minioartifactId>
        <version>8.3.5version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    客户端初始化

    import io.minio.MinioClient;
    
    public class MinioExample {
        public static void main(String[] args) throws Exception {
            String serverUrl = "http://localhost:9000";
            String accessKey = "your-access-key";
            String secretKey = "your-secret-key";
    
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(serverUrl)
                    .credentials(accessKey, secretKey)
                    .build();
    
            //构造方法二    
            MinioClient minioClient =
            MinioClient.builder()
                .endpoint("https://localhost:9000")
                .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
                .region("eu-east-1")
                .httpClient(customHttpClient)
                .build();
    
            //构造方式三    
            MinioClient minioClient = new MinioClient("https://play.min.io", "Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG");     
        }
    }
    
    • 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

    桶操作

    判断桶是否存在

    boolean found = minioClient.bucketExists("mybucket");
    
    • 1

    创建桶

    minioClient.makeBucket("mybucket");
    //创建桶指定区域
    if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket("my-new-bucket").build())) {
        minioClient.makeBucket(
                MakeBucketArgs.builder().bucket("my-new-bucket").region("new-bucket-west-1").build());
    }
    
    //创建桶,加入锁
    //用于确保数据的不可变性和合规性,尤其适用于需要长期数据保留和数据安全性的应用程序和环境
    if (!minioClient.bucketExists("my-new-bucket-with-object-lock")) {
        minioClient.makeBucket(
                MakeBucketArgs.builder()
                        .bucket("my-new-bucket-with-object-lock")
                        .region("new-bucket-west-1")
                        .objectLock(true)
                        .build());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    列出所有的桶

    List<Bucket> bucketList = minioClient.listBuckets();
    for (Bucket bucket : bucketList) {
        System.out.println(bucket.creationDate() + ", " + bucket.name());
    }
    
    //列出某个桶中的所有对象  
    boolean found = minioClient.bucketExists("mybucket");
    if (found) {
    Iterable<Result<Item>> myObjects = minioClient.listObjects("mybucket");
    for (Result<Item> result : myObjects) {
        Item item = result.get();
        System.out.println(item.lastModified() + ", " + item.size() + ", " + item.objectName());
    }} 
    
    //列出存储桶中被部分上传的对象  
    //listIncompleteUploads(String bucketName, String prefix, boolean recursive)
    //bucketName 存储桶名称; prefix 对象名称的前缀; recursizve 是否递归查找;  
    boolean found = minioClient.bucketExists("mybucket");
    if (found) {
    Iterable<Result<Upload>> myObjects = minioClient.listIncompleteUploads("mybucket");
    for (Result<Upload> result : myObjects) {
        Upload upload = result.get();
        System.out.println(upload.uploadId() + ", " + upload.objectName());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    删除桶

    boolean found = minioClient.bucketExists("mybucket");
    if (found) {
        minioClient.removeBucket("mybucket");
    } 
    
    • 1
    • 2
    • 3
    • 4

    获取和设置策略

    //获得指定对象前缀的存储桶策略
    minioClient.getBucketPolicy("myBucket", "downloads");
    
    //给一个桶添加策略  
    minioClient.setBucketPolicy("myBucket", "uploads", PolicyType.READ_ONLY);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    对象操作

    以流的形式下载一个对象

    try {
      // 调用statObject()来判断对象是否存在, 不存在抛异常
      minioClient.statObject("mybucket", "myobject");
    
      // 获取流  
      InputStream stream = minioClient.getObject("mybucket", "myobject");
    
      byte[] buf = new byte[16384];
      int bytesRead;
      while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
        System.out.println(new String(buf, 0, bytesRead));
      }
      // 关闭流
      stream.close();
    } catch (MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    下载对象指定区域的字节数组做为流(断点下载)

    try {
      // 判断对象是否存在, 不存在抛异常
      minioClient.statObject("mybucket", "myobject");
    
      // 获取指定offset和length的"myobject"的输入流
      InputStream stream = minioClient.getObject("mybucket", "myobject", 1024L, 4096L);
    
      // 读取输入流直到EOF并打印到控制台。
      byte[] buf = new byte[16384];
      int bytesRead;
      while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
        System.out.println(new String(buf, 0, bytesRead));
      }
      // 关闭流。
      stream.close();
    } catch (MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    下载并将文件保存到本地

    try {
      // 不存在 抛异常
      minioClient.statObject("mybucket", "myobject");
    
      // 获取myobject的流并保存到photo.jpg文件中。
      minioClient.getObject("mybucket", "myobject", "photo.jpg");
    
    } catch (MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对加密数据进行解密下载(AES加密)

    try {
      // 判断是否存在 不存在抛异常
      minioClient.statObject("mybucket", "myobject");
    
      //生成256位AES key。
      KeyGenerator symKeyGenerator = KeyGenerator.getInstance("AES");
      symKeyGenerator.init(256);
      SecretKey symKey = symKeyGenerator.generateKey();
    
      // 获取对象数据并保存到photo.jpg
      InputStream stream = minioClient.getObject("testbucket", "my-objectname", symKey);
    
      // 读流到EOF,并输出到控制台。
      byte[] buf = new byte[16384];
      int bytesRead;
      while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
        System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8));
      }
    
      // 关闭流。
      stream.close();
    
    } catch (MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 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

    对加密数据进行解密下载(RSA加密)

    try {
      //文件不存在则抛异常  
      minioClient.statObject("mybucket", "myobject");
    
      KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
      keyGenerator.initialize(1024, new SecureRandom());
      KeyPair keypair = keyGenerator.generateKeyPair();
    
      // 获取对象数据并保存到photo.jpg
      InputStream stream = minioClient.getObject("testbucket", "my-objectname", keypair);
    
      // 读流到EOF,并输出到控制台。
      byte[] buf = new byte[16384];
      int bytesRead;
      while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
        System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8));
      }
    
      // 关闭流。
      stream.close();
    
    } catch (MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    通过InputStream上传对象
    单个对象的最大大小限制在5TB。putObject在对象大于5MiB时,自动使用multiple parts方式上传。
    这样,当上传失败时,客户端只需要上传未成功的部分即可(类似断点上传)。上传的对象使用MD5SUM签名进行完整性验证。

    try {
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < 1000; i++) {
        builder.append("Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. ");
        builder.append("(29 letters)\n");
        builder.append("Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. ");
        builder.append("- --\n");
      }
      ByteArrayInputStream bais = new ByteArrayInputStream(builder.toString().getBytes("UTF-8"));
      // 创建对象
      minioClient.putObject("mybucket", "myobject", bais, bais.available(), "application/octet-stream");
      bais.close();
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    通过文件上传到对象中

    try {
      minioClient.putObject("mybucket",  "island.jpg", "/mnt/photos/island.jpg")
      System.out.println("island.jpg is uploaded successfully");
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    AES加密上传

    try {
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < 1000; i++) {
        builder.append("Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. ");
        builder.append("(29 letters)\n");
        builder.append("Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. ");
        builder.append("(31 letters)\n");    
        builder.append("- --\n");
      }
      ByteArrayInputStream bais = new
      ByteArrayInputStream(builder.toString().getBytes("UTF-8"));
      
      //生成256位AES key.
      KeyGenerator symKeyGenerator = KeyGenerator.getInstance("AES");
      symKeyGenerator.init(256);
      SecretKey symKey = symKeyGenerator.generateKey();
      
      // 创建一个对象
      minioClient.putObject("mybucket", "myobject", bais, bais.available(), "application/octet-stream", symKey);
      bais.close();
      System.out.println("myobject is uploaded successfully");
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    RSA加密上传

    try {
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < 1000; i++) {
        builder.append("Sphinx of black quartz, judge my vow: Used by Adobe InDesign to display font samples. ");
        builder.append("(29 letters)\n");
        builder.append("Jackdaws love my big sphinx of quartz: Similarly, used by Windows XP for some fonts. ");
        builder.append("(31 letters)\n");
        builder.append("- --\n");
      }
      ByteArrayInputStream bais = new
      ByteArrayInputStream(builder.toString().getBytes("UTF-8"));
      
      KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
      keyGenerator.initialize(1024, new SecureRandom());
      KeyPair keypair = keyGenerator.generateKeyPair();
      
      // Create an object
      minioClient.putObject("mybucket", "myobject", bais, bais.available(), "application/octet-stream", keypair);
      bais.close();
      System.out.println("myobject is uploaded successfully");
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    获取对象的元数据

    try {
      // 获得对象的元数据。
      ObjectStat objectStat = minioClient.statObject("mybucket", "myobject");
      System.out.println(objectStat);
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    从objectName指定的对象中将数据拷贝到destObjectName指定的对象

    try {
      CopyConditions copyConditions = new CopyConditions();
      copyConditions.setMatchETagNone("TestETag");
    
      minioClient.copyObject("mybucket",  "island.jpg", "mydestbucket", "processed.png", copyConditions);
      System.out.println("island.jpg is uploaded successfully");
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    删除一个对象

    try {
          // 从mybucket中删除myobject。
          minioClient.removeObject("mybucket", "myobject");
          System.out.println("successfully removed mybucket/myobject");
    } catch (MinioException e) {
          System.out.println("Error: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    删除多个对象

    List<String> objectNames = new LinkedList<String>();
    objectNames.add("my-objectname1");
    objectNames.add("my-objectname2");
    objectNames.add("my-objectname3");
    try {
          // 删除my-bucketname里的多个对象
          for (Result<DeleteError> errorResult: minioClient.removeObject("my-bucketname", objectNames)) {
            DeleteError error = errorResult.get();
            System.out.println("Failed to remove '" + error.objectName() + "'. Error:" + error.message());
          }
    } catch (MinioException e) {
          System.out.println("Error: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    删除一个未完整上传的对象

    try {
        // 从存储桶中删除名为myobject的未完整上传的对象。
    	minioClient.removeIncompleteUpload("mybucket", "myobject");
    	System.out.println("successfully removed all incomplete upload session of my-bucketname/my-objectname");
    } catch(MinioException e) {
    	System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Presigned操作

    生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。

    try {
    	String url = minioClient.presignedGetObject("mybucket", "myobject", 60 * 60 * 24);
    	System.out.println(url);
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    允许给POST请求的presigned URL设置策略,比如接收对象上传的存储桶名称的策略,key名称前缀,过期策略。

    try {
    	PostPolicy policy = new PostPolicy("mybucket", "myobject",
      DateTime.now().plusDays(7));
    	policy.setContentType("image/png");
    	Map<String,String> formData = minioClient.presignedPostPolicy(policy);
    	System.out.print("curl -X POST ");
    	for (Map.Entry<String,String> entry : formData.entrySet()) {
        System.out.print(" -F " + entry.getKey() + "=" + entry.getValue());
    	}
    	System.out.println(" -F file=@/tmp/userpic.png  https://play.min.io/mybucket");
    } catch(MinioException e) {
      System.out.println("Error occurred: " + e);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Ubuntu22.04中root用户下依然权限不够,执行不了可执行文件
    手撸任意层神经网络-读从文本s.txt取网络结构初始化neuralNetwork
    JavaScript FileReader API 处理文件示例
    线阵相机之帧超时
    python零基础看完必会安装和配置环境,文末附下载安装包
    【仙逆】王林用计灭富二代,有长命锁也没用,藤化元一怒请一人出山
    PostgreSQL 基础--常用命令
    DocTemplateTool - 可根据模板生成word或pdf文件的工具
    LQ0017 排列字母【排序】
    网络编程 - IP协议
  • 原文地址:https://blog.csdn.net/yang1fei2/article/details/133777173