MinIO分布式专题(第一章带你认识MinIO)
Posted 风清扬逍遥子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MinIO分布式专题(第一章带你认识MinIO)相关的知识,希望对你有一定的参考价值。
市面上有很多的分布式存储方案,比如FastDFS,MongoDB,或者目前云厂商的存储
比如阿里云,腾讯云,华为云等等,但是对于很多企业不愿意上云,于是业内就出现了很多
的方案,而本章讲述的MinIO,一定是你看了就绝壁拍手称赞的!
目录
1、分布式文件系统应用场景
互联网下海量的非结构化存储的需求背景下,比如:
- 电商网站,存储海量的商品图片
- 视频网站,海量的视频文件
- 网盘,海量的文件
- 社交网站等等
在这样的背景下,传统的FastDFS部署太过于繁琐,动不动就是来个nginx,然后配置一
堆参数和设置,尤其是做分布式的时候,那维护成本一下就上来了,从维护和部署的角度,
FastDFS不是一个好的选择,而从迭代的角度,FastDFS早就不维护了,有很多需求是无法
支持到的,那么就需要你自己思考写源码打包了。
同理HDFS部署也不简单,而且Hadoop适合超大文件的存储,并且文件都需要分片,应
用场景更多是计算处理,实时数据分析,并且其实HDFS比较吃硬件设备,因为偏于计算,
所以对CPU的要求比较高,对于中小企业的业务量并没有这么大,所以应用场景这块也比较
难接触到,但是HDFS的功能还是十分强大的!!还是根据业务进行选型。
1.1、MinIO介绍
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云
存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份
数据和容器/虚拟机镜像等,而 一个对象文件可以是任意大小,从几kb到最大5T不等。
MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或
者mysql。
官网:http://minio.org.cn/overview.shtml
对于中小型企业,如果不选择存储上云,那么 Minio 是个不错的选择,麻雀虽小,五脏
俱全。当然 Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无
缝对接到 Amazon S3、MicroSoft Azure。
在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在
使用MinIO产品。
优点:
- 部署简单: 一个single二进制文件即是一切,还可支持各种平台。
- minio支持海量存储,可按zone扩展(原zone不受任何影响),支持单个对象最大5TB; 兼容Amazon S3接口,充分考虑开发人员的需求和体验;
- 低冗余且磁盘损坏高容忍,标准且最高的数据冗余系数为2(即存储一个1M的数据对象,实际占用 磁盘空间为2M)。但在任意n/2块disk损坏的情况下依然可以读出数据(n为一个纠删码集合(Erasure Coding Set)中的disk数量)。并且这种损坏恢复是基于单个对象的,而不是基于整个存储卷的。
- 读写性能优异
体现在下图,HDD硬盘下,运行16个节点的Minio集群,读性能在10GB/s,写性能在
8GB/s,这个是非常高的。
上述的优点先过个眼缘,后面我会一一去解释并演示出来。
1.2、MinIO基础概念
- Object:存储到 Minio 的基本对象,如文件、字节流,Anything...
- Bucket:用来存储 Object 的逻辑空间。每个 Bucket 之间的数据是相互隔离的。对于客户端而言,就相当于一个存放文件的顶层文件夹。
- Drive:即存储数据的磁盘,在 MinIO 启动时,以参数的方式传入。Minio 中所有的对象数据都会存储在 Drive 里。
- Set :即一组 Drive 的集合,分布式部署根据集群规模自动划分一个或多个 Set ,每个 Set 中的 Drive 分布在不同位置。一个对象存储在一个 Set 上。(For example: {1...64} is divided into 4 sets each of size 16.)
- 一个对象存储在一个Set上
- 一个集群划分为多个Set
- 一个Set包含的Drive数量是固定的,默认由系统根据集群规模自动计算得出 一个SET中的Drive尽可能分布在不同的节点上
1.3、纠删码
什么是纠删码呢?纠删码(Erasure Code)简称EC,是一种数据保护方法,它将数据
分割成片段,把冗余数据块扩展、编码,并将其存储在不同的位置,比如磁盘、存储节点或
者其它地理位置。
从数据函数角度来说,纠删码提供的保护可以用下面这个简单的公式来表示:n = k +
m。变量“k”代表原始数据或符号的值。变量“m”代表故障后添加的提供保护的额外或冗余符号
的值。变量“n”代表纠删码过程后创建的符号的总值。
举个例子,我有16块磁盘,就是n,有10份原始文件,一模一样,称为k,16 = 10 +
m,这个m就是可以恢复的校验块个数,所以m是6,任意6个不可用,原始文件都可以恢
复,极端情况,10个原始文件坏掉6个,靠4个原始的加上6个校验块,可以把坏掉的6个原始
文件恢复,这个用到数学行列式矩阵知识,后面再说。
2、MinIO环境搭建
2.1、单机部署
环境:Centos7.x
在/usr下建立一个文件夹,我这边建立了叫做chenxin。
在/usr/chenxin下我区分两个目录,一个是my-minio,一个是data,my-minio是来存放
minio的安装包的,data存放上传的存储数据;
创建目录:sudo mkdir my-minio
然后下载安装包:
wget https://dl.min.io/server/minio/release/linux-amd64/minio
如果命令不存在,记得yum -y install wget 安装下
如果你在使用命令下载的时候,下载不下来。可以多试几次,或者直接用别的机器访问
上面的url直接进行下载,然后上传到服务器上去。
赋予执行权限:chmod +x minio
启动minio写了个脚本,后面有需要可以直接自己搞个脚本启动,命名为start.sh
nohup /usr/chenxin/my-minio/minio server /usr/chenxin/data > /usr/chenxin/data/minio.log 2>&1 &
执行启动后打印
API: http://10.12.105.15:9000 http://127.0.0.1:9000 Console: http://10.12.105.15:34387 http://127.0.0.1:34387 Documentation: https://docs.min.io WARNING: Console endpoint is listening on a dynamic port (34387), please use --console-address ":PORT" to choose a static port. WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables
这里面的信息,API是你将来用上传的时候,调用的上传接口所在的ip+端口
Minio中存在服务端的控制台,地址就是Console的地址,当然下面会有警告,建议Console
控制台的地址ip你可以固定住,通过--console-address:":port"固定,不然你每次启动,这个
端口都会随机变更一个;下面还有一个警告,默认的服务端控制台账号密码是
minioadmin/minioadmin,如果你想修改的话,在linux里执行这两条命令就行了
export MINIO_ROOT_USER=随便你的账号 export MINIO_ROOT_PASSWORD=你的密码
运行起来后,minio会在/root目录下生成一个配置目录.minio
如果我们需要https,证书就需要放在这里面。默认的证书目录${HOME}/.minio/certs。
这里我们暂时用不到;
那我们的start.sh命令就改成这样即可
nohup /usr/chenxin/my-minio/minio server --console-address ":50000" /usr/chenxin/data > /usr/chenxin/data/minio.log 2>&1 &
访问控制台ip+50000端口,发现一直在转圈,那检查下防火墙,并将其关闭
systemctl stop firewalld.service 关闭防火墙
进来后是这样的界面就表示已经成功了。
进入系统后,我们先要点击菜单的Bucket右上角创建一个Bucket
点击菜单的Object Browser (对象浏览),选中后就可以上传文件
还可以删除文件等操作,这些后面我再通过客户端代码演示。
来看下服务器上这个数据是怎么存放的,会在data目录下,Bucket名字作为目录名称,
目录下存放你上传的文件。
单机部署就先到这,这样我们的minio服务端基本的配置算是ok了。
3、Springboot集成MinIO基础实现
我想很多人应该都比较在意的是这些基础功能的使用,所以我在第一章就先让大家用起
来,后面章节会继续延伸;
新建一个项目springboot-minio,我放下主代码:
@RestController @Slf4j public class FileController { @Autowired private MinioClient minioClient; @Value("${minio.bucketName}") private String bucketName; @GetMapping("/list") public List<Object> list() throws Exception { //获取bucket列表 Iterable<Result<Item>> myObjects = minioClient.listObjects( ListObjectsArgs.builder().bucket(bucketName).build()); Iterator<Result<Item>> iterator = myObjects.iterator(); List<Object> items = new ArrayList<>(); String format = "{'fileName':'%s','fileSize':'%s'}"; while (iterator.hasNext()) { Item item = iterator.next().get(); items.add(JSON.parse(String.format(format, item.objectName(), formatFileSize(item.size())))); } return items; } @PostMapping("/upload") public ResultBean upload(@RequestParam(name = "file", required = false) MultipartFile[] file) { ResultBean resultBean = ResultBean.newInstance(); if (file == null || file.length == 0) { return resultBean.error("上传文件不能为空"); } List<String> orgfileNameList = new ArrayList<>(file.length); for (MultipartFile multipartFile : file) { String orgfileName = multipartFile.getOriginalFilename(); orgfileNameList.add(orgfileName); try { //文件上传 InputStream in = multipartFile.getInputStream(); minioClient.putObject( PutObjectArgs.builder().bucket(bucketName).object(orgfileName).stream( in, multipartFile.getSize(), -1) .contentType(multipartFile.getContentType()) .build()); in.close(); } catch (Exception e) { log.error(e.getMessage()); return resultBean.error("上传失败"); } } Map<String, Object> data = new HashMap<String, Object>(); data.put("bucketName", bucketName); data.put("fileName", orgfileNameList); return resultBean.ok("上传成功", data); } @RequestMapping("/download/{fileName}") public void download(HttpServletResponse response, @PathVariable("fileName") String fileName) { InputStream in = null; try { // 获取对象信息 StatObjectResponse stat = minioClient.statObject( StatObjectArgs.builder().bucket(bucketName).object(fileName).build()); response.setContentType(stat.contentType()); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); //文件下载 in = minioClient.getObject( GetObjectArgs.builder() .bucket(bucketName) .object(fileName) .build()); IOUtils.copy(in, response.getOutputStream()); } catch (Exception e) { log.error(e.getMessage()); } finally { if (in != null) { try { in.close(); } catch (IOException e) { log.error(e.getMessage()); } } } } @DeleteMapping("/delete/{fileName}") public ResultBean delete(@PathVariable("fileName") String fileName) { ResultBean resultBean = ResultBean.newInstance(); try { minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build()); } catch (Exception e) { log.error(e.getMessage()); return resultBean.error("删除失败"); } return resultBean.ok("删除成功", null); } private static String formatFileSize(long fileS) { DecimalFormat df = new DecimalFormat("#.00"); String fileSizeString = ""; String wrongSize = "0B"; if (fileS == 0) { return wrongSize; } if (fileS < 1024) { fileSizeString = df.format((double) fileS) + " B"; } else if (fileS < 1048576) { fileSizeString = df.format((double) fileS / 1024) + " KB"; } else if (fileS < 1073741824) { fileSizeString = df.format((double) fileS / 1048576) + " MB"; } else { fileSizeString = df.format((double) fileS / 1073741824) + " GB"; } return fileSizeString; } }
yml配置
minio: endpoint: http://10.12.105.15:9000 accesskey: minioadmin secretKey: minioadmin bucketName: chenxin-bucket
启动Springboot项目后,调用localhost:8080/list
用postman上传试下,很明显上传成功了。
同理下载也是一样,看下接口就清楚了,接口后面跟着文件名就可以下载了,当然这个
后面要做成存储到数据库里,这个后面我拓展出来,先会使用再说。
本章主要介绍了最快认识MinIO的用法和基础结合,后面章节将继续扩展分布式存储的
部署方案和业务场景,希望多多支持!!
以上是关于MinIO分布式专题(第一章带你认识MinIO)的主要内容,如果未能解决你的问题,请参考以下文章
分布式技术专题「OSS中间件系列」Minio的Server端服务的架构和实战搭建
分布式技术专题「OSS中间件系列」Minio的Server端服务的架构和实战搭建
#私藏项目实操分享#分布式技术专题「OSS中间件系列」Minio的Server端服务的架构和实战搭建
分布式技术专题「OSS中间件系列」从0到1的介绍一下开源对象存储MinIO技术架构