簡體   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