设为首页 收藏本站
查看: 1386|回复: 0

[经验分享] 容器(docker)中运行java需关注的几个小问题

[复制链接]

尚未签到

发表于 2019-2-20 10:54:23 | 显示全部楼层 |阅读模式
简介

  •   container: 资源隔离、平台无关, 限制cpu、mem等资源


  •   java不知道自己运行在container里,以为它看到的资源都能用。结果:java工作在资源充足的
  给大家推荐一个程序员学习交流群:702895049。群里有分享的视频,还有思维导图
  群公告有视频,都是干货的,你可以下载来看。主要分享分布式架构、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战学习架构师视频。
详述
程序运行的两个核心资源:cpu和mem,其他资源或许也有限制,暂不涉及。cpu
jvm检测可用cpu个数来优化运行时,影响jvm后台做的一些决策。
影响

  •   java.lang.Runtime 所以ump的jvm监控数据一直以来都是不准确的
  •   GC 主要是线程数
  •   JIT 代码编译/执行子系统优化
实验
实验所用容器宿主机器是4核CPU16G内存

  •   java 6/7/8/9
  •   docker run --cpus 1 -m 1G -it adoptopenjdk/openjdk9:latest # 给1核
      jshell -J-Xmx512M -v # 启动jshell
      Runtime.getRuntime().availableProcessors() # 结果是不是1!!!
  •   java 10
      docker run --cpus 1 -m 1G -it adoptopenjdk/openjdk10:latest # 给1核
      jshell -J-Xmx512M -v # 启动jshell
      Runtime.getRuntime().availableProcessors() # 结果是1
对策
java 10才解决这个问题

  •   java 10之前:手动设置jvm相关的选项,如:

    •   ParallelGCThreads
    •   ConcGCThreads
    •   G1ConcRefinementThreads
    •   CICompilerCount / CICompilerCountPerCPU

  •   java 10+:

    •   UseContainerSupport, 默认开启

mem
jvm自动检测拿到的是宿主机的内存信息,它无法感知容器的资源上限
主要需要关注:动态内存管理(上下限,默认值)
我们先了解下java进程内存消耗在哪里内存结构
JFTR: 分代:垃圾收集的一大策略,并不是所有GC算法都分代哦
内存总量 = 广义堆内存 + 广义堆外内存
广义堆内内存 = 狭义堆内内存 + 永久代(Perm)
狭义对内内存 = 新生代(New) + 老年代(Old) # Xmx Xms
新生代(New) = S0 + S1 + Eden # NewSize NewRatio SurvivorRatio
    广义堆外内存 = 狭义堆外内存(directbytebuffer)  # MaxDirectMemorySize,netty/mina等高性能网络通信常用,具体不是很了解
                    + java栈 # 需关注,线程数 * ThreadStackSize(Xss)
                    + native栈 # 不大,线程数 * VMThreadStackSize + CICompilerCount * CompilerThreadStackSize
                    + pc寄存器  # 可忽略
                    + jni(如带用c/c++ malloc)# 这个不可控,一般忽略就好

    java 8之后Metaspace替代了Perm,从广义堆内转移到广义对外,why?
        - Perm连续、固定、jvm启动即claim到max,浪费,不好控制
        - 代码实验发现Perm不受Xmx限制`java -Xmx10M -Xmx10M -XX:PermSize=100M -XX:MaxPermSize=100M -version`
        - Metaspace的实现类似链式结构,默认值-1(无限大,取决于kernel让用多少),在fullgc时gc
    上面关于广义/狭义内存的定义是参考别人的资料后,自己定义的。。。不喜勿喷
        - 官方对于Perm的定义摇摆不定,前后矛盾,让我自己很困惑
            正方:在
                http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
                http://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdfOne important change in Memory Management in Java 8
            反方:不在
                https://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.html
                https://stackoverflow.com/questions/1262328/how-is-the-java-memory-pool-divided
                https://blogs.oracle.com/jonthecollector/presenting-the-permanent-generation               
                https://www.yourkit.com/docs/kb/sizes.jsp
                https://blog.codecentric.de/en/2010/01/the-java-memory-architecture-1-act/
        - 与Metaspace替换Perm有点儿关系吧综上,我们需要关注下面几类参数是否合理: – 狭义堆内 Xmx – 狭对堆外 MaxDirectMemorySize – Perm/Metaspace MaxPermSize/MaxMetaspaceSize
需关注的选项默认值
- Xmx: 1/4 * 物理内存 # 此处的物理内存为Runtime看到的内存(大多时候是宿主机的内存)
- MaxDirectMemorySize
    - Xmx 未设置,物理内存
    - Xmx 设置了, Xmx - S0(1/10 * Xmx) = 0.9 * Xmx # why? SurvivorRatio默认值8
- MaxPermSize: 默认64M
        [5.0+ 64 bit: 64M * 1.3 = 85M](http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html)
- MaxMetaspaceSize: -1,无限制实验
实验所用容器宿主机器是4核CPU16G内存

  •   java 7
      docker run -m 1G -it openjdk:7u181
      java -XX:+PrintFlagsFinal -version | grep MaxHeapSize # 结果是 16G / 4 = 4G
  •   java 8
      docker run -m 1G -it adoptopenjdk/openjdk8:latest
      java -XX:+PrintFlagsFinal -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -version | grep MaxHeapSize # 结果是 1G / 4 = 256M
  •   java 9
      docker run -m 1G -it adoptopenjdk/openjdk9:latest
      java -XX:+PrintFlagsFinal -version | grep MaxHeapSize # 结果是 16G / 4 = 4G
      java -XX:+PrintFlagsFinal -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -version | grep MaxHeapSize # 结果是 1G / 4 = 256M
  •   java 10
      docker run -m 1G -it adoptopenjdk/openjdk10:latest # 给1G
      jshell -v # 启动jshell
      java -XX:+PrintFlagsFinal -version | grep MaxHeapSize  # 结果是 1G / 4 = 256
对策

  •   java5/6/7/8u131-:务必设置内存选项
      懒人可考虑,虽然也不准确, 参考前面对jvm内存结构的分析
      java -Xmx`cat /sys/fs/cgroup/memory/memory.limit_in_bytes`
  •   java8u131+和java9+

    •   java 8u131+和java 9+-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
    •   java 8u191+ UseContainerSupport默认开启,backported;java 9暂未backport这个feature

  •   java10+

    •   使用最新版就好了,UseContainerSupport默认开启

扩展
排查工具

  •   jvm支持的选项

    •   生产
        java -XX:+PrintFlagsFinal 2>/dev/null
    •   试验
        java -XX:+PrintFlagsFinal -XX:+UnlockExperimentalVMOptions 2>/dev/null | grep experimental
    •   可热更新
        java -XX:+PrintFlagsFinal -XX:+UnlockExperimentalVMOptions 2>/dev/null | grep manageable
        如:热开启gc日志
                jinfo -flag +PrintGC ${pid} # 官方文档说jinfo是实验工具,截至java 10,它都还在,[不过jhat在java9被去掉了](http://openjdk.java.net/jeps/241)
                jinfo -flag +PrintGCDetails ${pid}

  •   容器内执行jstat/jps/jmapOOM问题
      工具类是用C++包装的java代码,它们不识别常规的传给jvm的参数,如最大内存。
      在强悍的(超级大内存)宿主机器下,容器内经常因为OOM问题启动不了这些工具。

    •   java 6及之前: 通过java调用
        java -cp ${JAVA_HOME}/lib/tools.jar -Xmx100M sun.tools.jstack.JStack ${pid}
    •   java 7+
        jstack -J-Xmx100M -v # -J选项给jvm传参数





运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-674801-1-1.html 上篇帖子: 虚拟机与Docker有何不同? 下篇帖子: 部署Docker
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表