编辑: 我有一个诊断中间件组件,可以将响应提取到跟踪文件中。那是罪魁祸首。所以,如果你发现这个是因为你遇到了我遇到的同样问题:检查你的中间件!
因此,在调用 Web API 端点时,我以流式异步方式从各种数据源收集了大量数据(> 100 MB)。我想以流式传输方式将该数据转发给客户端。
为此,我构建了自己的 IActionResultExecutor<T>
概括这一点,因为我们有一些这样的端点。
但是我注意到整个响应在实际发送到客户端之前缓存在内存中。不好。显然,我做错了什么,但我无法理解我做错了什么!
执行者的ExecuteAsync
看起来像这样:
public async Task ExecuteAsync(ActionContext context, AsyncStreamResult result)
{
var bufferingFeature = context.HttpContext.Features.Get<IHttpResponseBodyFeature>();
if (bufferingFeature != null)
bufferingFeature.DisableBuffering();
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
context.HttpContext.Response.ContentType = "application/json; charset=utf-8";
var cancellationToken = context.HttpContext.RequestAborted;
await context.HttpContext.Response.StartAsync(cancellationToken);
await context.HttpContext.Response.WriteAsync("[", cancellationToken);
bool seenFirstItem = false;
await foreach (var item in result.Data) {
if (seenFirstItem)
await context.HttpContext.Response.WriteAsync(",", cancellationToken);
await context.HttpContext.Response.BodyWriter.WriteAsync(item.JsonBytes, cancellationToken);
seenFirstItem = true;
}
await context.HttpContext.Response.WriteAsync("]", cancellationToken);
}
我可以看到整个过程如何在 Visual Studio 中以线性方式分配大量内存。我还可以看到 curl 在请求完成之前没有获取任何数据。然后一切都一气呵成。具有讽刺意味的是,curl 报告数据的传输编码是 chunked
.那是一大块!一些数据流超过 100 MB,仅出于这个原因,我买不起 k8s 集群中的强大 pod。在我看来,这个操作应该生成一堆 Gen 0 对象,但没有什么是 GC 不能处理的。引用的对象应该以千字节为单位!
我试过撒一些 await context.HttpContext.Response.BodyWriter.FlushAsync(cancellationToken)
, 但似乎没有任何区别。
我做错了什么?
最佳答案
问题已解决:我在管道中有一些调试日志记录中间件,它打开缓冲以跟踪发送给客户端的响应。卫生部!
关于c# - 从 ASP.NET Core 3.1 端点流式传输数据而不消耗大量内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61056100/