写点什么

.net core 集成 Minio,构建一个文件存储的基础设施

作者:为自己带盐
  • 2024-09-25
    河北
  • 本文字数:3973 字

    阅读完需:约 13 分钟

.net core集成Minio,构建一个文件存储的基础设施

背景

先简单介绍下 MinIO 吧,官方给的介绍是它是一种高性能、S3 兼容的对象存储。它专为大规模 AI/ML、数据湖和数据库工作负载而构建,并且它是由软件定义的存储。不需要购买任何专有硬件,就可以在云上和普通硬件上拥有分布式对象存储。


MinIO 拥有开源 GNU AGPL v3 和商业企业许可证的双重许可。


翻译一下,就是好使,能白嫖,能私有化部署。


这里提到的 S3,是亚马逊提供的对象存储服务,S3 兼容性是云原生应用程序的硬性要求,像国内流行的阿里云对象存储(OSS),腾讯云对象存储(COS),都是兼容 S3 的。


之所以要搭建私有化的对象存储服务,主要考虑是 2 个,一是原始的文件存储方案并不安全,也不能实现高可用,而且在使用场景上有很多局限,比如某个资源想要增加访问权限,或者想定期删除,又或者想使访问权限定期关闭,那就要在代码层面增加很多逻辑,非常不友好。而使用 MinIO 的话,这些都会变得非常简单。


在一个考虑是因为 MinIO 的可扩展性非常强大,且提供了丰富的 API 接口,只要条件允许,我甚至很方便的可以自建一个无限大的云存储服务出来,配合 CDN 等边缘加速技术,可以高效支撑团队内几乎所有涉及文件存储和访问的场景。


真正建立属于自己团队的存储基础设施。

安装

MinIO 的安装过程,官方文档(https://min.io/)上有非常详细的说明,我这里还是简单的镜像一下。


官方文档里,分别提供了 Kubernetes,Docker,Linux,macOS,Windows,5 种环境的安装方案,我使用过 docker,Linux,windows 这三种,这里就贴一下 Linux 的安装方案,还是在 WSL2 环境下。


  • 下载文件


wget https://dl.min.io/server/minio/release/linux-amd64/archive/minio_20240913202602.0.0_amd64.deb -O minio.debsudo dpkg -i minio.deb
复制代码


  • 启动服务


mkdir ~/miniominio server ~/minio --console-address :9001
复制代码


启动完成后,我们会看到这样的界面⬇️



其中,webui 给出的链接是可以直接访问的



输入控制台给出的账号密码,就可以登录进去了。


注意,这里介绍的这是基于开发或者测试环境的快速部署方案,如果要在生产环境中来部署 MinIO 集群,那不是本文讨论的范围,感兴趣的可以参照官方文档的详细说明。


传送门👉:https://min.io/docs/minio/linux/index.html

对接

安装 SDK

找一个测试项目或者新建个项目,安装上 MinIO 的 sdk。


我这里还是用的上次的测试项目,项目文件长这样⬇️


  <ItemGroup>    <PackageReference Include="Dapper" Version="2.1.35" />    <PackageReference Include="DotNetCore.CAP" Version="8.2.0" />    <PackageReference Include="DotNetCore.CAP.Dashboard" Version="8.2.0" />    <PackageReference Include="DotNetCore.CAP.Kafka" Version="8.2.0" />    <PackageReference Include="DotNetCore.CAP.PostgreSql" Version="8.2.0" />    <PackageReference Include="Minio" Version="6.0.3" />  </ItemGroup>
复制代码

注入服务

引入 sdk 后,在配置文件中增加一个类似这样的配置,如果是测试阶段在代码中直接配置也行。


"MinioSettings": {  "Endpoint": "{宿主机分配给wsl的ip}:9000",  "AccessKey": "在minio面板中获取",  "SecretKey": "在minio面板中获取",  "UseSSL": false}
复制代码


这里面用到的 accessKey 和 secretKey,涉及到访问权限,如果你了解过 AWS 的 IAM 相关知识点,就一目了然了。


这里我们不讨论这个话题,直接去获取相关的配置信息



在这个页面去创建这样一个 access key 即可。


或者我们也可以到 Identity 栏目,配置用户信息,用户组,组权限等信息,也可以生成一个更加具体的 access key。




补充完配置信息后,就可以去项目中注入服务了。


关键代码如下


var minioSetting = builder.Configuration.GetSection("MinioSettings").Get<MinioSettings>();builder.Services.AddMinio(x =>{    x.WithEndpoint(minioSetting.Endpoint)    .WithCredentials(minioSetting.AccessKey, minioSetting.SecretKey)    .WithSSL(minioSetting.UseSSL)    .Build();});
复制代码


这里,因为我们是在测试阶段,SSL 协议可以先关掉,降低一些心智负担。

编写接口

服务注入完成后,就可以来编写一个测试接口了。


这里为了方便,我直接创建了一个支持分片上传的接口。


[HttpPost]public async Task<IActionResult> Upload(FilePartModel model){    try    {          if (model.file == null || model.file.Length <= 0)            return BadRequest("No file found.");        await CreateBucketIfNotExists(model.bucket);
using (var stream = model.file.OpenReadStream()) { await _minioClient.PutObjectAsync(new PutObjectArgs() .WithBucket(model.bucket) .WithObject(model.savedFileName) .WithContentType(model.contentType) .WithObjectSize(stream.Length) .WithStreamData(stream)); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"{model.savedFileName} is uploaded successfully"); Console.ForegroundColor = ConsoleColor.White; } if (model.merged) { var listArgs = new ListObjectsArgs() .WithBucket(model.bucket) .WithPrefix(model.uploadId) .WithRecursive(true) .WithVersions(false);
using (var mergedStream = new MemoryStream()) { await foreach (var obj in _minioClient.ListObjectsEnumAsync(listArgs).ConfigureAwait(false)) { var partStream = await _minioClient.GetObjectAsync(new GetObjectArgs() .WithBucket(model.bucket) .WithObject(obj.Key) .WithCallbackStream((stream) => { stream.CopyTo(mergedStream); }));
await _minioClient.RemoveObjectAsync(new RemoveObjectArgs() .WithBucket(model.bucket) .WithObject(obj.Key));
}
// 将合并后的流写入到MinIO mergedStream.Seek(0, SeekOrigin.Begin); await _minioClient.PutObjectAsync(new PutObjectArgs() .WithBucket(model.bucket) .WithObject(model.savedFileName) .WithContentType(model.contentType) .WithObjectSize(mergedStream.Length) .WithStreamData(mergedStream)); } }
var respData = new FileResponseDto() { fileIndex = model.chunkIndex, Completed = model.completed, path = "未完成", }; if (model.completed) { // 上传完成后返回一个临时的访问链接,有效期24小时 PresignedGetObjectArgs args = new PresignedGetObjectArgs() .WithBucket(model.bucket) .WithObject(model.savedFileName) .WithExpiry(60 * 60 * 24); string temporaryUrl = await _minioClient.PresignedGetObjectAsync(args); respData.path = temporaryUrl; } return Json(_resp.success(respData, "上传成功")); } catch (Exception ex) { Console.WriteLine($"Failed to upload part {model.chunkIndex} to MinIO: {ex.Message}"); } return Json(_resp.error("上传失败"));}
复制代码


简单说明一下,我这里因为是测试,所以分段代码和合并代码的逻辑写到了一起,实际情况中,可以引入一些其他的流程或方法来拆解这个接口。比如,上传分段文件是一个单独的接口,合并文件又是一个单独的接口,还可以引入缓存或者队列结构,当文件上传完成后,发布一个事件,来完成一些数据库的写入业务等等。

编写前端代码

关于大文件上传的前端代码,市面上有很多方案,也可以使用 js 的原生技术来实现,这里由于逻辑点较多,不在赘述前端部分的实现。


我个人也曾在 2021 年的博客中聊到过大文件的上传,传送门👉:https://xie.infoq.cn/article/0eef4205691cd0f503e1dc2c5

效果

这是上传文件的效果


再看下 minio 面板上的传输记录


总结

至此,在开发环境下,就完成了一个简单的,支持各种文件上传的功能。


在系统内部搭建一个基于 MinIO 的存储集群可以带来多个方面的优势,包括但不限于以下几点


  1. MinIO 支持多租户架构,可以配置为高可用(HA)模式,意味着即便某个节点出现问题,系统仍可以继续运行而不丢失数据,这是传统的文件存储方式无法比拟的。

  2. MinIO 设计用于高性能存储,支持对象存储协议如 S3 API,可以提供高速的数据访问速度。对于需要快速读写大量数据的应用场景来说,这是一个重要的优点。

  3. MinIO 支持水平扩展,可以通过增加更多的节点来扩展存储容量和吞吐量。

  4. 相比于使用第三方云服务提供商的服务,自己搭建 MinIO 集群可能会更经济实惠,尤其是当数据量非常大或者有特定的安全性和合规性要求时

  5. 自建存储集群可以更好地控制数据的位置和安全性,这对于需要遵守严格数据保护法律或行业标准的企业来说是一个关键因素

  6. 自己管理存储集群允许对环境进行深度定制,以满足特定的工作负载需求或者集成现有的工具和技术栈。


好了,基本就这样了。


发布于: 刚刚阅读数: 6
用户头像

学着写代码 2019-04-11 加入

是一枚,热爱技术,天赋不高,又有点轴,的猿。。

评论

发布
暂无评论
.net core集成Minio,构建一个文件存储的基础设施_.net core_为自己带盐_InfoQ写作社区