在容器中的Ruby OOM
最近我们遇到了一个Docker容器中的Ruby问题。 尽pipe负载很低,应用程序往往会消耗大量的内存,并在经过一段时间的下载负载OOMs。
经过一番调查,我们把问题缩小到一线
docker run -ti -m 209715200 ruby:2.1 ruby -e 'while true do array = []; 3000000.times do array << "hey" end; puts array.length; end;'
在一些机器上,它在开始后不久就被OOM杀死了(因为超出限制而死亡),但是在一些机器上,虽然缓慢,但没有OOM。 似乎(似乎只是,也许不是这样)在一些configurationruby能够推断cgroup的限制,并调整它的气相色谱。
testingconfiguration:
- CentOS 7,Docker 1.9 – OOM
- CentOS 7,Docker 1.12 – OOM
- Ubuntu 14.10,Docker 1.9 – OOM
- Ubuntu 14.10,Docker 1.12 – OOM
- MacOS X Docker 1.12 – 没有OOM
- Fedora 23 Docker 1.12 – 没有OOM
如果你看看ruby进程的内存消耗情况,在所有情况下,它的performance都与这张图片类似,保持在稍低于极限的相同水平,或者崩溃到极限并被杀死。
内存消耗情节
我们希望不惜一切代价避免OOM,因为它会降低弹性并且会造成数据丢失的风险。 内存真正需要的应用程序是低于极限。
你有什么build议,如何做ruby,以避免OOMing,可能是因为失去了性能?
我们无法弄清楚testing装置之间的显着差异。
编辑:更改代码或增加内存限制不可用。 第一个是因为我们用我们无法控制的社区插件来运行,第二个是因为它不能保证我们将来不会再面对这个问题。
你可以尝试通过环境variables来调整 ruby垃圾回收(取决于你的ruby版本):
RUBY_GC_MALLOC_LIMIT=4000100 RUBY_GC_MALLOC_LIMIT_MAX=16000100 RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=1.1
或通过GC.start
调用垃圾回收GC.start
对于你的例子,尝试
docker run -ti -m 209715200 ruby:2.1 ruby -e 'while true do array = []; 3000000.times do array << "hey" end; puts array.length; array = nil; end;'
帮助垃圾收集器。
编辑:
我没有与你相似的环境。 在我的机器上(14.04.5 LTS,docker 1.12.3,RAM 4GB,Intel(R)Core TM i5-3337U CPU @ 1.80GHz),以下看起来很有希望。
docker run -ti -m 500MB -e "RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=1" \ -e "RUBY_GC_MALLOC_LIMIT=5242880" \ -e "RUBY_GC_MALLOC_LIMIT_MAX=16000100" \ -e "RUBY_GC_HEAP_INIT_SLOTS=500000" \ ruby:2.1 ruby -e 'while true do array = []; 3000000.times do array << "hey" end; puts array.length; puts `ps -o rss -p #{Process::pid}`.chomp.split("\n").last.strip.to_i / 1024.0 / 1024 ; puts GC.stat; end;'
但每个ruby应用程序需要一个不同的设置微调,如果你遇到内存泄漏,你的丢失。
我不认为这是一个docker问题。 你过度使用容器的资源,一旦你达到内存阈值,Ruby往往performance不好。 它可以是GC,但是如果另一个进程试图占用一些内存,或者Ruby在最大输出时尝试重新分配,那么内核将(通常)以最大内存来终止进程。 如果您担心服务器上的内存使用率,请在80%的RAM上添加一些阈值警报,并为作业分配适当大小的资源。 当您开始达到阈值时,分配更多的RAM或查看特定的作业参数/分配,以查看是否需要重新devise以降低占用空间。
另一个可能的select,如果你真的想有一个很好的固定的内存带到GC反对是使用JRuby和设置JVM最大内存留在容器内存一个小摆动的空间。 JVM将更好地pipe理OOM,因为它不会与其他进程共享这些资源,也不会让内核认为服务器正在死亡。
我在一个Docker主机上运行的一些基于java的Docker容器也有类似的问题。 问题是每个容器看到了主机的全部可用内存,并假定它可以为自己使用所有的内存。 它不经常运行GC,最终导致内存exception。 我结束了手动限制每个容器可以使用的内存量,我不再有OOMs。 在合作者内部,我也限制了JVM的内存。
不知道这是否是你看到的相同的问题,但它可能是相关的。
https://docs.docker.com/engine/reference/run/#/runtime-constraints-on-resources
- 无法使用AWS Java API读取图像的LABEL键和特定图像的值
- 如何将Docker容器连接到本地networking
- 错误:tornado.general:WebSocket … Swampdragon:DoesNotExist:匹配查询不存在
- 为什么部署在Docker容器上的Spring云Netflix应用程序需要明确设置eureka.instance.hostname?
- docker群生产
- .Net – 将日志从Web应用程序推送到运行Fluentd的Docker容器
- Docker中使用入口点的节点webservice失败,但在其他情况下工作
- Docker永久存储跨主机?
- capitrano是否与docker冲突?