热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java程序在K8S容器部署CPU和Memory资源限制相关设置

背景在k8sdocker环境中执行Java程序,因为我们设置了cpu,memory的limit,所以Java程序执行时JVM的参数没有跟我们设置的参数关联,导致JVM感知到的cpu
背景

在k8s docker环境中执行Java程序,因为我们设置了cpu,memory的limit,所以Java程序执行时JVM的参数没有跟我们设置的参数关联,导致JVM感知到的cpu和memory是我们k8s的work node上的cpu和memory大小。这样造成的问题是:当容器中Java程序使用内存超过memory limit时,直接造成Out of Memory错误,从而引起容器重启。JVM很多参数也是很智能的,启动时内存的分配也会根据cpu和memory进行调整,比如GC相关的参数就是动态调整的。如果容器感知到的cpu核数不对,那么对程序的性能也会造成很大的影响。

内存

Java对内存的使用有几个参数可以配置。以前的版本可以用-Xms, -Xmx来分别设置初始化Java堆大小和最大的Java堆大小。但因为Java堆大小并不等于所有可用的内存大小,所以在设置memory limit的时候会加一个值。这样避免Java使用的内存超过分配给容器的最大内存限制。这个增加的值需要一定的经验和测试来获取。

JVM后来提供了UseCGroupMemoryLimitForHeap参数来让JVM自动根据我们提供的内存限制来分配堆的大小。这样也就避免了我们人为去确定应该给堆多大的空间。只要经过测试,确定这个Java程序占用的总共空间就行了。使用方法是在java运行后面加上参数:java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap ⋯

CPU

配了上面的参数,我们还没有完全解决问题。因为JVM GC相关的参数跟CPU处理器核相关联的,可使用的CPU核数越多,分配给GC的线程资源也越多。如果我们不设置正确的CPU核数给容器,那么它看到的就是整个k8s worker node的CPU个数,比如我们限制容器可使用2core,但worker node有32core。那么这个容器会给GC分配很多的线程资源,从而严重影响正常Java线程的运行。

CPU个数对JVM GC的影响

JVM提供了ActiveProcessorCount参数来设置这个值。但这个参数只在java 1.8.0_191以后版本才支持。下面我在笔记本上做了测试(total 8 cores),看看这个参数如何影响GC的参数。

Step1: 写一个hello wold程序。

root@kyle:~# cat Hello.java
public class Hello{
    public static void  main(String[] args){
        System.out.println("hello world");
}

Step2: 编译

root@kyle:~# javac Hello.java

Step3: 不加参数运行

root@kyle:~# java -XX:+PrintFlagsFinal Hello > init.txt
[Global flags]
     intx ActiveProcessorCount                      = -1                                  {product}
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
    uintx AdaptiveSizePausePolicy                   = 0                                   {product}
    uintx AdaptiveSizePolicyCollectiOnCostMargin= 50                                  {product}
…

Step4: 加不同参数值运行

root@kyle:~# java -XX:ActiveProcessorCount=1 -XX:+PrintFlagsFinal Hello > p1.txt
root@kyle:~# java -XX:ActiveProcessorCount=2 -XX:+PrintFlagsFinal Hello > p2.txt
root@kyle:~# java -XX:ActiveProcessorCount=4 -XX:+PrintFlagsFinal Hello > p4.txt
root@kyle:~# java -XX:ActiveProcessorCount=8 -XX:+PrintFlagsFinal Hello > p8.txt

Step5: 看看不同参数对GC的影响:
1个处理器跟2个处理器的比较:

 root@kyle:~# diff p1.txt p2.txt
2c2
      intx ActiveProcessorCount                     := 2                                   {product}
304c304
     uintx MarkSweepDeadRatio                        = 1                                   {product}
311c311
     uintx MaxHeapFreeRatio                          = 100                                 {manageable}
335,336c335,336
     uintx MinHeapDeltaBytes                        := 524288                              {product}
>     uintx MinHeapFreeRatio                          = 0                                   {manageable}
388c388
     uintx ParallelGCThreads                         = 2                                   {product}
682,683c682,683
      bool UseParallelGC                            := true                                {product}
>      bool UseParallelOldGC                          = true                                {product}

2个处理器跟4个处理器的比较:

root@kyle:~# diff p2.txt p4.txt
2c2
      intx ActiveProcessorCount                     := 4                                   {product}
59c59
      intx CICompilerCount                          := 3                                   {product}
388c388
     uintx ParallelGCThreads                         = 4                                   {product}

4个处理器跟8个处理器的比较:

root@kyle:~# diff p4.txt p8.txt
2c2
      intx ActiveProcessorCount                     := 8                                   {product}
59c59
      intx CICompilerCount                          := 4                                   {product}
388c388
     uintx ParallelGCThreads                         = 8                                   {product}

不加参数跟8个处理器的比较:

root@kyle:~# diff init.txt p8.txt
2c2
      intx ActiveProcessorCount                     := 8                                   {product}

从上面比较可以看出,不设这个参数跟设置最大参数(当前系统是8core)是一样的。2,4,8核设置只影响ParallelGCThreads, CICompilerCount。但如果只用1核的话,UseParallelGC,UseParallelOldGC都变为false,同时也会影响其它几个参数。见上面diff p1.txt p2.txt比较结果。

CPU个数对Java程序的影响

CPU个数的设置除了对JVM GC性能产生影响外,对Java的工作线程也会产生影响。以下的代码常用于Java库,它会根据CPU的个数产生工作线程。如果没有正确设置docker中的参数,对实际的程序性能会产生很大的影响。

Runtime.getRuntime().availableProcessors()

以下代码摘自aliyun-log-java-producer库,是根据可用处理器来产生相应个数的IO线程来发送loghub数据。

# ProducerConfig.java:
public class ProducerConfig {
  public static final int DEFAULT_IO_THREAD_COUNT =
      Math.max(Runtime.getRuntime().availableProcessors(), 1);
OpenJDK版本

我们运行以下命令检查JDK的版本。openjdk version "1.8.0_131"以后支持UseCGroupMemoryLimitForHeap参数,"1.8.0_191"以后才支持ActiveProcessorCount这个参数。

root@kyle:~# java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.16.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
改进方案

如果我们使用的JDK版本支持这2个参数,那么我们只需要在运行Java程序时把这UseCGroupMemoryLimitForHeap参数加上,同时再给ActiveProcessorCount参数赋值实际分配给容器的cpu limit就可以了。如果目前的JDK版本低于1.8.0_191,即不支持ActiveProcessorCount,针对这个情况,有2种方法可以进行:

  1. 建议升级到191以后的版本,然后根据cpu limit配置ActiveProcessorCount。
  2. 不升级jdk版本,直接设置跟ActiveProcessorCount参数相关的GC参数:比如ParallelGCThreads,CICompilerCount。如果是1.8.0_131以前的版本,可以用-Xms, -Xmx参数进行堆空间的大小分配,注意这两个参数只设置了分配给堆的大小,实际的memory limit应该比这个大。这种方案不是一个best practice,毕竟这样没有用到JVM自动适配的一些参数。最关键的,此种方法不能避免很多Java库根据availableProcessors()来做相应逻辑处理。

推荐阅读
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • go channel 缓冲区最大限制_Golang学习笔记之并发.协程(Goroutine)、信道(Channel)
    原文作者:学生黄哲来源:简书Go是并发语言,而不是并行语言。一、并发和并行的区别•并发(concurrency)是指一次处理大量事情的能力 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 流数据流和IO流的使用及应用
    本文介绍了流数据流和IO流的基本概念和用法,包括输入流、输出流、字节流、字符流、缓冲区等。同时还介绍了异常处理和常用的流类,如FileReader、FileWriter、FileInputStream、FileOutputStream、OutputStreamWriter、InputStreamReader、BufferedReader、BufferedWriter等。此外,还介绍了系统流和标准流的使用。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • ScrollView嵌套Collectionview无痕衔接四向滚动,支持自定义TitleView
    本文介绍了如何实现ScrollView嵌套Collectionview无痕衔接四向滚动,并支持自定义TitleView。通过使用MainScrollView作为最底层,headView作为上部分,TitleView作为中间部分,Collectionview作为下面部分,实现了滚动效果。同时还介绍了使用runtime拦截_notifyDidScroll方法来实现滚动代理的方法。具体实现代码可以在github地址中找到。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 介绍平常在多线程开发中,总避免不了线程同步。本篇就对net多线程中的锁系统做个简单描述。目录一:lock、Monitor1:基础 ... [详细]
author-avatar
Elaine_Fox
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有