容器中 Java 应用程序的内存和 CPU 如何分配?看这一篇就够了!

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 随着2018年的结束,我们将回顾排名前五的最受读者欢迎的文章。今天分享的第一篇文章,将帮助那些在容器中运行 Java 虚拟机(JVM)时遇到内存和 CPU 大小调整/使用困难的人,本文将解释如何在 Docker Desktop(Mac或Windows)和 Docker Enterprise 环境中改进 Docker 容器与 Java 10的集成。

screenshot

出品丨Docker公司(ID:docker-cn)
编译丨小东
每周一、三、五,与您不见不散!


随着2018年的结束,我们将回顾排名前五的最受读者欢迎的文章。今天分享的第一篇文章,将帮助那些在容器中运行 Java 虚拟机(JVM)时遇到内存和 CPU 大小调整/使用困难的人,本文将解释如何在 Docker Desktop(Mac或Windows)和 Docker Enterprise 环境中改进 Docker 容器与 Java 10的集成。


许多应用程序都以容器的形式运行在 Java 虚拟机(JVM)中,其中包括 Apache Spark 和 Kafka 等数据服务以及旧的企业级应用程序。直到最近,在容器中运行 Java 虚拟机会出现内存和cpu大小以及使用方面的问题,从而导致性能损失。这是因为 Java 没有识别到它是在容器中运行的。随着 Java 10的发布,Java 虚拟机现在可以识别容器控制组(cgroups)设置的约束。内存和 cpu 约束都可以用于直接在容器中管理 Java 应用程序,包括:

  • 遵守容器中设置的内存限制;
  • 在容器中设置可用的 cpu;
  • 在容器中设置 cpu 约束;

Docker Desktop(Mac 或 Windows)和 Docker Enterprise 环境都实现了 Java 10的改进。


容器内存限制

在 Java 9之前,Java 虚拟机无法识别容器使用标记设置的内存或CPU限制。在Java 10中,内存限制将自动进行识别并强制执行。

Java 将服务器类机器定义为具有2个 CPU 和 2GB 内存,默认堆大小为物理内存的1/4。 例如,Docker Enterprise Edition 安装有2GB内存和4个CPU。比较运行 Java 8和 Java 10之间容器的区别。首先,Java 8:

docker container run -it -m512 --entrypoint bash openjdk:latest
$ docker-java-home/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
   uintx MaxHeapSize := 524288000 {product}
openjdk version "1.8.0_162"

最大堆大小为 512M 或 Docker EE 安装设置的 2GB 的1/4,而不是容器上设置的限制为512M。 相比之下,在 Java 10上运行相同的命令表明容器中设置的内存限制非常接近预期的128M:

docker container run -it -m512M --entrypoint bash openjdk:10-jdk
$ docker-java-home/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
  size_t MaxHeapSize = 134217728 {product} {ergonomic}
openjdk version "10" 2018-03-20

设置可用的CPU

默认情况下,每个容器对主机 CPU 周期的访问权限是不受限制的。可以设置各种约束来限制给定容器对主机 CPU 周期的访问。Java 10可以识别出这些限制:

docker container run -it --cpus 2 openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 2

分配给 Docker EE 的所有 CPU 获得相同比例的 CPU 周期。可以通过相对于所有其他正在运行的容器的权重更改容器的 CPU 份额权重来修改该比例。该比例仅适用于 CPU 密集型进程运行时。当一个容器中的任务空闲时,其他容器可以使用剩余的 CPU 时间。 实际的 CPU 时间量将根据系统上运行的容器数量而有所不同。这些可以在 Java 10中进行设置:

docker container run -it --cpu-shares 2048 openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 2

“cpuset” 约束设置了哪些 cpu 允许在 Java 10中执行。

docker run -it --cpuset-cpus="1,2,3" openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 3

分配内存和 CPU

使用 Java 10,容器设置可用于估计部署应用程序所需的内存和 CPU 分配。假设已经确定了容器中运行的每个进程的内存堆和 CPU 需求,并设置了 JAVA_OPTS。例如,如果您的应用程序分布在10个节点上,五个节点需要512Mb内存,每个节点占用 1024 CPU,另外五个节点需要256Mb内存,每个节点占用 512 CPU共享。请注意,1个CPU份额比例由 1024 表示。

对于内存,应用程序至少需要分配 5Gb 内存。

  • 512Mb x 5 = 2.56 Gb
  • 256Mb x 5 = 1.28 Gb

对于 CPU,应用程序需要分配8个CPU才能高效运行。

  • 1024 x 5 = 5 CPUs
  • 512 x 5 = 3 CPUs

最佳实践建议:分析应用程序以确定 Java 虚拟机中运行的每个进程的内存和 CPU 分配。无论如何,Java 10在调整容器大小时消除了猜测,预防了 Java 应用程序中的内存不足错误以及保障了分配足够的 CPU 来处理工作负载。

相关文章
|
22天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
23天前
|
缓存 算法 Java
Java内存管理与调优:释放应用潜能的关键
【4月更文挑战第2天】Java内存管理关乎性能与稳定性。理解JVM内存结构,如堆和栈,是优化基础。内存泄漏是常见问题,需谨慎管理对象生命周期,并使用工具如VisualVM检测。有效字符串处理、选择合适数据结构和算法能提升效率。垃圾回收自动回收内存,但策略调整影响性能,如选择不同类型的垃圾回收器。其他优化包括调整堆大小、使用对象池和缓存。掌握这些技巧,开发者能优化应用,提升系统性能。
|
22天前
|
Java
深入理解Java并发编程:线程池的应用与优化
【4月更文挑战第3天】 在Java并发编程中,线程池是一种重要的资源管理工具,它能有效地控制和管理线程的数量,提高系统性能。本文将深入探讨Java线程池的工作原理、应用场景以及优化策略,帮助读者更好地理解和应用线程池。
|
4天前
|
机器学习/深度学习 缓存 监控
linux查看CPU、内存、网络、磁盘IO命令
`Linux`系统中,使用`top`命令查看CPU状态,要查看CPU详细信息,可利用`cat /proc/cpuinfo`相关命令。`free`命令用于查看内存使用情况。网络相关命令包括`ifconfig`(查看网卡状态)、`ifdown/ifup`(禁用/启用网卡)、`netstat`(列出网络连接,如`-tuln`组合)以及`nslookup`、`ping`、`telnet`、`traceroute`等。磁盘IO方面,`iostat`(如`-k -p ALL`)显示磁盘IO统计,`iotop`(如`-o -d 1`)则用于查看磁盘IO瓶颈。
|
2天前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
18 0
|
2天前
|
Java
Java中的并发编程:理解和应用线程池
【4月更文挑战第23天】在现代的Java应用程序中,性能和资源的有效利用已经成为了一个重要的考量因素。并发编程是提高应用程序性能的关键手段之一,而线程池则是实现高效并发的重要工具。本文将深入探讨Java中的线程池,包括其基本原理、优势、以及如何在实际开发中有效地使用线程池。我们将通过实例和代码片段,帮助读者理解线程池的概念,并学习如何在Java应用中合理地使用线程池。
|
7天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
7天前
|
设计模式 算法 Java
Java中的设计模式及其应用
【4月更文挑战第18天】本文介绍了Java设计模式的重要性及分类,包括创建型、结构型和行为型模式。创建型模式如单例、工厂方法用于对象创建;结构型模式如适配器、组合关注对象组合;行为型模式如策略、观察者关注对象交互。文中还举例说明了单例模式在配置管理器中的应用,工厂方法在图形编辑器中的使用,以及策略模式在电商折扣计算中的实践。设计模式能提升代码可读性、可维护性和可扩展性,是Java开发者的必备知识。
|
7天前
|
安全 Java API
函数式编程在Java中的应用
【4月更文挑战第18天】本文介绍了函数式编程的核心概念,包括不可变性、纯函数、高阶函数和函数组合,并展示了Java 8如何通过Lambda表达式、Stream API、Optional类和函数式接口支持函数式编程。通过实际应用案例,阐述了函数式编程在集合处理、并发编程和错误处理中的应用。结论指出,函数式编程能提升Java代码的质量和可维护性,随着Java语言的演进,函数式特性将更加丰富。
|
8天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
15 1