蜘蛛记忆体 如何设定Docker容器中Java应用的记忆体限制
如何设定Docker容器中Java应用的记忆体限制
如何设定Docker容器中Java应用的记忆体限制
docker run 命令可以对cpu和记忆体限制,目前没有直接对磁碟限制
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a mand in a new container -c, --cpu-shares=0 CPU shares (relative weight) -m, --memory="" Memory limit (format: <number><optional unit>, where unit = b, k, m or g)

最近在和阿里的一些同事谈起使用Docker部署Java应用的场景,其中一个大家普遍关心的问题就是如何设定容器中JVM的记忆体限制。
如果使用官方的Java映象,或者基于Java映象构建的Docker映象,都可以通过传递 JAVA_OPTS 环境变数来轻松地设定JVM的记忆体引数。比如,对于官方Tomcat 映象,我们可以执行下面命令来启动一个最大记忆体为512M的tomcat例项
docker run --rm -e JAVA_OPTS='-Xmx512m' tomcat:8
在日志中,我们可以清楚地发现设定已经生效 “Command line argument: -Xmx512m”
02-Apr-2016 12:46:26.970 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Server version: Apache Tomcat/8.0.32
02-Apr-2016 12:46:26.974 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Server built: Feb 2 2016 19:34:53 UTC
02-Apr-2016 12:46:26.975 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Server number: 8.0.32.0
02-Apr-2016 12:46:26.975 INFO [main] .apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
02-Apr-2016 12:46:26.975 INFO [main] .apache.catalina.startup.VersionLoggerListener.log OS Version: 4.1.19-boot2docker
02-Apr-2016 12:46:26.975 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
02-Apr-2016 12:46:26.975 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/lib/jvm/java-7-openjdk-amd64/jre
02-Apr-2016 12:46:26.976 INFO [main] .apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.7.0_95-b00
02-Apr-2016 12:46:26.976 INFO [main] .apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation
02-Apr-2016 12:46:26.977 INFO [main] .apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat
02-Apr-2016 12:46:26.977 INFO [main] .apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat
02-Apr-2016 12:46:26.978 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
02-Apr-2016 12:46:26.978 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=.apache.juli.ClassLoaderLogManager
02-Apr-2016 12:46:26.978 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx512m
...
然而在Docker丛集上部署执行Java容器应用的时候,仅仅对JVM的heap引数设定是不够的,我们还需要对Docker容器的记忆体资源进行限制:
1. 限制容器使用的记忆体的最大量,防止对系统或其他应用造成伤害
2. 能够将Docker容器排程到拥有足够空余的记忆体的节点,从而保证应用的所需执行资源
关于容器的资源分配约束,Docker提供了相应的启动引数
对记忆体而言,最基本的就是通过 -m引数来约束容器使用记忆体的大小
-m, --memory=""
Memory limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M.
那么问题就来了,为了正确设定Docker容器记忆体的大小,难道我们需要同时传递容器的记忆体限制和JAVA_OPTS环境变数吗? 如下所示:
docker run --rm -m 512m -e JAVA_OPTS='-Xmx512m' tomcat:8
这个方法有两个问题
1. 需要管理员保证容器记忆体和JVM记忆体设定匹配,否则可能引发错误
2. 当对容器记忆体限制调整时,环境变数也需要重新设定,这就需要重建一个新的容器
是否有一个方法,可以让容器内部的JVM自动适配容器的记忆体限制?这样可以采用更加统一的方法来进行资源管理,简化配置工作。
大家知道Docker是通过CGroup来实现资源约束的,自从1.7版本之后,Docker把容器的local cgroups以只读方式挂载到容器内部的档案系统上,这样我们就可以在容器内部,通过cgroups资讯来获取系统对当前容器的资源限制了。
我建立了一个示例映象 registry.aliyuncs./denverdino/tomcat:8-autoheap
,其原始码可以从Github 获得。它基于Docker官方Tomcat映象建立,它的启动指令码会检查CGroup中记忆体限置,并计算JVM最大Heap size来传递给Tomcat。其程式码如下
#!/bin/bash
limit_in_bytes=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)
# If not default limit_in_bytes in cgroup
if [ "$limit_in_bytes" -ne "9223372036854771712" ]
then
limit_in_megabytes=$(expr $limit_in_bytes / 1048576)
heap_size=$(expr $limit_in_megabytes - $RESERVED_MEGABYTES)
export JAVA_OPTS="-Xmx${heap_size}m $JAVA_OPTS"
echo JAVA_OPTS=$JAVA_OPTS
fi
exec catalina.sh run
说明:
为了监控,故障排查等场景,我们预留了部分记忆体(预设64M),其余容器记忆体我们都分配给JVM的堆。
这里没有对边界情况做进一步处理。在生产系统中需要根据情况做相应的设定,比如最大的堆大小等等。
现在我们启动一个tomcat执行在512兆的容器中
docker run -d --name test -m 512m registry.aliyuncs./denverdino/tomcat:8-autoheap
通过下列命令,从日志中我们可以检测到相应的JVM引数已经被设定成 448MB (512-64)
docker logs test
...
02-Apr-2016 14:18:09.870 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx448m
...
我们也可以方便的调整Java应用的记忆体.
Docker 1.10提供了对容器资源限制的动态修改能力。但是由于JVM无法感知容器资源修改,我们依然需要重启tomcat来变更JVM的记忆体设定,例如,我们可以通过下面命令把容器记忆体限制调整到1GB
docker update -m 1024m test
docker restart test
再次检查日志,相应的JVM Heap Size最大值已被设定为960MB
docker logs test
...
02-Apr-2016 14:21:07.644 INFO [main] .apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx960m
...
然而在Docker丛集上部署执行Java容器应用的时候,仅仅对JVM的heap引数设定是不够的,我们还需要对Docker容器的记忆体资源进行限制: 1. 限制容器使用的记忆体的最大量,防止对系统或其他应用造成伤害 2. 能够将Docker容器排程到拥有足够空余的记忆体
然而在Docker丛集上部署执行Java容器应用的时候,仅仅对JVM的heap引数设定是不够的,我们还需要对Docker容器的记忆体资源进行限制:
1. 限制容器使用的记忆体的最大量,防止对系统或其他应用造成伤害
2. 能够将Docker容器排程到拥有足够空余的记忆体的节点,从而保证应用的所需执行资源
关于容器的资源分配约束,Docker提供了相应的启动引数
- 上一篇
为什么语言表达能力很差 我的作文写得不好、而且表达能力很差、和别人交流的时候也不知道该说什么、您觉得该怎么做 或看些什么书?
我的作文写得不好、而且表达能力很差、和别人交流的时候也不知道该说什么、您觉得该怎么做 或看些什么书? 我的作文写得不好、而且表达能力很差、和别人交流的时候也不知道该说什么、您觉得该怎么做 或看些什么书
- 下一篇
司马姓氏现在姓什么 诸葛、司马这些姓氏为什么消失了?复姓究竟是怎么来的?!
诸葛、司马这些姓氏为什么消失了?复姓究竟是怎么来的? 中国古代有很多复姓存在,例如诸葛、司马、上官、欧阳等,其实这些姓氏都非常好听,充满一种江湖的气息,为什么到了现代这些姓氏都消失了呢?其实这些姓氏的