【问题标题】:How do I increase maximum download size in an MVC application?如何在 MVC 应用程序中增加最大下载大小?
【发布时间】:2017-02-01 15:49:19
【问题描述】:

坦率地说,我很难过。这超出了我的经验。

我有一个 C# MVC 程序,它在 MemoryStream 中生成一个 zip 文件以供下载。通过单击 JavaScript 的按钮调用 action 方法。

唯一的问题是,在某些情况下,潜在的文件大小很容易超过 1 Gig,根据我的阅读,这是一个常见问题。我尝试在 IIS (IIS8) 上的请求过滤中将最大允许内容长度提高到 3000000000。我尝试将 requestLimits maxAllowedContentLength 添加到我的 web.config 中。 我什至尝试通过多次调用 action 方法来分解 zip(没有成功),尽管我还没有得到任何确认/否认这甚至是可能的。

在 IIS 或我的 web.config 中是否有任何我可以忽略的设置?这可能是公司网络问题,无法在应用开发者层面解决吗?

【问题讨论】:

  • 尽管您没有提及您遇到的确切问题,但根据您问题上的标签,我假设您的内存不足。除了在服务器上放置更多 RAM 之外,没有其他解决方案。没有固有的下载限制,但如果你在内存中创建东西,显然它不能大于系统的可用内存。
  • 值得一提的是,您还需要考虑多个请求。例如,如果您要创建一个 1GB 的文件,那么添加 1GB 的额外内存只会帮助一个请求。如果两个人尝试访问创建该 1GB 文件的同一操作,那么您将需要 2GB 的 RAM 来满足这两个请求。将创建的文件缓存到文件系统会有所帮助,因为您只需要用于初始创建的内存,但您应该确保在平均文件大小之上有足够的空间。
  • 我已经向管理层申请了更多内存(但我没有屏住呼吸......)它已经有 8 个演出了。
  • 8GB 对于一个中等规模的网站来说也不算什么。我有一个 32 GB 的站点,甚至没有在内存中做太多明确的事情(即,这只是用于工作线程池的内存)。诚然,我们每月提供超过 100 万的唯一身份,但与许多网站相比,即使这样也相对温和。
  • 一个快速的经验法则是每个工作进程至少应该有 2-4 GB,并且每个离散的 CPU 内核应该有一个工作人员。但是,这只是基本的操作 RAM,如果您明确地在内存中执行操作,那么您将需要额外的 RAM。并且不要忘记操作系统本身,它会在开箱即用的 2-4 GB RAM 上运行。换句话说,如果你有一个工作进程,你可能需要多达 8GB 来处理标准请求,更不用说在内存中做额外的工作了。

标签: asp.net-mvc asp.net-mvc-4 download out-of-memory iis-8


【解决方案1】:

好的,所以很难用 400 个字符或更少的字符来解释大概念,所以我认为我只是在 cmets 部分引起了更多的混乱。此外,我认为我们已经足够接近您可能得到的“答案”了。

MemoryStream 的默认构造函数本质上将初始大小设置为 0。实际上,初始大小设置为 256 左右,但由于初始大小主要是一个参考值,它实际上并没有声称该空间在需要之前,它从 0 开始。

每次写入流时,它都会检查正在写入的内容与缓冲区数组的剩余大小。如果它不适合写入,它会创建一个新的、更大的缓冲区数组并将旧的缓冲区数组复制到其中。通过这种方式,设置初始大小可以有所帮助,因为您从较大的初始缓冲区数组开始,您可能不需要增加该缓冲区。你可能有更好的机会获得一块连续的内存,我稍后会解释它的重要性,但这实际上也对你不利。如果您只需要 1MB 的文件,但您使用 100MB 进行初始化并且没有 100MB 的连续内存,即使可能有 1MB 的连续内存可用,您也会得到 OutOfMemoryException .

无论您是否初始化,都存在一些不可变的事实。首先,MemoryStream 需要连续内存。即使您在技术上在系统上有可用内存,您也可能没有大块可用内存。换句话说,如果您有 4GB 可用空间,但它都是零散的,即使尝试在内存中创建 1GB 流也可能会失败,因为它无法保留 1GB 的连续内存。显然,您要在内存中创建的文件越大,您遇到此问题的机会就越大。 仅出于这个原因,我会说如果没有增加系统 RAM 量,你就很不走运。如果 IIS 实际可用 8GB 并且可能只有 4-6GB,然后在工作进程和线程之间进行拆分,那么您将能够将 25% 左右的可用 RAM 作为连续空间的可能性极小。

下一个不可变的事实可能相关也可能不相关,但由于您没有指定,我会提到它。如果您的 Web 应用程序部署为 32 位,则 any 对象的硬限制为 2GB,这意味着 MemoryStream 永远不能容纳超过 2GB(实际上大约 1.3-1.6GB 为.NET 代码会消耗一些地址空间),任何尝试这样做都会导致OutOfMemoryException,即使您在系统上有一些荒谬的 RAM 量(如 1TB+)。如果您的应用程序是 64 位的,这不太可能是一个问题,因为您可以解决更多的内存,假设它已正确编译。不过,你几乎必须尝试把它搞砸,所以你应该没问题。

最后,多次写入也会导致问题。正如我之前所说,缓冲区数组调整大小(如有必要)以响应写入。每次调整大小时,新的缓冲区数组必须能够适应连续的地址空间。因此,多次调整大小可能会导致您遇到OutOfMemoryException,如果您从一开始就写入了所有数据,您就不会遇到这种情况。这是初始化MemoryStream 可能有用的地方,但正如我之前所说,它也是一把双刃剑,因为您的初始缓冲区大小可能太大而无法开始,您最终会遇到一个您可能没有的异常有一个让它有机地生长。总而言之,尽量一次性将所有内容写入流中,而不是零碎地写入。

【讨论】:

  • 澄清一下,应用程序是使用 Target = Any CPU 编译的。但是,它运行的服务器是 64 位的,并且它运行的应用程序池启用 32 位应用程序 = False。所以我认为我在这方面还可以。至于一次性将所有内容写入流,请澄清。该过程本质上是一个循环,一次添加一个文件。不确定我是否还有其他方法可以做到这一点。
  • 到目前为止完全失败。我的老板将内存提高到 16Gig。然后我尝试了我的程序,无论是否初始化 MemoryStream 大小。两次相同的“算术”错误。
  • 另一件事:堆栈跟踪上的第一条错误消息是:[HttpException (0x80004005): 与远程主机通信时发生错误。错误代码是 0x80070216。] System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 结果,布尔 throwOnDisconnect)IIS7?服务器正在运行 IIS8。
  • 我也尝试将 maxQueryStringLength 添加到 system.web 设置 再次没有运气。
猜你喜欢
  • 1970-01-01
  • 2021-02-06
  • 1970-01-01
  • 2018-05-07
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
相关资源
最近更新 更多