因为某些原因,需要对静态资源文件进行鉴权或代理转发,鉴权需要和业务系统用户权限关连,转发是因为要访问的文件并非是存储在服务器本地磁盘上的实体文件(文体存储在对象存储或数据库中)。
测试发现,用接口返回文件的方式,性能非常差,没有任何逻辑的代码,返回速度也不快,关键是频繁访问还偶尔有返回错误的情况。
不知道园友们是怎么解决类似的问题的。
我们系统的小图片,视频文件特别多,一天要接受好几十万张,大多图片都是20K左右,视频文件在4M左右。
先前是直接存储在磁盘上,用静态文件访问的,现在逐步迁移到对象存储中(云和MinIO都有)。
目前发现性能问题暂时只有将对象存储设置为公开,MinIO设置为公开后用nginx代理性能还不错,但云上的对象存储设置为公开还需要更改客户端的访问地址(考虑到兼容性问题和客户端版本太多,这个方案不能接受)。
这个是先前测试用的代理图片的接口代码
现在的对象存储很多都是Amason S3驱动兼容的,获取对象返回的Stream都是通过委托回调的方式(using 自动关闭的),另一边 asp.net core context.Response 返回流也是 using 自动关闭的,这样不得不进行一次两个流之间的内容拷贝过程。
不知道这个是不是性能瓶颈的原因?
首先,您可能希望优化提供文件的方式。一种选择是使用内容交付网络(CDN)将文件分发到世界各地的多个服务器,从而减少服务器负载并提高性能。另一种选择是使用缓存机制将频繁访问的文件存储在内存中,从而减少访问文件系统的需要并提高性能。
其次,您可能需要考虑使用不同的方法来提供文件。您可以考虑使用web服务器(如Apache或Nginx)直接为文件提供服务,而不是使用API返回文件。这可能比使用API更快、更高效,尤其是对于大型文件。nginx也可以鉴权,鉴权url与返数据url分开。
最后,您可能需要优化检索文件的代码。您提供的代码使用MinIO库异步检索文件,但是没见到使用buffers缓存数据。参考以下示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VideoFileServer
{
class Program
{
static void Main(string[] args)
{
// 初始化MinIO
MinIO minIO = new MinIO();
minIO.Init();
// 获取视频文件
VideoFile videoFile = new VideoFile();
videoFile.Get(minIO);
// 断开连接
minIO.Disconnect();
}
}
// MinIO类
class MinIO
{
public void Init()
{
// 初始化MinIO
}
public async Task GetObjectAsync(string bucketName, string objectName, Action<System.IO.Stream> action)
{
// 获取视频文件
await Task.Delay(1000);
action(new System.IO.MemoryStream(Encoding.UTF8.GetBytes("This is a video file.")));
}
public void Disconnect()
{
// 断开连接
}
}
// 视频文件类
class VideoFile
{
public void Get(MinIO minIO)
{
// 获取视频文件
for (int i = 0; i < 100000; i++)
{
Task.Run(async () =>
{
await minIO.GetObjectAsync("attachfile", "video.mp4", async (stream) =>
{
byte[] buffer = new byte[4096];
int bytesRead;
do
{
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
} while (bytesRead > 0);
});
});
}
}
}
}
前面没有提到,我们系统客户端访问特点是随机性强,使用缓存可能没有什么作用,只有及其个别的情况下才会二次请求。
使用场景是,用户可能一下打开一个图片列表页面,一个页面上就有几百上千张图片,但大多数时候用户不会点开看,所有缓存利用率不高。
可以理解为就是要实现百度图片那总效果,根据关词匹配图片用户列表显示,用户可以点击查看大图。
另外,我们不是互联网应用,内容不是公开的,需要鉴权(隔离),每个客户只能访问自已的内容,CDN对我们也没多大用处。nginx鉴权涉及到改客户端不能采用,前面有提到过。
@Adming: 可以明确的是,大量的并发请求,api处理不过来,是卡顿报错的原因;1.先修改一下buffer参数,不加buffer参数,默认就是一次线程读取整个文件4m大小;加了buffer就是一次线程读取4k大小;2.通过redis与consul增加api服务,负载均衡处理;3.在可能的地方记日志,见到错误提示不要猜,盲改是浪费时间;4.自己写测试代码进行压力测试,模拟几十万次请求,看看你的api能承受的响应极限是多少(超过会频繁报错),超过极限必须增加api并行处理
dotnet core 有个中间件可以针对接口进行压缩gzip https://learn.microsoft.com/zh-cn/aspnet/core/performance/response-compression?view=aspnetcore-6.0