繁体   English   中英

来自 ASP.NET 核心 3.1 端点的 Stream 数据,无需消耗大量 memory

[英]Stream data from an ASP.NET Core 3.1 endpoint without consuming huge amounts of memory

编辑:我有一个诊断中间件组件,可以将响应提取到跟踪文件中。 那是罪魁祸首。 所以,如果你发现这个是因为你有同样的问题:检查你的中间件!

因此,在调用 Web API 端点时,我以流式异步方式从各种数据源收集大量数据(> 100 MB)。 我想以流的方式将该数据转发给客户端。

为此,我构建了自己的IActionResultExecutor<T>来概括这一点,因为我们有一些这样的端点。

然而,我注意到整个响应在实际发送到客户端之前被缓存在 memory 中。 不好。 显然,我做错了什么,但我无法理解我做错了什么!

执行器的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 中以线性方式分配大量 memory。 我还可以看到 curl 没有得到任何数据,直到请求完成。 然后一切都在一个 go 中。 具有讽刺意味的是,curl 报告数据的传输编码是chunked的。 这是一大块,一些数据流超过 100 MB。 仅仅因为这个原因,我在我的 k8s 集群中买不起强大的 pod,在我看来,这个操作应该生成一堆 Gen 0 对象。 但没有什么是 GC 不应该处理的。 引用的对象应该以千字节计算!

我尝试在一些await context.HttpContext.Response.BodyWriter.FlushAsync(cancellationToken)中撒上一些东西,但似乎没有任何区别。

我究竟做错了什么?

问题已解决:我在管道中有一些调试日志中间件,它打开了缓冲以跟踪发送给客户端的响应。 哦!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM