【问题标题】:Golang Run GC on OOMGolang 在 OOM 上运行 GC
【发布时间】:2021-03-09 12:50:24
【问题描述】:

golang 遇到 OOM 时是否会运行 GC 并重试分配?
我们面临一个问题,即 kubernetes pod(运行 go 代码)在处理大文件时被 OOM Killed。

go 代码处理许多文件,逐行读取它们并为它解析的每一行(通过创建解析的结构分配一些内存 - 循环中的局部变量),如果匹配某些条件,则将其插入数据库。 这是为多个客户端同时运行的。 这适用于许多具有小文件的客户端。但是当它遇到客户端的大文件时,它就会 OOM。

我们让系统运行了很长时间,没有发现任何内存泄漏。甚至 pprof 分析也表明没有内存泄漏。

【问题讨论】:

  • GC 不会释放内存,它只能重用它。您无法从进程中判断何时内存不足,这取决于系统。如果你不能再分配任何东西,你无论如何都不能运行 GC。
  • 不,OOM 杀手只是杀死一个进程。没有事先的“警告”。如果在 Go 中分配内存失败,也会选择“否”。

标签: go garbage-collection


【解决方案1】:

OOM 杀手是内核在面临内存压力时的最后手段。 “要么我现在牺牲一个进程,要么整个系统变得无法使用。”

因为这是最后的手段(例如,内核会在调用 OOM 杀手之前很久就选择减少可用于文件系统缓存的内存量)选择被牺牲的进程在这个和那里没有发言权没有预警1

在您的情况下,您可能没有用完物理内存,而是达到了用户定义的容器内存限制。但是内核也使用相同的工具来强制执行此限制。

您必须提高内存限制以应对最坏情况下的工作负载,或提高程序的内存消耗以保持在其限制范围内。

鉴于小文件可以正常工作,因此您没有适当地限制并发性是理所当然的。如果你一次为每一行生成一个 goroutine,就内存使用而言,读取整个文件没有根本区别。 Concurrency can be easily limited with a semaphore


  1. 您可以将 SIGKILL 更改为 SIGTERM,但这对您没有帮助。如果您将 SIGTERM 的含义从“退出”更改为“向操作系统释放一些内存但继续运行”,您的运维团队会讨厌您。并不是说 Go 无论如何都可以这样做。

【讨论】:

  • 并发是多个客户端,而不是文件的每一行。客户端通常会拥有 40-50 个文件,每个文件在我们处理的每个窗口中大约有 10k 行。我们尝试在每处理 1000 行后显式添加 runtime.GC(),我们看到大文件也可以正常运行。似乎我们需要以某种方式调整 GC 设置?
  • @Pratham:您可以使用 GOGC 环境变量调整 GC,但这只能延迟下一个稍大的文件加载到内存中时不可避免的情况,或者加载速度稍快一些。您需要通过其他方式限制内存消耗。
猜你喜欢
  • 2021-02-08
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 2014-06-04
  • 1970-01-01
  • 2012-08-05
相关资源
最近更新 更多