我正在用这个问题撞墙。我们正在并行运行许多容器,它们正在运行简单的文件系统操作或简单的linux命令,并且其中某些在某些情况下会因内存分配问题而失败,Docker容器会出现OOMKiled。
我认为它与特定命令无关。 tail
不是唯一失败的命令,我们还遇到过cp
或gzip
。
我们已经缩小了问题的范围,并创建了一个脚本,当根据基础系统对参数进行相应调整时,该脚本几乎肯定会失败。
https://github.com/keboola/processor-oom-test
使用默认设置的脚本会生成一个随机的CSV,包含100M行(〜2.5GB),将其复制20次,然后运行20个运行tail -n +2 ...
的容器。在具有1TB SSD的m5.2xlarge
AWS EC2实例上,某些容器被OOMKilled(某些容器以不同的错误结束)。进程因各种错误而终止:
/code/tail.sh: line 2: 10 Killed tail -n +2 '/data/source.csv' > '/data/destination.csv'
tail: error reading '/data/source.csv': Cannot allocate memory
tail: write error
(最后一个不是OOMKilled)
我不知道tail
应该消耗任何内存。如果可以同时工作的容器数量足够少,则可以轻松使用64MB的内存。对于更大数量的容器,即使256MB内存也不够用。我一直在看htop
和docker stats
,还没有看到内存消耗的任何峰值。
我们已经尝试过的事情
其中一些只提供了部分帮助。调整内存限制或容器数量会使它每次都再次崩溃。我们有一个带有1GB内存的容器,该容器在OOMKilled导致大文件崩溃时运行简单的tail
。
关于几个月前我尝试过的工作的进一步说明-https://500.keboola.com/cp-in-docker-cannot-allocate-memory-1a5f57113dc4。而且--memory-swap
只是部分帮助。
有什么建议吗?我不是Linux专家,所以我可能缺少一些重要的东西。任何帮助或建议,我们将不胜感激。
答案 0 :(得分:1)
似乎您对“写入缓存大小”有疑问。
要向磁盘写入内容时,它不是直接写入,而是存储在写入缓存中(称为dirty_pages)。这是因为所有进程都不必等到获得特权才能写入磁盘并继续工作时才等待。但是,如果该过程很长时间没有权限写入磁盘,则它的写缓冲区开始增长,直到达到为容器定义的内存限制。然后它被码头工人杀死。
有一个名为pdflush
的守护程序,该守护程序负责刷新缓存并将这些dirty_pages写入磁盘。我认为您正在明确地寻找参数vm.dirty_bytes
和vm.dirty_background_bytes
。这两个参数在Difference between vm.dirty_ratio and vm.dirty_background_ratio?中有很好的描述。
例如,如果您正在使用内存限制--memory=128M
,并且容器一次仅运行一个进程,则vm.dirty_bytes
的字节数不得超过128M。 vm.dirty_background_ratio
(可以选择设置比率[占总内存的百分比]或确切的字节数)取决于您同时运行的容器数。该值对您而言并不重要,您可以将其设置为10到15之间的一个值。
要设置这些变量,请使用sysctl -w
。对于您的情况,应为:
sysctl -w vm.dirty_bytes=134217728
sysctl -w vm.dirty_background_ratio=15
希望这会有所帮助!
答案 1 :(得分:0)
我没有评论代表,所以这里有一个答案的猜测!我们遇到了类似的问题,事实证明,磁盘内存不仅仅是您总共使用了多少空间-还有称为inode的东西,它们具有单独的有限数量,例如node_modules(在js中)或任何形式的大文件小文件库,甚至可能还有日志文件,都可以真正吞噬您的inode。
尝试在命令行中键入此命令(假设您使用的是Linux或Mac)
df -ih
如果您的根目录(位于/上)的IUse为99%,那就是您的问题。您可能会拥有一堆陈旧的Docker卷,其中包含成千上万个文件,它们占用了您的所有空间。
Linux经常建议为根(/)设置一个小容量(20G),然后为/ home设置一个大容量,以适合您的所有小猫等个人照片。但是,除非另行说明,Docker会放置所有数据在根挂载中,因此您可以非常快速地将其填满,并且仍然看起来像服务器上剩余的空间!通常,这在专业服务器上并不重要,但是请记住这一点。