【问题标题】:How to limit per-request memory usage in ASP.NET?如何在 ASP.NET 中限制每个请求的内存使用量?
【发布时间】:2021-04-04 03:59:12
【问题描述】:

我有一个在 ASP.NET 中运行的多租户 .NET 5 应用程序,其中一个请求可以运行任意代码并使用任意数量的内存。如何针对每个请求防止用户使用过多内存?

我知道我可以限制每个进程,也可以限制发出的 HTTP 请求的大小,但这不是我需要的。我需要一种方法,如果用户运行像 int array = int[1,000,000,000,000,000,000,000] 这样的代码,他们会得到一个异常,而不是整个网站都崩溃。

编辑:这是一个 jsfiddle 风格的应用程序(具体来说,它是 darklang.com),虽然使用自定义语言和运行时,所以我可以很好地控制运行时。

【问题讨论】:

  • 这似乎是一个架构设计决策,您应该提前做出,而不是上线!在它自己的应用程序域中运行代码怎么样? stackoverflow.com/questions/1094478/… 。显然 App Domains 不再是一个东西,而是使用 LoadContexts 吗?
  • ...或者可能不是:docs.microsoft.com/en-us/dotnet/api/… :“使用应用程序域来隔离可能导致进程中断的任务。如果正在执行任务的 AppDomain 的状态变得不稳定,则 AppDomain 可以在不影响进程的情况下卸载。当进程必须长时间运行而不重新启动时,这一点很重要"
  • " 如果用户运行代码" 是吧?你不是在谈论开发人员编写代码吗?为什么网络应用程序的最终用户要编写代码?什么样的代码?退后一步,描述您的实际问题。
  • 我假设您正在尝试构建一个 API,允许人们在浏览器中编写代码,将其提交到后端,然后您将动态编译和运行它。就像那些code websites 一样。
  • @JeremyLakeman:以dotnetfiddle 之类的网站为例,说明用户如何“在后端运行代码”。

标签: c# asp.net .net .net-core memory-management


【解决方案1】:

.NET CORE 和 .NET 5

因为问题是关于 .Net Core,所以我必须说明为什么走 AppDomain 路线行不通。

应用程序域

为什么停产? AppDomain 需要运行时支持,而且通常非常昂贵。虽然仍由 CoreCLR 实现,但它在 .NET Native 中不可用,我们不打算在其中添加此功能。

我应该改用什么? AppDomain 用于不同的目的。对于代码隔离,我们推荐进程和/或容器。对于程序集的动态加载,我们推荐新的 AssemblyLoadContext 类。

Source: Porting to .NET Core | .NET Blog

如果您想获得有关内存使用情况的“自动”信息,我们只有一种方法可以做到这一点。

如何测量单独进程的内存使用情况

要测量其他进程内存,我们可以使用Process 句柄并获取它的WorkingSetPrivateMemoryVirtualMemoryMore about memory types

处理另一个进程的代码非常简单。

private Process InterpreterProcess;

// Run every how often you want to check for memory
private void Update()
{
    var workingSet = InterpreterProcess.WorkingSet64;
    if(workingSet > Settings.MemoryAllowed)
    {
        InterpreterProcess.Kill(true);
    }
}

private void Start()
{
    InterpreterProcess = new Process(...);
    // capture standard output and pass it along to user
    Task.Run(() =>
    {
        Update();
        Thread.Sleep(50);
        // This will be also convenient place to kill process if we exceeded allowed time
    });
}

然而,这给我们留下了一个非常重要的问题,因为我们可能允许用户访问系统关键资源——即使我们没有在进程上运行管理员权限。

替代方法

由于您提到您有一个自定义解释器,您可能更容易为解释器添加内存管理、内存计数和安全性。

由于我们可以假设内存分配仅使用 new 进行,您的解释器只需测试每个新分配的大小并进行相应的测试。

要测试托管对象的大小,您需要“分析”创建的实例并在每个简单类型上使用sizeof(),正确的方法是制作There's no way to get the managed object size in memory #24200

【讨论】:

  • “由于我们可以假设内存分配只使用新的,您的解释器只需测试每个新分配的大小并进行相应的测试。” -> 唉,它在 F# 中,所以这里没有 news
  • 所以你只剩下单独的过程方法或等待适当的实施形式 dotnet 团队来获取对象的内存大小
【解决方案2】:

您需要使用进程(在作业对象或 cgroup 中),在 .NET 中的应用程序级别无法做到这一点。

【讨论】:

    猜你喜欢
    • 2010-12-17
    • 2010-12-29
    • 1970-01-01
    • 2015-11-27
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多