找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

477

积分

1

好友

54

主题
发表于 3 天前 | 查看: 9| 回复: 0

新部署的Kubernetes集群版本为v1.34.1,在部署应用后发现所有Java服务都频繁出现OOM Kill现象。这些服务均已配置了明确的内存request和limit,并将堆内存设置为容器内存的80%。值得注意的是,同样的部署文件在1.30版本的集群上可以正常运行。

经过排查,发现被OOM Kill的Pod中,容器并未正确识别到为其设定的内存限制。例如,一个容器内存限制为1Gi,JVM参数为-XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0 -XX:MetaspaceSize=200m,而宿主机内存为32G。通过Arthas在Pod内查看,发现堆内存远超预期,基本上是按照宿主机内存来计算的,这直接导致了OOM的发生。

Java Heap Memory Setting in Pod

在Pod内执行以下命令进一步确认:

root@xxxxxx:/# java -XshowSettings:vm -version
Picked up JAVA_TOOL_OPTIONS: -XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0 -XX:MetaspaceSize=200m
VM settings:
    Max. Heap Size (Estimated): 23.44G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (build 25.312-b07, mixed mode)

这显然不符合预期。深入排查后发现,问题的根源在于集群使用的CGroup版本。新集群启用了cgroup v2,这导致运行在Pod内的Java应用错误地将宿主机内存当作了容器的可用内存上限。这类似于早年cgroup v1时代,JDK 8u131版本之前的JVM无法自动识别CGroup资源限制的情况,如今在cgroup v2环境下重现了。

如何识别Linux节点上的cgroup版本

cgroup版本取决于Linux发行版及其默认配置。要检查节点使用的cgroup版本,请在该节点上执行以下命令:

stat -fc %T /sys/fs/cgroup/
  • 如果输出为 cgroup2fs,则表示使用的是 cgroup v2
  • 如果输出为 tmpfs,则表示使用的是 cgroup v1

在容器内部,同样可以使用此命令进行验证:

root@xxxx:/# stat -fc %T /sys/fs/cgroup/
cgroup2fs

cgroup v2简介

cgroup v2是Linux cgroup API的下一个演进版本,它提供了一个统一的控制系统,具备更强的资源管理能力。Kubernetes 1.35版本已计划彻底移除对cgroup v1的支持。

相比cgroup v1,cgroup v2带来了多项重要改进,例如:

  • 单一、统一的层次结构设计。
  • 更安全的子树委派机制,更适合容器场景。
  • 新增如压力阻塞信息(Pressure Stall Information,PSI)等特性。
  • 跨CPU、内存、IO等多种资源的增强分配管理与隔离。
  • 统一核算不同类型的内存分配(如网络内存、内核内存)。
  • 更好地处理非即时资源变化,例如页面缓存回写。

对于现代容器化部署和云原生环境,一些Kubernetes高级特性(如MemoryQoS)正是依赖于cgroup v2的原语来实现更精细的内存服务质量控制与隔离。

解决方案

要彻底解决此问题,关键在于为Java应用使用已完全支持cgroup v2的JDK版本。

以下是各主流JDK发行版中,开始完整支持cgroup v2的最低版本号:

  • OpenJDK / HotSpot: jdk8u372、11.0.16、15 及更高的版本
  • IBM Semeru Runtimes: 8.0.382.0、11.0.20.0、17.0.8.0 及更高的版本
  • IBM Java: 8.0.8.6 及更高的版本

验证效果

我们将基础镜像升级至JDK 8u472并重新部署服务。服务配置保持不变:

- name: JAVA_TOOL_OPTIONS
  value: "-XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0 -XX:MetaspaceSize=200m"
...
resources:
  requests:
    memory: 1Gi
  limits:
    memory: 1Gi

容器内存Limit为1Gi,预期堆内存应为1Gi的80%,即约800MiB。再次使用Arthas在Pod内查看,结果符合预期,堆内存上限被正确识别为792M,应用运行稳定,未再发生OOM Kill。

Memory                                       used          total        max          usage        GC
heap                                         164M          792M         792M         20.73%       gc.copy.count                                 31
...
Runtime
os.name                                                                                          Linux
java.version                                                                                     1.8.0_472
...

这表明升级JDK版本后,应用已能正确识别cgroup v2施加的资源限制,内存配置生效,问题得到解决。




上一篇:Kubernetes持久化存储实战指南:Volume、PV、PVC与StorageClass核心概念解析
下一篇:Snowflake与Leaf-Segment时钟回拨处理实战:高并发系统ID生成选型指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-8 17:28 , Processed in 0.095863 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

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