MinIO linux安装并整合spring boot

一、简介

MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。

二、环境

ip 端口
100 9000
102 9000

我这里服务器就只用了两台,会用来做 MinIO的分布式文件。

三、单机

wget https://dl.min.io/server/minio/release/linux-amd64/minio
# 赋予执行权限
chmod +x minio
# 启动 并设置数据存储位置(单机)
./minio server /data

四、分布式

建议编写脚本如下 start.sh

# 端口打开 9000
/sbin/iptables -I INPUT -p tcp --dport 9000 -j ACCEPT
# 重新设置密钥
export MINIO_ACCESS_KEY=minio
export MINIO_SECRET_KEY=minio@2020
# 启动并指定分布式服务器,这里会有坑 可以看 5 标题
./minio server \
http://10.240.30.100/home/MinIO/data{1...4}  http://10.240.30.102/home/MinIO/data{1...4}

{1...4} 的意思是会在 /home/MinIO/ 生产4个文件 data1 data2 data3 data3,其中 "..." 必须为3个点,得以获得最佳的纠删码分布。启动成功后会有一个 VIP做为网关。我自己使用VIP一旦崩溃,无法转移,具体原因尚不清楚。

纠删码 是一种恢复丢失和损坏数据的数学算法,来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量的硬盘,您仍然可以恢复数据。内部会根据你提供的磁盘数量或节点数量,去分配数据和奇偶校验块,一般是对半开,确保对硬盘故障提供最佳保护。Minio纠删码的设计目标是为了性能和尽可能的使用硬件加速。

五、分布式出现的问题

我很疑惑他是怎么知道我的 nginx1.18.0,我并没有给 MinIO 配置过相关nginx信息。

API: SYSTEM()
Time: 17:53:35 CST 12/25/2020
DeploymentID: e660d5ad-c358-4aca-bdb5-f9859348b8c6
Error: <html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
 (*errors.errorString)
       2: cmd/notification.go:468:cmd.(*NotificationSys).updateBloomFilter.func1()
       1: pkg/sync/errgroup/errgroup.go:55:errgroup.(*Group).Go.func1()

改到如下配置即可解决

/sbin/iptables -I INPUT -p tcp --dport 9000 -j ACCEPT
export MINIO_ACCESS_KEY=minio
export MINIO_SECRET_KEY=minio@2020
./minio server \
http://10.240.30.102/home/MinIO/data1  http://10.240.30.100/home/MinIO/data1 \
http://10.240.30.102/home/MinIO/data2  http://10.240.30.100/home/MinIO/data2

之前我设置的是每个节点会创建4个目录,现在改为2个目录,并没有在报错。在官网看到如下:

MinIO选择最大的EC(纠删码)集大小,该大小划分为驱动器总数或给定的节点总数-确保保持统一分布,即每个节点每集合参与相等数量的驱动器。

我理解的意思是,在分布式中可能单个节点的磁盘数量根据分布式的节点数量而定。

六、特性及注意

  1. 在分布式中,如果有16个节点,其中8个节点蹦了,依然可以查看,但无法编辑或上传,只有在可用节点为9台才能正常使用。
  2. 单独给分布式其中的某一个节点上传文件,文件会被同步到其他节点。
  3. 分布式MinIO所需的最小磁盘(目录)为4,所以小于4就会报错,4是所有节点的磁盘(目录)之和,不是单个节点需要设置4个磁盘(目录),并且使用分布式Minio自动引入了纠删码功能。
  4. 2台分布式的时候,会分配一个主的做为网关(VIP),当VIP被宕,无法在通过VIP访问到。
  5. 分布式中密钥必须一致。
  6. 2台分布式的时候,其中一台挂掉另一台无法使用任何功能。
  7. minio 自带控制台 http://xx.xxx.xxx.xx:9000/minio/login 老是会忘记
  8. 新建的bucket上传文件后是没办法查看到的,需要修改bucket读写权限后重新上传。

七、整合spring boot

依赖

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

控制层

package com.giant.cloud.controller;

import com.giant.cloud.service.ImgServer;
import com.giant.security.util.ResponseData;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;

/**
 * @Author big uncle
 * @Date 2020/6/15 10:41
 **/
@RestController
@RequestMapping("/img")
@RefreshScope
public class ImgController {


    @Resource(name = "MinIOServer")
    private ImgServer imgServer;

    @PostMapping("/push")
    public ResponseData push(@RequestParam("file") MultipartFile file,String path,String bucket){
        return imgServer.push(bucket,path,file);
    }

    @PostMapping("/del")
    public ResponseData<Boolean> del() {
        return imgServer.del();
    }

    @PostMapping("/get")
    public ResponseData get() {
        return imgServer.download();
    }

}

服务层

package com.giant.cloud.service.impl;

import com.giant.cloud.code.UploadFileCode;
import com.giant.cloud.config.FileEnvironmentConfig;
import com.giant.cloud.service.ImgServer;
import com.giant.security.util.ResponseData;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.UUID;

/**
 * @author big uncle
 * @date 2021/1/11 17:50
 * @module
 **/
@Service(value = "MinIOServer")
public class MinIOServerImpl implements ImgServer {

    @Resource
    private ObjectServerImpl objectServer;
    @Resource
    private FileEnvironmentConfig fileEnvironmentConfig;

    @Override
    public ResponseData<String> push(String bucket,String path,MultipartFile file) {
        try {
            Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            String id = UUID.randomUUID().toString().replaceAll("-","");
            String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
            String objName = id + milliSecond + fileSuffix;
            String str = objectServer.createObject(bucket,path+objName, file.getInputStream());
            return ResponseData.successResponse(fileEnvironmentConfig.getGateway()+bucket+"/"+str);
        }catch(Exception e){
            e.printStackTrace();
            return ResponseData.failureResponse(UploadFileCode.UPLOAD_FILE_CODE_1001);
        }
    }

    @Override
    public ResponseData<String> download() {
        return null;
    }

    @Override
    public ResponseData<Boolean> del() {
        return null;
    }
}

ObjectServerImpl

package com.giant.cloud.service.impl;

import cn.hutool.core.util.StrUtil;
import com.giant.cloud.code.BucketCode;
import com.giant.cloud.service.ObjectServer;
import com.giant.security.exp.impl.BasicException;
import io.minio.MinioClient;
import io.minio.ObjectWriteArgs;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.InputStream;

/**
 * @author big uncle
 * @date 2021/1/11 18:39
 * @module
 **/
@Service
public class ObjectServerImpl implements ObjectServer {

    @Resource
    private MinioClient minioClient;
    @Resource
    private BucketServerImpl bucketServer;


    @Override
    public String putObject(String bucket, String filePath, InputStream inputStream) throws Exception{
        if(StrUtil.isBlank(bucket)){
            throw new BasicException(BucketCode.BUCKET_CODE_200);
        }
        if(!bucketServer.bucketExists(bucket)){
            throw new BasicException(BucketCode.BUCKET_CODE_201);
        }
        minioClient.putObject(
                PutObjectArgs.builder().bucket(bucket).object(filePath).stream(
                        inputStream, -1, ObjectWriteArgs.MIN_MULTIPART_SIZE)
                        .contentType("image/png")
                        .build());
        return filePath;
    }

    @Override
    public String createObject(String bucket,String path, InputStream inputStream) throws Exception {
        if(!bucketServer.bucketExists(bucket)){
            bucketServer.createBucket(bucket);
        }
        return putObject(bucket,path,inputStream);
    }

    @Override
    public void delObject(String bucket,String path,String name) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder().bucket(bucket).object(path+name).build());
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容