zoukankan      html  css  js  c++  java
  • Docker——Tomcat JVM 内存配置

    前言

    安装再docker中的tomcat,在下载大文件或者某些情况下,会出现tomcat的内存溢出等情况,所以需要配置tomcat的内存大小,docker中的tomcat内存大小配置有四种方式。

    一、修改catalina.sh

    加入JVM:

    JAVA_OPTS="-server -Dfile.encoding=UTF-8 -Xms4g -Xmx4g -Xmn1g -Xss512K -verbose:gc -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=10 -XX:PermSize=1g -XX:MaxPermSize=1g -XX:+ExplicitGCInvokesConcurrent -XX:GCTimeRatio=19 -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=10 -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=50 -Xnoclassgc -XX:SoftRefLRUPolicyMSPerMB=0"

    示例:

    二、创建setenv.sh

    如果你查看过catalina.sh里面的代码你会发现下面2段说明:

    进入到tomcat/bin目录下,通过以下命令创建setenv.sh文件:

    vi setenv.sh

    添加环境变量到文件中并保存

    JAVA_OPTS="-server -Dfile.encoding=UTF-8 -Xms4g -Xmx4g -Xmn1g -Xss512K -verbose:gc -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=10 -XX:PermSize=1g -XX:MaxPermSize=1g -XX:+ExplicitGCInvokesConcurrent -XX:GCTimeRatio=19 -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=10 -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=50 -Xnoclassgc -XX:SoftRefLRUPolicyMSPerMB=0"

    三、docker启动设置环境变量

    如果使用官方的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] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.0.32
    02-Apr-2016 12:46:26.974 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Feb 2 2016 19:34:53 UTC
    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number:         8.0.32.0
    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            4.1.19-boot2docker
    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
    02-Apr-2016 12:46:26.975 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/lib/jvm/java-7-openjdk-amd64/jre
    02-Apr-2016 12:46:26.976 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           1.7.0_95-b00
    02-Apr-2016 12:46:26.976 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Oracle Corporation
    02-Apr-2016 12:46:26.977 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/tomcat
    02-Apr-2016 12:46:26.977 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/tomcat
    02-Apr-2016 12:46:26.978 INFO [main] org.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] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
    02-Apr-2016 12:46:26.978 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx512m
    ...

    完整示例:

    # docker
    docker run -d --name masl -e TZ="Asia/Shanghai" -e JAVA_OPTS='-server -Dfile.encoding=UTF-8 -Xms2g -Xmx2g -Xmn512m -Xss512K -verbose:gc -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=10 -XX:PermSize=512m -XX:MaxPermSize=512m -XX:+ExplicitGCInvokesConcurrent -XX:GCTimeRatio=19 -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=10 -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=50 -Xnoclassgc -XX:SoftRefLRUPolicyMSPerMB=0' -p 8081:8080 172.16.99.2:40305/masl:dev-yc-36

    四、自动适配容器内存

    通过前面3种方法,我们知道在Docker集群上部署运行Java容器应用的时候,可以设置JVM的heap,然而仅仅对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.com/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

    说明:

    • 为了JVM自身的Non-Heap内存,以及监控,故障排查等场景,我们预留了部分内存(缺省256M),其余容器内存我们都分配给JVM的堆。
    • 这里没有对边界情况做进一步处理。在生产系统中需要根据情况做相应的设定,比如最大的堆大小等等。

    现在我们启动一个tomcat运行在512兆的容器中

    docker run -d --name test -m 512m registry.aliyuncs.com/denverdino/tomcat:8-autoheap

    通过下列命令,从日志中我们可以检测到相应的JVM参数已经被设置成 256MB (512-256)

    docker logs test
    
    ...
    02-Apr-2016 14:18:09.870 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx256m
    ...

    我们也可以方便的调整Java应用的内存.

    Docker 1.10提供了对容器资源限制的动态修改能力。但是由于JVM无法感知容器资源修改,我们依然需要重启tomcat来变更JVM的内存设置,例如,我们可以通过下面命令把容器内存限制调整到1GB

    docker update -m 1024m test
    docker restart test

    再次检查日志,相应的JVM Heap Size最大值已被设置为768MB

    docker logs test
    
    ...
    02-Apr-2016 14:21:07.644 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Xmx768MB
    ...

    总结

    第1和第2种方法,通过在Dockerfile中构建image的时候写死了一个catalina.sh或setenv.sh到tomcat的bin目录下(或者通过挂载文件的方式),这样的话就限制死了我们的镜像,不够通用。

    第3种方法,也容易引发问题,且不够灵活。所以,推荐使用第4种方法。

    参考:https://yq.aliyun.com/articles/18037

  • 相关阅读:
    redis为何单线程 效率还这么高 为何使用跳表不使用B+树做索引(阿里)
    阿里笔试-生产者消费者模式
    调用 redis 原子命令,保证多线程安全 的incr命令问题
    忽略警告注解@SuppressWarnings详解
    怎样查出连续数字中缺失的数字
    IDEA-Maven的Dependencies中出现红色波浪线
    Java实现AES加密(window机器和linux机器) 注意window机器 和linux机器算法稍有不同
    PR代码提交规范
    接口的幂等性,如何保证
    bash 括号(小括号,双小括号,中括号,双中括号,大括号)
  • 原文地址:https://www.cnblogs.com/caoweixiong/p/12383223.html
Copyright © 2011-2022 走看看