容器中的Java与内存限制:LXC、Docker与OpenVZ

译文
开发 后端 前端
Matt Willaims提起的Docker内Java及其内存限制的议题得到了广泛关注,而这些在容器使用当中无法避免的状况也在Twitter上引发一系列讨论。除了Jelastic之外,大家也可以根据Matt的提示始终为JVM指定heap大小而非依赖于启发机制。

开发者在使用JVM、内存与Docker时是否遭遇到难题?今天我们将一同利用Jelastic将其解决。最近Matt Willaims提起的Docker内Java及其内存限制的议题得到了广泛关注,而这些在容器使用当中无法避免的状况也在Twitter上引发一系列讨论。

那么在今天的文章中,我们就来共同分析这一问题并尝试找出解决办法。

问题

Matt讲述了他在Docker容器内使用JVM heap时的探索之旅。他指出,容器对于内存的限制未能正确显示,这导致任意Java或其它应用都可分配给该主机设备的全部内存资源,而JVM却无法指示其中有多少资源应该专门用于其运行所在的父容器。如此一来,OutOfMemoryError开始出现。

事实上,大多数Linux工具所提供的系统资源指标在创建时间上要早于cgroups(例如free与top,二者皆源自procps)。其通常会从proc文件系统:/proc/meminfo,/proc/vmstat, /proc/PID/smaps或者其它位置处读取内存指标。

遗憾的是,/proc/meminfo, /proc/vmstat及其它位置无法实现容器化,也就是其无法为cgroup所识别。其只能显示主机系统(物理或虚拟机)的整体内存容量,而现代Linux容器技术无法对其加以利用。容器中的流程无法依靠free、top及其它指标确定所能使用的内存容量;其必须遵循cgroups提供的约束条件,且无法使用主机系统中的全部内存。

事实上,实际内存限制条件的可见性非常重要,我们需要利用其实现应用优化及故障排查,例如内存泄露、交换空间使用、性能下降等等。另外,某些用例还需要利用垂直伸缩以实现容器内的资源使用优化,包括自动变更工作程序、进程或线程数量。垂直伸缩往往取决于特定容器的实际可用内存量,因此必须配合容器中的限制可见性方能起效。

解决方案

开放容器倡议配合runC能够利用文件系统用户空间覆盖/proc文件。LXC创建的lxcfs文件系统允许容器拥有虚拟cgroup文件系统及虚拟/proc文件查看方式,这样上述问题的实质就成了如何对容器进行维护。

我们也遇到过类似的问题,但在Jelastic的帮助下,我们顺利为客户解决了这一障碍。下面来看具体办法。

首先打开Jelastic向导,为测试账户选定服务供应商并利用预定义内存限制创建一套Java Docker容器——例如8 cloudlets,相当于1 GB内存。

接下来前往Jelastic SSH gate(1),选定之前创建的测试环境(2),而后选定该容器(3)。现在我们已经可以利用free工具检查可用内存了(4)。

As we can see, the memory limit equals 1GB defined before. Let’s check the top tool.

一切运行正常。为了进一步检查,我们重复Matt之前提到的Java启发式行为问题。

现在的MaxHeapSize = 268435546 (~256 MiB),意味着当前容器的内存容量为默认JVM heap的四分之一。

其中的秘诀是什么?当然,这是各种“成分”的***结合。在本示例中,我们将OpenVZ与Docker技术结合以提供更出色的安全与隔离控制效果,同时保证其不会影响到容器实时迁移与容器休眠等必要功能。下面,大家可以看到Docker容器在Jelastic当中的高级应用思路。

在OpenVZ中,每套容器都拥有一套/proc pseudo-filesystem虚拟化视图。需要强调的是,容器中的/proc/meminfo为“定制”版本,能够显示每容器信息而非直接提取自主机。如此一来,top与free等工具在运行于容器内时,就能显示特定容器中遵循限制条件时的内存与swap使用情况。

值得注意的是,容器中的swap并非真正的swap,而只是一种虚拟机制(因此其整体技术被称为VSwap)。其核心思路在于,一旦启用了VSwap的某容器超出配置内存限制,则其部分内存即会转换为所谓swap cache。期间并不会发生真正的空间交换,意味着不存在I/O——除非整体环境下出现了全局(而非每容器)内存短缺。另外,使用VSwap的容器会通过降低运行速度的方式解决内存超标,这种方式从容器内部角度来看类似于执行真正的空间交换。这项技术能够对每容器内存与swap使用情况加以有效控制。

当然,除了Jelastic之外,大家也可以根据Matt的提示始终为JVM指定heap大小而非依赖于启发机制。如果各位有其它更好的思路,也请在评论中与我们分享。

原文标题:Java and Memory Limits in Containers: LXC, Docker and OpenVZ

【51CTO.com独家译文,合作站点转载请注明来源。】

责任编辑:王雪燕 来源: 51CTO
相关推荐

2009-03-04 12:16:13

2021-12-25 23:25:04

LinuxDocker容器

2022-03-10 08:24:17

Docker容器SaaS

2023-05-30 14:56:18

Docker开发容器

2009-06-03 15:52:34

堆内存栈内存Java内存分配

2022-01-24 17:08:33

Linux容器Docker

2015-08-19 14:54:25

2024-01-10 09:48:52

Docker工具

2015-10-10 14:35:46

Linux容器工具

2014-11-27 09:59:02

dockerlinux技巧

2024-03-11 08:22:40

Java内存泄漏

2021-03-05 00:06:12

Docker容器内存

2009-06-16 11:11:07

Java内存管理Java内存泄漏

2021-09-14 13:25:23

容器pod僵尸进程

2017-11-28 09:21:53

LinuxWindowsDocker

2024-04-19 13:02:27

容器C++

2018-07-23 09:02:18

容器KubernetesAmazon

2023-07-11 08:43:43

volatileJava内存

2013-03-28 09:55:37

Java对象

2015-05-14 15:38:40

javajava内存泄露
点赞
收藏

51CTO技术栈公众号