SpringBoot+MinIO实现minio部署和使用

news2024/11/29 8:45:39

Minio是一个go编写基于Apache License v2.0开源协议的对象存储系统,是为海量数据存储、人工智能、大数据分析而设计,它完全兼容Amazon S3接口,十分符合存储大容量的非结构化数据从几十kb到最大5T不等。是一个小而美的开源分布式存储软件。

特点
简单、可靠:Minio采用简单可靠的集群方案,摒弃复杂的大规模的集群调度管理,减少风险与性能瓶颈,聚焦产品的核心功能,打造高可用的集群、灵活的扩展能力以及超过的性能。建立众多的中小规模、易管理的集群,支持跨数据中心将多个集群聚合成超大资源池,而非直接采用大规模、统一管理的分布式集群。

功能完善:Minio支持云原生,能与Kubernetes、Docker、Swarm编排系统良好对接,实现灵活部署。且部署简单,只有一个可执行文件,参数极少,一条命令即可启动一个Minio系统。Minio为了高性能采取无元数据数据库设计,避免元数据库成为整个系统的性能瓶颈,并将故障限制在单个集群之内,从而不会涉及其他集群。Minio同时完全兼容S3接口,因此也可以作为网关使用,对外提供S3访问。同时使用Minio Erasure code和checksum 来防止硬件故障。即使损失一半以上的硬盘,但是仍然可以从中恢复。分布式中也允许(N/2)-1个节点故障。

docker+rancher部署minio集群
在rancher上创建三个minio服务,这三个选择的服务器ip是三台不同的服务器ip,在主机调度中进行选择不同的主机
端口映射:
在这里插入图片描述
配置环境变量:

主机调度
每个指定不同的主机,三台机器分别运行一个minio
配置数据卷
在三台主机主机的host文件中添加host对应关系

ip1 minio-1
ip2 minio-2
ip3 minio-3

数据卷配置
在这里插入图片描述
在这里插入图片描述

网络
使用主机网络:是
入库命令
server --console-address :9090 http://minio-{1…3}/data{1…2}
在这里插入图片描述

安装ngxin负载均衡访问minio在rancher上创建nginx服务
在这里插入图片描述

数据卷映射
进入主机目录配置nginx,
vi /mnt/nginx/conf.d

内容如下:

worker_processes  1;

events {
    worker_connections  1024;
}

http{
  
  #上面安装主机的三台机器记得修改
    upstream http_minio_back{
        server ip1:9000;
        server ip2:9000;
        server ip3:9000;
    }
    server{
        listen 6555;
        server_name localhost;
        ignore_invalid_headers off;
        #配置成上传文件不限制大小
        client_max_body_size 0;
        proxy_buffering off;

        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-Host $host:$server_port;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

            proxy_connect_timeout 300;
            proxy_http_version 1.1;
            chunked_transfer_encoding off;
            proxy_ignore_client_abort on;

            proxy_pass http_minio_back

        }
    }
    }
}

数据卷配置引入conf.d
在这里插入图片描述

springboot+minio 实例如下:

pom.xml

<dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.0.3</version>
        </dependency>

application.yml配置:

spring:
  # 配置文件上传大小限制
  servlet:
    multipart:
      max-file-size: 500MB
      max-request-size: 500MB
oss:
  endpoint: ${ENDPOINT:http://nginx的ip:nginx的端口号}
  access-key: ${ACCESS_KEY:minio}
  secret-key: ${SECRET_KEY:minio}

minio配置类

@Configuration
@ApiModel(value = "minio配置")
public class MinIoClientConfig {
	@Value("${oss.endpoint}")
    private String url;
    @Value("${oss.access-key}")
    private String accessKey;
    @Value("${oss.secret-key}")
    private String secretKey;
    @Bean
    public MinioClient minioClient(){
 
        return MinioClient.builder()
                .endpoint(url)
                .credentials(accessKey, secretKey)
                .build();
    }
 }

编写工具类用于将公用方法写到工具类中,实现调用

import cn.hutool.core.io.FastByteArrayOutputStream;
import com.alibaba.nacos.common.util.UuidUtils;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
@RequiredArgsConstructor
public class MinioUtil {
//必须使用注入的方式否则会出现空指针
    @Autowired
   MinioClient minioClient;

    /**
     * 查看存储bucket是否存在
     *  bucketName 需要传入桶名
     * @return boolean
     */
    public Boolean bucketExists(String bucketName) {
        Boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return found;
    }

    /**
     * 创建存储bucket
     *  bucketName 需要传入桶名
     * @return Boolean
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 删除存储bucket
     * bucketName 需要传入桶名
     * @return Boolean
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 获取全部bucket
     */
    public List<Bucket> getAllBuckets() {
        try {
            List<Bucket> buckets = minioClient.listBuckets();
            return buckets;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    /**
     * 文件上传
     *
     * @param file 文件
     * BucketName 需要传入桶名
     * @return Boolean
     */
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)){
            throw new RuntimeException();
        }
        String fileName = UuidUtils.generateUuid() + originalFilename.substring(originalFilename.lastIndexOf("."));
        String objectName = "sssss" + "/" + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket("BucketName").object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectName;
    }

    /**
     * 预览
     * @param fileName
     * BucketName 需要传入桶名
     * @return
     */
    public String preview(String fileName){
        // 查看文件地址
        GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket("BucketName").object(fileName).method(Method.GET).build();
        try {
            String url = minioClient.getPresignedObjectUrl(build);
            return url;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件下载
     * @param fileName 文件名称
     * BucketName 需要传入桶名
     * @param res response
     * @return Boolean
     */
    public void download(String fileName, HttpServletResponse res) {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket("BucketName")
                .object(fileName).build();
        try (GetObjectResponse response = minioClient.getObject(objectArgs)){
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
                while ((len=response.read(buf))!=-1){
                    os.write(buf,0,len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                // res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()){
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看文件对象
     * BucketName 需要传入桶名
     * @return 存储bucket内文件对象信息
     */
    public List<Item> listObjects() {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket("BucketName").build());
        List<Item> items = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                items.add(result.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return items;
    }

    /**
     * 删除
     * @param fileName
     * BucketName 需要传入桶名
     * @return
     * @throws Exception
     */
    public boolean remove(String fileName){
        try {
            minioClient.removeObject( RemoveObjectArgs.builder().bucket("BucketName").object(fileName).build());
        }catch (Exception e){
            return false;
        }
        return true;
    }
    }

测试

@RequestMapping("/tesss")
@RestController
public class TestCon {
    @Autowired
    MinioUtil minioUtil;
    @GetMapping("/test")
    public Boolean bucketExists(String bucketName) {
        return minioUtil.bucketExists(bucketName);
    }

    @GetMapping("/test123")
    public Boolean makeBucket(String bucketName) {
        return minioUtil.makeBucket(bucketName);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/741558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows系统下载大白菜制作iso镜像文件

背景 1. ventory制作了U盘启动盘&#xff0c;ventory只能加载iso文件&#xff0c; 我们有些操作需要进入到winpe系统进行操作&#xff0c;故需要制作大白菜pe的iso文件 操作步骤 下载大白菜 大白菜u盘启动盘制作工具_大白菜u盘装系统_大白菜pe_大白菜官网-首页 (windowsrw.…

一个判断 I2C 总线通信异常原因的方法

一个判断 I2C 总线通信异常原因的方法 参考链接 【经验分享】一个判断 I2C 总线通信异常原因的方法 (stmicroelectronics.cn)https://shequ.stmicroelectronics.cn/thread-633302-1-1.html 至于如何在i2c总线中如何使用还没有弄明白。后续再看。 使用方法记录 阻值分配 图中…

Confidence Regularized Self-Training 阅读笔记

Confidence Regularized Self-Training 领域自适应研究的最新进展表明&#xff0c;深度自训练是实现无监督领域自适应的有效手段。这些方法通常涉及到一个迭代过程&#xff0c;即在目标域上进行预测&#xff0c;然后将自信的预测作为伪标签进行再训练。然而&#xff0c;由于伪…

泛微打造国资委国企双端的监管平台,数据互联,动态管理

数字政府和数字监管成为趋势。数字化方式能够助力完善国有资产管理体制&#xff0c;促进国有资产保值增值&#xff0c;推动国有资本做强做优做大&#xff0c;有效防止国有资产流失。 国资监管过程中存在着诸多挑战 监管企业众多&#xff0c;需要建立不同的管理模式。既要发挥…

C/C++库函数之——str类和mem篇(常用速学)

目录 一&#xff0c;str类 1&#xff09;strlen 2&#xff09;strcpy 3&#xff09;strcmp 4&#xff09;strcat 5&#xff09;strstr 二&#xff0c;mem类函数 1&#xff09;memcpy 2&#xff09;memmove 一&#xff0c;str类 1&#xff09;strlen 用途&#xff1a…

光伏5G多合一融合终端|光伏多合一融合终端|光伏多合一群调群控网关|分布式光伏群控群调|光伏AGC/AVC系统这几者之间什么技术关系,多少钱一套预算?

光伏5G多合一融合终端|光伏多合一融合终端|光伏多合一群调群控网关|分布式光伏群控群调|光伏AGC/AVC系统这几者之间什么技术关系&#xff0c;多少钱一套预算&#xff1f; 一&#xff1a;光伏5G多合一融合终端的功能 光伏5G多合一融合终端的功能&#xff1a;群调群控/AGC/AVC功…

[MMDetection]生成测试集预测的test.bbox.json文件

基于MMdetection3.10 困扰了大半天的问题&#xff0c;终于解决了。 方法1&#xff1a;定位到configs\_base_\datasets\coco_detection.py 将里面的路径全部换为自己的路径&#xff0c;最重要的是将以下注释取消掉&#xff0c;特别注意以下两个参数 改好的文件示例 # datase…

数据结构 - 线性表(C语言版)

线性表分为顺序表和单链表 线性表的操作主要是查询、插入、删除 1、顺序表 首先&#xff0c;定义一个顺序表的结构体 #define MAX_SIZE 10 typedef struct {int data[MAX_SIZE];int length; }SqList, * PsqList;创建一个线性表 void createSqList(PsqList pSqList) {pSqLis…

Spring—事务及事务的传播机制

Spring—事务及事务的传播机制 &#x1f50e;事务的定义&#x1f50e;Spring—事务的实现铺垫Spring 编程式事务Spring 声明式事务Transactional 的参数注意事项Transactional 的工作原理 &#x1f50e;Spring—事务的隔离级别MySQL—事务的隔离级别Spring—事务的隔离级别Spri…

剑指 Offer 04. 二维数组中的查找(java)

二维数组中的查找 剑指 Offer 04. 二维数组中的查找题目描述抽象 BST 解题 二叉树专题 剑指 Offer 04. 二维数组中的查找 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof 题目描述…

js为啥是设计成单线程而不是多线程呢

了解这个问题之前&#xff0c;需要先了解一下以下问题&#xff1a; 什么是进程&#xff1f;什么是线程&#xff1f;二者有啥关联&#xff1f;任务队列是什么&#xff1f;宏任务&#xff1f;微任务&#xff1f;eventloop&#xff1f;为什么说js是单线程&#xff0c;为什么要设计…

UWB高精度定位标签方案,厘米级室内测距,实时人员物品位置确定

随着科技的不断进步&#xff0c;UWB技术正逐渐成为各个领域的定位解决方案的首选。其高精度、安全、实时的特性使其在安全免提访问控制、实时室内定位等应用领域发挥着重要的作用。 安全免提访问控制是目前应用UWB技术的重要领域之一。通过将UWB标签&#xff08;如手机、钥匙扣…

Django如何删除数据库表中的数据【不断积累】

这篇博客积累Django的数据库常用删除方法。 假设有表模型Author定义如下&#xff1a; class Author(models.Model):name models.CharField(max_length100)def __str__(self):return self.name01-根据记录的id号来删除指定的记录 Django 默认为每个模型添加一个名为 id 的自…

RPA赋能日化产业,实在智能广东日化共推行业数字化转型

广东日化&#xff0c;因其独特的地域、产能优势&#xff0c;成为广东制造业的支柱产业之一&#xff0c;占据了全国日化行业的半壁江山。作为本土最具影响力商会组织之一&#xff0c;广东省日化商会凝聚了一批具有影响力的日化企业&#xff0c;其经济总量、市场占有率、品牌知名…

python网站创建:初识网站(001)

1. 初识网站&#xff1a;首先来认识一下&#xff0c;前端、后端、数据库它是怎么分工合作来形成网站的 使用python创建网站之前&#xff0c;需要先稍微认识一下两个最流行python web框架&#xff1a;(Flask)和(Django) Flask是一个轻量级的框架&#xff0c;适用于比较轻巧&…

【*1900倍数遍历】CF1627 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 在枚举数列子集的gcd时&#xff0c;通常可以枚举倍数 对于这道题要注意&#xff0c;j/i的gcd要为1&#xff0c;这样才能保证i是这个子集的最大公约数 Code&#xff1a; #include <bits/stdc.h>//#define…

三菱FX3U简单工程编程

1.简单工程编程 1.1.元件 常开触点&#xff08;ld&#xff09; 选中位置&#xff0c;点击图标&#xff0c;输入软元件&#xff0c;完成添加。 选中位置&#xff0c;快捷键F5添加。 选中位置&#xff0c;输入ld 软元件添加。常闭触点&#xff08;ldi&#xff09;横线、竖线 …

红黑树增删操作详解(相信我,这次你一定会弄懂)

前言&#xff1a; 网上众多关于红黑树的讲解&#xff0c;但大多数都是重复的&#xff0c;只列出了几种简单情况&#xff0c;逻辑和思维深度都不足以解答吾之困惑。。。 直到看到张彦峰先生的 对红黑树的认识总结&#xff0c;基本可以说是集大成者&#xff0c;本文会基于…

MySQL原理探索——28 读写分离有哪些坑

在上一篇文章中&#xff0c;介绍了一主多从的结构以及切换流程。今天我们就继续聊聊一主多从架构的应用场景&#xff1a;读写分离&#xff0c;以及怎么处理主备延迟导致的读写分离问题。 我们在上一篇文章中提到的一主多从的结构&#xff0c;其实就是读写分离的基本结构了。这里…

linux环境下使用jmeter进行分布式测试

目录 1、前言 2、环境准备 3、分布式配置 总结&#xff1a; 1、前言 熟练使用jmeter进行性能测试的工程师都知道&#xff0c;jmeter的客户端性能是有点差的。这会导致一个问题&#xff0c;其客户端的性能损耗会干扰到性能测试的结果&#xff0c;而且当线程数/并发大到一定程…