gpt4 book ai didi

java - Kubernetes,简单的 SpringBoot 应用程序 OOMKilled

转载 作者:行者123 更新时间:2023-12-02 07:32:22 27 4
gpt4 key购买 nike

我正在使用 OpenJDK 11 和一个非常简单的 SpringBoot 应用程序,它几乎唯一的功能就是启用了 SpringBoot 执行器,因此我可以调用 /执行器/健康 等等

我在 GCE 上也有一个 kubernetes 集群,非常简单,只有一个带有容器的 pod(当然包含这个应用程序)

我的配置有一些我想强调的关键点,它有一些要求和限制

resources:
limits:
memory: 600Mi
requests:
memory: 128Mi

它有一个就绪探针
readinessProbe:
initialDelaySeconds: 30
periodSeconds: 30
httpGet:
path: /actuator/health
port: 8080

我还设置了一个 JVM_OPTS (我的程序显然正在使用)
env:
- name: JVM_OPTS
value: "-XX:MaxRAM=512m"

问题

我启动它,每次大约 3 小时后它就会被 OOMKilled!

我自己从来没有调用任何东西,唯一的调用是 kubernetes 每 30 秒进行一次就绪探测,这足以耗尽内存吗?我也没有实现任何不寻常的东西,只是一个 Get 方法,它在所有 SpringBoot 导入中说 hello world 以拥有执行器

如果我运行 kubectl top pod XXXXXX,我实际上会看到如何逐渐变大

我尝试了很多不同的配置、技巧等,但任何东西似乎都适用于基本的 SpringBoot 应用程序

有没有办法以 Java 可以引发 OutOfMemory 异常的方式实际硬限制内存?或防止这种情况发生?

提前致谢

编辑:运行 15 小时后
NAME                        READY   STATUS    RESTARTS   AGE
pod/test-79fd5c5b59-56654 1/1 Running 4 15h

描述 pod 说……
State:          Running
Started: Wed, 27 Feb 2019 10:29:09 +0000
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Wed, 27 Feb 2019 06:27:39 +0000
Finished: Wed, 27 Feb 2019 10:29:08 +0000

最后的时间跨度大约是 4 小时,只有 483 次调用/actuator/health,显然这足以让 java 超过 MaxRAM 提示?

编辑:差不多 17 小时

它又要死了
$ kubectl top pod test-79fd5c5b59-56654

NAME CPU(cores) MEMORY(bytes)
test-79fd5c5b59-56654 43m 575Mi

编辑:在 23 小时失去任何希望
NAME                        READY   STATUS    RESTARTS   AGE
pod/test-79fd5c5b59-56654 1/1 Running 6 23h

描述 pods :
State:          Running
Started: Wed, 27 Feb 2019 18:01:45 +0000
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Wed, 27 Feb 2019 14:12:09 +0000
Finished: Wed, 27 Feb 2019 18:01:44 +0000

编辑:新发现

昨天晚上我在读一些有趣的书:

https://developers.redhat.com/blog/2017/03/14/java-inside-docker/
https://banzaicloud.com/blog/java10-container-sizing/
https://medium.com/adorsys/jvm-memory-settings-in-a-container-environment-64b0840e1d9e

TL;DR 我决定取消内存限制并重新启动该过程,结果非常有趣(运行了大约 11 个小时后)
NAME                    CPU(cores)   MEMORY(bytes)   
test-84ff9d9bd9-77xmh 218m 1122Mi

那么......那个CPU的WTH?我有点期待内存使用量很大,但是 CPU 会发生什么?

我能想到的一件事是 GC 正在疯狂地运行,认为 MaxRAM 是 512m 并且他正在使用超过 1G。我想知道,Java 是否正确检测人体工程学? (我开始怀疑了)

为了测试我的理论,我设置了 512m 的限制并以这种方式部署应用程序,我发现从一开始就有一个不寻常的 CPU 负载,它必须是 GC 非常频繁地运行
kubectl create ...

limitrange/mem-limit-range created
pod/test created

kubectl exec -it test-64ccb87fd7-5ltb6 /usr/bin/free
total used free shared buff/cache available
Mem: 7658200 1141412 4132708 19948 2384080 6202496
Swap: 0 0 0

kubectl top pod ..
NAME CPU(cores) MEMORY(bytes)
test-64ccb87fd7-5ltb6 522m 283Mi

522m 是太多的 vCPU,所以我合乎逻辑的下一步是确保我在这种情况下使用最合适的 GC,我以这种方式更改了 JVM_OPTS:
  env:
- name: JVM_OPTS
value: "-XX:MaxRAM=512m -Xmx128m -XX:+UseSerialGC"
...
resources:
requests:
memory: 256Mi
cpu: 0.15
limits:
memory: 700Mi

这就是在 kubectl top pod 之后再次将 vCPU 使用率恢复到合理的状态。
NAME                    CPU(cores)   MEMORY(bytes)   
test-84f4c7445f-kzvd5 13m 305Mi

与具有 MaxRAM 的 Xmx 混在一起显然会影响 JVM,但是如何无法控制我们在虚拟化容器上拥有的内存量?我知道 free命令将报告主机可用 RAM 但 OpenJDK 应该使用 cgroups 对吧?

我还在监视内存...

编辑:新的希望

我做了两件事,第一件事是再次删除我的容器限制,我想分析它会增长多少,我还添加了一个新标志来查看进程如何使用 native 内存 -XX:NativeMemoryTracking=summary
一开始一切正常,进程通过 kubectl top pod开始消耗300MB所以我让它运行了大约 4 个小时,然后......
kubectl top pod

NAME CPU(cores) MEMORY(bytes)
test-646864bc48-69wm2 54m 645Mi

有点预期,对吧?但后来我检查了 native 内存使用情况
jcmd <PID> VM.native_memory summary

Native Memory Tracking:

Total: reserved=2780631KB, committed=536883KB
- Java Heap (reserved=131072KB, committed=120896KB)
(mmap: reserved=131072KB, committed=120896KB)

- Class (reserved=203583KB, committed=92263KB)
(classes #17086)
( instance classes #15957, array classes #1129)
(malloc=2879KB #44797)
(mmap: reserved=200704KB, committed=89384KB)
( Metadata: )
( reserved=77824KB, committed=77480KB)
( used=76069KB)
( free=1411KB)
( waste=0KB =0.00%)
( Class space:)
( reserved=122880KB, committed=11904KB)
( used=10967KB)
( free=937KB)
( waste=0KB =0.00%)

- Thread (reserved=2126472KB, committed=222584KB)
(thread #2059)
(stack: reserved=2116644KB, committed=212756KB)
(malloc=7415KB #10299)
(arena=2413KB #4116)

- Code (reserved=249957KB, committed=31621KB)
(malloc=2269KB #9949)
(mmap: reserved=247688KB, committed=29352KB)

- GC (reserved=951KB, committed=923KB)
(malloc=519KB #1742)
(mmap: reserved=432KB, committed=404KB)

- Compiler (reserved=1913KB, committed=1913KB)
(malloc=1783KB #1343)
(arena=131KB #5)

- Internal (reserved=7798KB, committed=7798KB)
(malloc=7758KB #28415)
(mmap: reserved=40KB, committed=40KB)

- Other (reserved=32304KB, committed=32304KB)
(malloc=32304KB #3030)

- Symbol (reserved=20616KB, committed=20616KB)
(malloc=17475KB #212850)
(arena=3141KB #1)

- Native Memory Tracking (reserved=5417KB, committed=5417KB)
(malloc=347KB #4494)
(tracking overhead=5070KB)

- Arena Chunk (reserved=241KB, committed=241KB)
(malloc=241KB)

- Logging (reserved=4KB, committed=4KB)
(malloc=4KB #184)

- Arguments (reserved=17KB, committed=17KB)
(malloc=17KB #469)

- Module (reserved=286KB, committed=286KB)
(malloc=286KB #2704)

等等,什么? 2.1 GB 预留给线程?并且正在使用 222 MB,这是什么?我现在不知道,我只是看到它...

我需要时间来了解为什么会这样

最佳答案

我终于找到了我的问题,我想分享它,以便其他人可以以某种方式从中受益。

正如我在上次编辑中发现的那样,我遇到了一个线程问题,随着时间的推移导致所有内存消耗,特别是我们使用了来自第三方库的异步方法,而没有正确处理这些资源(确保这些调用在这种情况下正确结束)。

我能够检测到这个问题,因为我从一开始就在我的 kubernete 部署中使用了内存限制(这在生产环境中是一个很好的做法),然后我使用像 jstat, jcmd, visualvm, kill -3 这样的工具非常密切地监控了我的应用程序内存消耗。最重要的是-XX:NativeMemoryTracking=summary在这方面给了我很多细节的标志。

关于java - Kubernetes,简单的 SpringBoot 应用程序 OOMKilled,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54892977/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com