调试虚拟化/容器化环境非常困难

One of the customers using Plumbr APM was recently facing a peculiar issue in their production environment where one of the Docker containers in production exited with the exit code 137. The setup of the environment was fairly simple

  • 具有Ubuntu OS的自托管硬件;多个Docker容器也运行在计算机上运行的Ubuntu OS在Docker容器中运行的Java虚拟机。

Investigating the issue led us toDocker documentation on the topic. Reading this made it clear that the cause for this exit code is either manual docker stop command or out of memory condition coupled with subsequent kill signal sent by the kernel’s oomkiller.

仔细查看系统日志,确认确实触发了硬件上部署的OS内核的杀手::

[138805.608851] java invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=0
[138805.608887] [<ffffffff8116d20e>] oom_kill_process+0x24e/0x3b0
[138805.608916] Task in /docker/264b771811d88f4dbd3249a54261f224a69ebffed6c7f76c7aa3bc83b3aaaf71 killed as a result of limit of /docker/264b771811d88f4dbd3249a54261f224a69ebffed6c7f76c7aa3bc83b3aaaf71
[138805.608902] [<ffffffff8116da84>] pagefault_out_of_memory+0x14/0x90
[138805.608918] memory: usage 3140120kB, limit 3145728kB, failcnt 616038
[138805.608940] memory+swap: usage 6291456kB, limit 6291456kB, failcnt 2837
[138805.609043] Memory cgroup out of memory: Kill process 20611 (java) score 1068 or sacrifice child

从该日志摘录中可以看出,Java进程正在接近3145728kB(约3GB)的限制,从而触发了Docker容器的终止。 这很奇怪,因为Docker本身是在docker-compose文件中以4GB的限制启动的。

您可能知道,JVM还限制了其内存使用。 虽然在docker-compose文件中将Docker本身配置为4GB限制,但JVM是使用Xmx = 3GB启动的。 这可能会引起更多的混乱,但请注意,如我们之前分析JVM内存使用情况的一篇文章中所述,手头JVM的内存使用情况可能会超过-Xmx指定的限制。

了解所有这些使我们仍然感到困惑。 应该允许Docker提供4G内存,那么到底为什么OOMkilled已经达到3GB? 进一步的谷歌搜索显示,直接部署在硬件上的OS还涉及更多内存限制。

向cgroup打个招呼。 cgroups(又名控制组)是一种Linux内核功能,用于限制,管理和说明一组进程的资源使用情况。 与其他方法(“ nice”命令或/etc/security/limits.conf)相比,cgroup具有更大的灵活性,因为它们可以在一组(子)进程集上进行操作。

在我们的情况下,cgroup将内存使用量(通过memory.limit_in_bytes)限制为3GB。 现在我们到了某个地方!

使用Plumbr对内存利用率和GC事件的检查显示,运行在Docker中的JVM的大部分时间内存利用率约为700MB。 唯一的例外发生在终止事件之前,内存分配达到峰值。 尖峰之后是长时间的GC暂停。 因此,似乎正在发生的事情是:

  • 在JVM中运行的Java代码试图分配大量内存。JVM在检查是否有足够的内存要使用以低于3GB Xmx限制后,要求操作系统提供更多内存。Docker验证了在其4GB限制以下有足够的内存可供使用,并且没有实施任何限制。OS内核验证了已达到3GB的cgroup内存限制,并杀死了Docker容器。JVM进程与Docker容器一起被杀死,然后它才能执行自己的OutOfMemoryError过程。

了解了这一点,我们调整了所涉及组件的所有内存限制-Docker为2.5 GB,Java为1.5GB。 完成此操作后,JVM能够执行OutOfMemoryError操作并抛出其OutOfMemoryError。 这使Plumbr终于发挥了魔力–通过相关的堆栈转储捕获内存快照,并迅速公开了一个数据库查询,该查询在某些情况下试图下载几乎整个数据库。

Take-away

即使在这样简单的部署中,也会涉及三个不同的内存限制

  • 通过-Xmx参数的JVMDocker通过docker-compose参数通过memory.limit_in_bytes cgroups参数的操作系统

因此,每当您遇到一个进程被OOM杀手杀死时,就需要注意所有相关控件的内存限制。

另一个收获是针对Docker开发人员。 在嵌套的Docker容器内存限制设置为高于cgroups内存限制的情况下,允许启动此类“ Matryoshkas”似乎没有任何意义。 如果在容器启动时检查此语句以及启动时发出警告消息,这似乎很简单,那么将来可以为用户节省数百个调试时间。

from: https://dev.to//ivomagi/debugging-virtualised-containerised-environments-is-hard-onb

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值