.NET Core 应用程序在 Fargate 上运行时出现内存问题。

5

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

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

 resource "aws_ecs_task_definition" "test" {
   ....
   cpu                      = 256
   memory                   = 512
   ....

根据文档,这是Fargate所必需的。

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

我们观察到,在任务启动后,我们的内存会增长,具体取决于应用程序,有时增长得非常快,有时则需要一段时间。

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

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

在我们完成这个操作之后,我们发现我们应用程序中的内存表现要好得多。

从.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会定期发生,内存不会剧烈上升。

所以我们有了一个解决方案,但不理解为什么会这样。希望知道原因。


我想知道.NET运行时是否会使用这些容器级内存设置,并根据这些值对内存分配或垃圾回收器进行不同的处理。这是我能想到的唯一解释。 - undefined
1个回答

0
可能会对以后的参考有用,我们花了一些时间来弄清楚这个问题。
描述的行为发生是因为.NET(目前)无法理解所有可能的cgroups设置。
当您在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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接