在BlogCore中,上传附件到MinIO分布式文件服务器

一、认识MinIO

在上篇文章中,我们说到了Seaweedfs,通过原理,安装以及使用,从0到1的了解了这个老牌的分布式文件存储服务,那无独有偶,这篇咱们说说另一个高性能的分布式文件服务器——MinIO,http://docs.minio.org.cn/。

它是一个基于Apache License v2.0开源协议的高性能的 分布式 对象存储服务器, 也是使用Go语言开发, 整个系统都运行在操作系统的用户态空间。客户端与存储服务器之间采用http/https通信协议。专为大规模数据基础架构而设计,它 兼容亚马逊S3云存储服务接口 , 非常适合于存储大容量非结构化的数据 ,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从小到kb级别到最大5T不等,使用 纠删码(erasure code) 和 校验(checksum) 技术来保护数据免受硬件故障, 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。

MinIO有一个核心概念,就是——存储桶 buckets , 是指存储文件的一个空间或容器。

二、架构原理

极简理念——采用尽可能简单可靠的集群管理方案,摒弃复杂的大规模集群调度管理,减少风险因素与性能瓶颈,聚焦产品的核心功能,打造高可靠的集群、灵活的扩展能力以及超高的性能;

积木式扩展——建立众多的中小规模、易管理的集群,支持跨数据中心将多个集群聚合成超大资源池,而非直接采用大规模、统一管理的分布式集群。

由于MinIO是非常轻量级的软件,所以架构上也没有这么复杂,他使用操作系统的文件系统作为存储介质,我们在向任意节点写数据的时候,MinIO会自动同步数据到另外的节点,这个机制叫做erasure code(纠删码)来保证集群的稳定,保证数据可用,所以我们建议至少使用4个节点来构建集群。

如果一个N节点的分布式MinIO,只要有N/2节点在线,数据就是安全的。但是如果要创建新的对象,就需要保证至少有N/2+1个节点健康。比如:我们的集群有4个节点,每个节点上一块盘,就算有2两个节点宕机,这个集群仍然是可读的,但是,我们需要3个节点才能让集群写数据。这就是为什么我们要有4个节点来构建集群。

在早期版本中,每个租户至少有4个盘,最多有16个盘,这个是纠删码的限制,而新版本中去掉了这个限制。如果想要实现多租户,可以借助于k8s来构建多个MinIO实例,或者启动多个实例来实现多租户。也就是说,一个进程对应一个实例,一个实例对应一个租户。

对象存储系统把存储资源组织为租户-桶-对象的形式。数据结构组织见下图:
在这里插入图片描述
对象:类似于hash表中的表项:它的名字相当于关键字,它的内容相当于“值”。

桶:是若干个对象的逻辑抽象,是盛装对象的容器。

租户:用于隔离存储资源。在租户之下可以建立桶、存储对象。

用户:在租户下面创建的用于访问不同桶的账号。可以使用MinIO提供的mc命令设置不用用户访问各个桶的权限。

从官网和网上的资料中,我们可以了解到MinIO的一些架构方面的知识。

1、去中心化架构

MinIO采用去中心化的无共享架构,对象数据被打散存放在不同节点的多块硬盘,对外提供统一命名空间访问,并通过Web负载均衡器或DNS轮询(DNS round-robin)在各服务器之间实现负载均衡。

在这里插入图片描述
2、统一命名空间

MinIO对象存储系统主要有两种部署方式,一种是常见的本地分布式集群部署,另一种是联盟模式部署。

本地分布式集群部署方式即在多个本地服务器节点部署MinIO软件,并将其组成单套分布式存储集群,并提供统一命名空间和标准S3访问接口。

联盟部署模式即将多个MinIO集群在逻辑上组成了统一命名空间,实现近乎无限的扩展与海量的数据规模管理,这些集群可以都在本地,或分布在不同地域的数据中心。

3、分布式锁管理

与分布式数据库相类似,MinIO对象存储系统也面临数据一致性问题:

一个客户端程序在读取一个对象的同时,另一个客户端程序可能正在修改或者删除这个对象。为了避免出现数据不一致情况,MinIO相关开发人员为MinIO对象存储专门设计并实现了dsync分布式锁管理器。它采用如下分布式锁管理机制:

1  //任何一个节点的锁请求都会广播给集群内所有在线节点;
2  //如果n/2 + 1个节点回应“是”,则成功获得锁;
3  //客户端获得锁以后可保留任意时间,不需要时自己释放即可。
释放操作也会广播给所有的节点,从而恢复锁的可用状态。
写锁仅能被一个写入者获得。

三、搭建MinIO环境(二进制方式)

1、单机安装

1、新建minio安装目录,执行如下命令:


mkdir -p /home/minio/data

2、官网下载minio二进制文件:

下载地址:http://dl.minio.org.cn/server/minio/release/darwin-amd64/minio

也可以在服务器中执行下载命令,过程可能比较慢。

cd /home/minio/data
# 下载 minio 
wget http://dl.minio.org.cn/server/minio/release/linux-amd64/minio
# 添加可执行权限
chmod +x minio

3、开始安装

二进制文件上传到安装目录后,执行:


# 配置密钥
export MINIO_ACCESS_KEY=minioadmin123
export MINIO_SECRET_KEY=minioadmin123
# 开启服务
# 启动minio server服务,指定数据存储目录/mnt/data
./minio server /mnt/data

然后就可以通过上述简单步骤安装和启动minio服务后,minio已开启web客户端操作页面,可通过界面添加文件夹和上传文件等操作,也可通过minio官方提供的客户端,通过命令进行相关操作。

编写服务脚本,其中环境变量为默认账号密码,


[Unit]
Description=Minio Service

[Service]
Environment="MINIO_ROOT_USER=admin"
Environment="MINIO_ROOT_PASSWORD=password"
ExecStart=/opt/minio/minio server /home/minio/data --console-address ":9001"
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
StandardOutput=/opt/minio/minio.log
PrivateTmp=true

[Install]
WantedBy=multi-user.target

开启服务


# 重新刷新
systemctl daemon-reload
# 启动
systemctl start minio.service
# 查看状态
systemctl status minio -l
# 开机自启
systemctl enable minio.service

如果是集群部署的话,可以参考这篇文章操作,这里就不过多介绍了。

https://blog.csdn.net/water1209/article/details/124197957

四、搭建MinIO环境(docker方式)

docker在搭建环境的时候,还是比较简单的。

1、单节点的方式

直接运行实例,首先先安装docker


#Step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
#Step 2: 添加软件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#Step 3: 缓存并安装Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
#Step 4: 开启Docker服务
sudo service docker start
#Step 5: 设置Docker开机自启动
systemctl enable docker
#Step 6: 启动Docker
systemctl start docker
#Step 7: 查看版本
docker --version

在这里插入图片描述
创建挂载文件夹,可以挂载多个Drives

mkdir /home/minio
mkdir /home/minio/data1
mkdir /home/minio/data2
mkdir /home/minio/data3
mkdir /home/minio/data4

可以通过以下命令运行minio,

这里是安装的单节点的,也可以搭建集群的方式,通过nginx做负载


docker run -d -p 9000:9000 \
  -p 9090:9090 \
  --name minio \
  -v /data/minio:/data \
  -e "MINIO_ROOT_USER=minioadmin" \
  -e "MINIO_ROOT_PASSWORD=minioadmin" \
  minio/minio server /data \
  --console-address ":9090" \
  --address ":9000"

在这里插入图片描述
访问ip地址:9090,

 控制台页面访问地址为ip:9090
• api服务地址为:ip:9000
• 使用docker,要注意使用-p命令将端口号进行映射,注意,冒号前面为宿主机端口号,后面为容器端口号
• --name 指的是为容器创建一个名称
• -v 指的是数据挂载,冒号前面为宿主机目录,与冒号后面的容器目录进行绑定,注意以 /开头,表示为相对路径,如果使用绝对路径请注意
• -e 设置容器内的环境变量
• --console-address 控制台地址
• --address api服务地址
• MINIO_ROOT_USER设置用户名
• MINIO_ROOT_PASSWORD设置密码

在这里插入图片描述
可以看到一些指标信息
在这里插入图片描述
2、部署集群的方式

1、前期准备

我特定买了两个服务器来搭建MinIO集群

#1.安装docker 环境
# 安装命令参考上文中的单节点安装中的docker命令
#2.修改两节点本地hosts 如下:vim /etc/hosts
150.158.44.198 minio1
124.223.11.37 minio2

在这里插入图片描述
创建文件夹

mkdir /data/config
mkdir /data/data1
mkdir /data/data2
mkdir /data/data3
mkdir /data/data4

然后两个节点都执行命令


docker  run -d --name minio \
-p 9000:9000  \
-p 9001:9001  \
--restart=always  --net=host \
-e MINIO_ACCESS_KEY=minioadmin \
-e MINIO_SECRET_KEY=minioadmin \
-v /data/config:/root/.minio \
-v /data/data1:/data1 \
-v /data/data2:/data2 \
-v /data/data3:/data3 \
-v /data/data4:/data4 \
minio/minio server http://minio{1...2}/data{1...4} \
--console-address ":9001"

这样的话,集群就搭建完成,访问任意一个节点的9090端口,就可以看到

一共是两个server,每个server有4个Drives。

五、MinIO在BlogCore中的使用

[HttpGet]
 public async Task<FileStreamResult> DownFileMinio([FromServices] IWebHostEnvironment environment, string filename)
        {
            var bucketName = "blogcore";
            var errStream = new MemoryStream(System.Text.Encoding.Default.GetBytes("访问的资源不存在!"));

            try
            {
                string FileTypes = filename.Substring(filename.LastIndexOf('.') + 1).ToLower();
                var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
                var memi = provider.Mappings["." + FileTypes];
                string contenttype = "";
                bool ispic = false;
                // 处理各种文件类型
                Stream filestreamObj = new MemoryStream();
                await MinioHelper.GetInstance().FGetObject(bucketName, filename, null, (stream) =>
                {
                    stream.CopyTo(filestreamObj);
                    filestreamObj.Position = 0;
                    stream.FlushAsync();
                });

                if (ispic) return File(filestreamObj, contenttype);
                else return File(filestreamObj, contenttype, filename);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
                return File(errStream, "application/json");
            }
        }


 [HttpPost]
 public async Task<MessageModel<string>> InsertFileMinio([FromServices] IWebHostEnvironment environment)
        {
            var data = new MessageModel<string>();
            IFormFileCollection files = null;
            try
            {
                files = Request.Form?.Files;
            }
            catch (Exception) { }
            if (files == null || !files.Any()) { data.msg = "请选择上传的文件。"; return data; }
            //格式限制
            var allowType = new string[] { "image/jpg", "image/png", "image/jpeg", "application/pdf",
                "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document","","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };
            FormFile picfile = files[0] as FormFile;
            if (!allowType.Contains(picfile.ContentType))
            {
                data.msg = "只允许上传jpg,jpeg,png,pdf,doc,docx,xlsx类型的文件。"; return data;
            }

            if (picfile.Length >= 1024 * 1024 * 15)
            {
                data.msg = "文件不能超过10M"; return data;
            }

            // 获取附带的数据
            var objName = Request.Form["objName"].ObjToString() ?? "";

            string minioName = await UploadByMinioObjName(picfile.OpenReadStream(), picfile.FileName, picfile.ContentType, objName);

            if (minioName.IsNotEmptyOrNull())
            {
                data = new MessageModel<string>()
                {
                    response = minioName,
                    msg = "上传成功",
                    success = true,
                };
            }
            else
            {
                data = new MessageModel<string>()
                {
                    response = "",
                    msg = "上传出错",
                    success = false,
                };
            }

            return data;
        }


 [HttpDelete]
 [AllowAnonymous]
 public async Task<MessageModel<string>> DeleteFileMinio(string filename)
        {
            var data = new MessageModel<string>();
            try
            {
                var bucketName = "blogcore";
                await MinioHelper.GetInstance().RemoveObject(bucketName, filename);
                data.msg = "删除成功";
                data.success = true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            return data;
        }

六、MinIO的优缺点

1、安装部署(运维简单)

MinIO在安装过程是黑盒的,不用深入关注它的架构,也不需要进行零件组装,基本上可以做到开箱即用。普通的技术人员就能够参与后期的运维。

MinIO提供了两种部署方式:单机部署和分布式,两种部署方式都非常简单,其中分布式部署还提供了纠删码功能来降低数据丢失的风险。

2、丰富的管理UI界面

MinIO自带UI界面,且页面不需要你单独的部署,和服务端一并安装。开箱即用。

3、高性能与云原生

MinIO号称是世界上速度最快的对象存储服务器。在标准硬件上,对象存储的读/写速度最高可以达到183 GB/s和171 GB/s。对象存储可以充当主存储层,以处理Spark、Presto、TensorFlow、H2O.ai等各种复杂工作负载以及成为Hadoop HDFS的替代品。MinIO用作云原生应用程序的主要存储,与传统对象存储相比,云原生应用程序需要更高的吞吐量和更低的延迟。而这些都是MinIO能够达成的性能指标。

4、容器化支持

MinIO 符合一切原生云计算的架构和构建过程,并且包含最新的云计算的全新的技术和概念。其中包括支持Kubernetes 、Docker、微服和多租户的的容器技术。

5、MinIO的缺点

MinIO不支持动态增加节点,MinIO创始人的设计理念就是动态增加节点太复杂,后续会采用其它方案来支持扩容。目前只能是新增节点后手动重启系统才生效,系统会自动平衡数据,这种设计到底对系统后续有什么影响,我觉得使用者需要考虑清楚点。

这里有个方案可以参考下,就是事先准备好一套容量适中且是开启状态的MinIO集群,当业务量陡增、原MinIO集群容量告警时,应用自动启用备份MinIO集群,后续再整合两个集群的文件成一个更大的集群。否则不支持在线动态扩容,确实是个硬伤。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值