当前位置:首页 > 科技  > 软件

Kubernetes 中的 Java 应用的内存调优

来源: 责编: 时间:2023-10-18 09:18:41 390观看
导读前言在 Kubernetes 环境中运行 Java 应用程序虽然很常见,但往往也充满各种问题,特别是在管理内存资源时。在本文中,我们将讨论配置应用程序以优化 Kubernetes 环境中的内存使用并避免内存不足问题的一些最佳实践。OpenJD

Zc228资讯网——每日最新资讯28at.com

前言

在 Kubernetes 环境中运行 Java 应用程序虽然很常见,但往往也充满各种问题,特别是在管理内存资源时。在本文中,我们将讨论配置应用程序以优化 Kubernetes 环境中的内存使用并避免内存不足问题的一些最佳实践。Zc228资讯网——每日最新资讯28at.com

OpenJDK 17 中的内存空间

OpenJDK 17 包含 Java 虚拟机 (JVM) 使用的多个内存空间来管理 Java 应用程序的内存。了解这些不同的内存空间可以帮助开发人员针对 Kubernetes 环境优化其 Java 应用程序。Zc228资讯网——每日最新资讯28at.com

图片Zc228资讯网——每日最新资讯28at.com

Heap Memory-堆内存

堆内存会在Java运行时分配给对象(Object)或者JRE类。每当我们创建一个对象的时候,在堆内存中就会分配一块储存空间给这个对象。Java的垃圾回收机制就是运行在堆内存上的,用以释放那些没有任何引用指向自身的对象(不可达的对象。注意Java的垃圾回收也会处理几个相互引用但没有任何外部引用的对象)。任何在堆内存中分配的对象都有全局访问权限,可以从应用的任何地方被引用。Zc228资讯网——每日最新资讯28at.com

堆内存是存储Java应用程序创建的对象的地方。它是Java应用程序最重要的内存空间。在 OpenJDK 17 中,默认堆大小是根据可用物理内存计算的,并设置为可用内存的 1/4。Zc228资讯网——每日最新资讯28at.com

Young Generation-年轻代

对象被创建时,内存的分配首先发生在年轻代(大对象可以直接被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快变得不可达,于是被年轻代的GC机制清理掉(IBM的研究表明,98%的对象都是很快消亡的),这个GC机制被称为Minor GC或叫Young GC。注意,Minor GC并不代表年轻代内存不足,它事实上只表示在Eden区上的GC。Zc228资讯网——每日最新资讯28at.com

年轻代上的内存分配是这样的,年轻代可以分为3个区域:Eden区(伊甸园,亚当和夏娃偷吃禁果生娃娃的地方,用来表示内存首次分配的区域,再贴切不过)和两个存活区(Survivor 0 、Survivor 1)。Zc228资讯网——每日最新资讯28at.com

Old Generation-老一辈

对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代大,能存放更多的对象,在年老代上发生的GC次数也比年轻代少。当年老代内存不足时,将执行Major GC,也叫 Full GC。  Zc228资讯网——每日最新资讯28at.com

可以使用-XX:+UseAdaptiveSizePolicy开关来控制是否采用动态控制策略,如果动态控制,则动态调整Java堆中各个区域的大小以及进入老年代的年龄。Zc228资讯网——每日最新资讯28at.com

如果对象比较大(比如长字符串或大数组),Young空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)。用-XX:PretenureSizeThreshold来控制直接升入老年代的对象大小,大于这个值的对象会直接分配在老年代上。Zc228资讯网——每日最新资讯28at.com

可能存在年老代对象引用新生代对象的情况,如果需要执行Young GC,则可能需要查询整个老年代以确定是否可以清理回收,这显然是低效的。解决的方法是,年老代中维护一个512 byte的块——”card table“,所有老年代对象引用新生代对象的记录都记录在这里。Young GC时,只要查这里即可,不用再去查全部老年代,因此性能大大提高。Zc228资讯网——每日最新资讯28at.com

Metaspace-元空间

非堆空间被 JVM 用于存储元数据和类定义。在旧版本的 Java 中,它也称为永久代 (PermGen)。在 OpenJDK 17 中,PermGen 空间已被新的 Metaspace 取代,其设计更加高效和灵活。Zc228资讯网——每日最新资讯28at.com

Code Cache-代码缓存

简而言之,JVM Code Cache (代码缓存)是JVM存储编译成本机代码的字节码的区域。我们将可执行本机代码的每个块称为nmethod。nmethod可能是一个完整的或内联的Java方法。Zc228资讯网——每日最新资讯28at.com

即时(JIT)编译器是代码缓存区的最大消费者。这就是为什么一些开发人员将此内存称为JIT代码缓存。Zc228资讯网——每日最新资讯28at.com

Thread Stack Space-线程堆栈空间

Java程序中,每个线程都有自己的Stack Space(堆栈)。这个Stack Space不是来自Heap的分配。所以Stack Space的大小不会受到-Xmx和-Xms的影响,这2个JVM参数仅仅是影响Heap的大小。Zc228资讯网——每日最新资讯28at.com

Stack Space用来做方法的递归调用时压入Stack Frame(栈帧)。所以当递归调用太深的时候,就有可能耗尽Stack Space,爆出StackOverflow的错误。Zc228资讯网——每日最新资讯28at.com

-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆 栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一 个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。Zc228资讯网——每日最新资讯28at.com

线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误。Zc228资讯网——每日最新资讯28at.com

Shared libs-共享库

Java JVM 中的共享库空间(也称为共享类数据空间)是用于存储共享类元数据和其他数据结构的内存空间。该内存空间在多个 Java 进程之间共享。这允许在同一台机器上运行的各种 Java 应用程序共享类元数据和其他数据结构的相同副本。 Zc228资讯网——每日最新资讯28at.com

共享库空间的目的是通过避免同一类元数据的重复副本来减少内存使用并提高性能。当多个 Java 进程使用相同的类元数据时,它们可以共享该元数据的相同副本,从而减少内存使用并缩短应用程序的启动时间。Zc228资讯网——每日最新资讯28at.com

为什么要微调JVM的内存设置?

JVM 的默认行为会给 Kubernetes 带来很多麻烦。正如我们之前看到的,堆默认设置为可用内存的 1/4。由于 JVM 将考虑 pod 可用的最大内存(有限制),因此堆的大小可能会比我们想要的大。此外,其他默认值将应用于其他空间,例如代码缓存或元空间。 如果从 JVM 的角度来看最大可用内存,它将大于提供给 pod 的最大可用内存。这将导致应用程序出现许多内存不足的情况(在 Kubernetes 部分)。Zc228资讯网——每日最新资讯28at.com

避免Java应用程序在Kubernetes上出现OOM

大多数时候,都是为了微调 JVM。由于我们看到 JVM 涉及不同的内存空间,因此我们必须为每个空间设置特定的大小。这将帮助我们更精确地计算 pod 的内存限制。 以下是显示每个内存空间可用选项的架构:Zc228资讯网——每日最新资讯28at.com

图片Zc228资讯网——每日最新资讯28at.com

基本公式是:Zc228资讯网——每日最新资讯28at.com

Heap + Metaspace + Code Cache

意思是 :Zc228资讯网——每日最新资讯28at.com

-XmX + -XX:MaxMetaspaceSize + -XX:ReservedCodeCacheSize

由于线程的数量取决于应用程序的上下文,因此建议为此部分添加一些“缓冲”内存。默认情况下,线程堆栈最大设置为 1MB。Zc228资讯网——每日最新资讯28at.com

如果想处理来自 JVM 的堆转储,则需要添加堆的大小作为第二次可用的“额外”内存。 最后,设置 pod 限制的公式为:Zc228资讯网——每日最新资讯28at.com

(-XmX * 2) + -XX:MaxMetaspaceSize + -XX:ReservedCodeCacheSize + SomeBuffer

缓冲区部分取决于上下文,128 MB 应该可以开始。Zc228资讯网——每日最新资讯28at.com

Helm模板配置

既然有了公式,我们就可以使用一些 Helm 模板自动计算 pod 的请求和限制。为开发人员提供一个简单的选项来设置不同的参数,而无需担心 Pods 设置,这也是一个好的方式。 以下是默认值的示例:Zc228资讯网——每日最新资讯28at.com

jvm: garbageCollector: -XX:+UseG1GC # values in Mi memory:   heap: 128   metaspace: 256   compressedClassSpaceSize: 64   nonMethodCodeHeapSize: 5   profiledCodeHeapSize: 48   nonProfiledCodeHeapSize: 48   buffer: 128

使用 Helper 来设置 JAVA_TOOL_OPTIONS :Zc228资讯网——每日最新资讯28at.com

{{/*JVM customisation*/}}{{- define "chart.javaToolOptions" -}}-Xms{{.Values.jvm.memory.heap}}m -Xmx{{.Values.jvm.memory.heap}}m -XX:MetaspaceSize={{.Values.jvm.memory.metaspace}}m -XX:MaxMetaspaceSize={{.Values.jvm.memory.metaspace}}m -XX:CompressedClassSpaceSize={{.Values.jvm.memory.compressedClassSpaceSize}}m -XX:+TieredCompilation -XX:+SegmentedCodeCache -XX:Nnotallow={{.Values.jvm.memory.nonMethodCodeHeapSize}}m -XX:ProfiledCodeHeapSize={{.Values.jvm.memory.profiledCodeHeapSize}}m -XX:Nnotallow={{.Values.jvm.memory.nonProfiledCodeHeapSize}}m -XX:ReservedCodeCacheSize={{ add .Values.jvm.memory.nonMethodCodeHeapSize .Values.jvm.memory.profiledCodeHeapSize .Values.jvm.memory.nonProfiledCodeHeapSize}}m{{- end -}}

在deployment.yaml文件中使用:Zc228资讯网——每日最新资讯28at.com

- name: {{ include "chart.name" . }}         image: "{{ .Values.container.image.repository }}:{{ .Values.container.image.tag }}"         env:           - name: JAVA_TOOL_OPTIONS             value: {{ include "chart.javaToolOptions" . }}

根据提供的参数自动配置内存请求和限制:Zc228资讯网——每日最新资讯28at.com

resources:           limits:             memory: {{ add .Values.jvm.memory.heap .Values.jvm.memory.heap .Values.jvm.memory.metaspace .Values.jvm.memory.nonMethodCodeHeapSize .Values.jvm.memory.profiledCodeHeapSize .Values.jvm.memory.nonProfiledCodeHeapSize .Values.jvm.memory.buffer | printf "%dMi"}}             cpu: {{ .Values.container.resources.limits.cpu }}           requests:             memory: {{ add .Values.jvm.memory.heap .Values.jvm.memory.metaspace .Values.jvm.memory.nonMethodCodeHeapSize .Values.jvm.memory.profiledCodeHeapSize .Values.jvm.memory.nonProfiledCodeHeapSize | printf "%dMi"}}             cpu: {{ .Values.container.resources.requests.cpu }}

结论

通过这一设置,我们将 Kubernetes 一侧的 "内存不足"(Out Of Memory)错误数量降至零。现在,JVM 会在自己这边发生 OOM,并生成堆转储,帮助开发人员分析内存。我们会发现是否有一些优化需要推进,或者我们是否需要增加堆大小(或其他内存空间)。Zc228资讯网——每日最新资讯28at.com

通过微调 JVM 内存配置,我们打破了恶性循环,即每次 OOM 都意味着为 pod 增加内存,以避免未来出现问题。我们能更好地了解每个内存空间,以及如何和何时增加它们。Zc228资讯网——每日最新资讯28at.com

图片Zc228资讯网——每日最新资讯28at.com

每次调整都需要测试,因此我们建议使用一些工具,例如 Micrometer,来获得有关 JVM 使用情况的一些指标。 而且,最重要的是,我们减少了应用程序的内存需求,并通过减少内存浪费事实上降低了基础设施的成本!Zc228资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-13840-0.htmlKubernetes 中的 Java 应用的内存调优

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 用Babel和Nodemon搭建一个功能齐全的Nodejs开发环境

下一篇: 利用贝叶斯网络预测医院服务患者数量

标签:
  • 热门焦点
  • 印度登月最关键一步!月船三号今晚进入环月轨道

    8月5日消息,据印度官方消息,月船三号将于北京时间今晚21时30分左右开始近月制动进入环月轨道。这是该探测器能够成功的最关键步骤之一,如果成功将开始围
  • 从 Pulsar Client 的原理到它的监控面板

    背景前段时间业务团队偶尔会碰到一些 Pulsar 使用的问题,比如消息阻塞不消费了、生产者消息发送缓慢等各种问题。虽然我们有个监控页面可以根据 topic 维度查看他的发送状态,
  • 三言两语说透柯里化和反柯里化

    JavaScript中的柯里化(Currying)和反柯里化(Uncurrying)是两种很有用的技术,可以帮助我们写出更加优雅、泛用的函数。本文将首先介绍柯里化和反柯里化的概念、实现原理和应用
  • 新电商三兄弟,“抖快红”成团!

    来源:价值研究所作 者:Hernanderz 随着内容电商的概念兴起,抖音、快手、小红书组成的“新电商三兄弟”成为业内一股不可忽视的势力,给阿里、京东、拼多多带去了巨大压
  • 当家的盒马,加速谋生

    来源 | 价值星球Planet作者 | 归去来自己“当家”的盒马,开始加速谋生了。据盒马官微消息,盒马计划今年开放生鲜供应链,将其生鲜商品送往食堂。目前,盒马在上海已经与
  • 三星Galaxy Z Fold5官方渲染图曝光:13.4mm折叠厚度依旧感人

    据官方此前宣布,三星将于7月26日在韩国首尔举办Unpacked活动,届时将带来带来包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy Z Flip 5、
  • 质感不错!OPPO K11渲染图曝光:旗舰IMX890传感器首次下放

    一直以来,OPPO K系列机型都保持着较为均衡的产品体验,历来都是2K价位的明星机型,去年推出的OPPO K10和OPPO K10 Pro两款机型凭借各自的出色配置,堪称有
  • 苹果MacBook Pro 2021测试:仍不支持平滑滚动

    据10月30日9to5 Mac 消息报道,苹果新的 14 英寸和 16 英寸 MacBook Pro 2021 上市后获得了不错的评价,亮点包括行业领先的性能,令人印象深刻的电池续航,精美丰
  • 北京:科技教育体验基地开始登记

      北京“科技馆之城”科技教育体验基地登记和认证工作日前启动。首批北京科技教育体验基地拟于2023年全国科普日期间挂牌,后续还将开展常态化登记。  北京科技教育体验基
Top