在 Fargate 上运行的 .NET Core 应用程序存在内存问题

Noe*_*oel 5 garbage-collection .net-core asp.net-core aws-fargate

我们正在通过 terraform 在 Fargate 中运行 .NET 应用程序,其中我们在aws_ecs_task_definition资源中指定 CPU 和内存。

该服务只有 1 个任务,例如

 resource "aws_ecs_task_definition" "test" {
   ....
   cpu                      = 256
   memory                   = 512
   ....
Run Code Online (Sandbox Code Playgroud)

从文档来看,这是 Fargate 所必需的。

您还可以在container_definitions中指定cpu和内存,但文档指出该字段是可选的,并且由于我们已经在任务级别设置值,所以我们没有在此处设置它们。

我们观察到,任务开始后,我们的记忆力在增长,具体取决于应用程序,有时非常快,有时则需要一段时间。

因此,我们开始认为存在内存泄漏,并使用 dotnet-monitor 工具作为 sidecar 进行分析。

作为引入 sidecar 的一部分,我们在 container_definitions 级别为 .NET 应用程序设置了 cpu 和内存值。

完成此操作后,我们发现应用程序中的内存表现得更好。

从.NET监视器跟踪中我们看到,当我们在container_definitions级别设置内存时:

  1. 工作集要小得多
  2. Gen 0/1/2 GC 计数高于 1(GC 发生较早)
  3. GC 0/1/2 尺寸较小
  4. GC 提交字节数较小

总结一下,当我们不在container_definitions级别设置内存时,内存会继续增长并且不会发生GC,直到我们几乎耗尽内存为止。

当我们在container_definitions级别设置内存时,GC会定期发生,并且内存不会激增。

所以我们有一个解决方案,但不明白为什么会出现这种情况。想知道为什么会这样

Ale*_*min 1

可能对将来的参考有用,我们花了一些时间来解决这个问题。

发生所描述的行为是因为 .NET(尚)无法理解所有可能的 cgroup 设置。

当您在 ECS 中的任务级别设置内存限制时,AWS 使用名为 hierarchical_memory_limit 的东西,.NET 不知道它 - 因此可用堆大小估计不正确。当您在容器级别设置它时,它会使用 .NET 正确理解的(不同的)cgroups 旋钮。

如果您不想在容器级别指定内存限制,另一种解决方法是使用 GCHeapHardLimit 配置设置来告诉 .NET 可用内存量(将其设置为容器内存限制的 80% 之类的值以考虑其他内存使用情况) 。

关于它的一篇不错的博客文章:https://aws.amazon.com/blogs/developer/configuring-net-garbage-collection-for-amazon-ecs-and-aws-lambda/

相关问题的一些链接: https://github.com/dotnet/runtime/issues/83563 https://github.com/dotnet/runtime/issues/82815