我正在使用OpenJDK 11和一个非常简单的SpringBoot应用程序,它几乎唯一具有的功能是启用了SpringBoot执行器,因此我可以调用 / actuator / health 等。
我在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个小时它就会被OOM杀死!
我从不给自己打电话,唯一的电话就是kubernetes每30秒进行一次就绪探针,这足以耗尽内存吗?我也没有实现任何异常,只是实现了一个Get方法,该方法在所有SpringBoot导入中都向您问好,以显示执行器
如果我运行kubectl顶部吊舱XXXXXX,我实际上会看到它逐渐变得越来越大
我尝试了许多不同的配置,技巧等,但是似乎所有基本SpringBoot应用程序都可以使用
是否有一种方法可以通过Java引发OutOfMemory异常的方式来硬限制内存?或防止这种情况发生?
预先感谢
NAME READY STATUS RESTARTS AGE
pod/test-79fd5c5b59-56654 1/1 Running 4 15h
描述豆荚说...
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小时,仅对/ actuator / health进行了483次调用,显然足以使Java超过MaxRAM提示吗?
它又要死了
$ kubectl top pod test-79fd5c5b59-56654
NAME CPU(cores) MEMORY(bytes)
test-79fd5c5b59-56654 43m 575Mi
NAME READY STATUS RESTARTS AGE
pod/test-79fd5c5b59-56654 1/1 Running 6 23h
描述豆荚:
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有什么用?我希望内存使用量很大,但是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
NAME CPU(cores) MEMORY(bytes)
test-84f4c7445f-kzvd5 13m 305Mi
使用具有MaxRAM的Xmx进行处理显然会影响JVM,但如何控制虚拟容器上的内存量又又如何呢?我知道free
命令将报告主机可用的RAM,但是OpenJDK应该使用 cgroups rihgt?。
我仍在监视内存...
我做了两件事,第一件事是再次删除我的容器限制,我想分析它会增长多少,还添加了一个新标志来查看该进程如何使用本机内存-XX:NativeMemoryTracking=summary
起初,一切正常,开始通过kubectl top pod
消耗300MB内存,因此我让它运行大约4个小时,然后...
kubectl top pod
NAME CPU(cores) MEMORY(bytes)
test-646864bc48-69wm2 54m 645Mi
有点期望吧?但后来我检查了本机内存使用情况
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正在使用,这是什么?我目前不知道,我只是看到了...
我需要时间来了解为什么会发生
答案 0 :(得分:0)
我终于找到了自己的问题,并希望与他人分享,以便其他人可以从中以某种方式受益。
正如我在上一次编辑中发现的那样,我遇到了一个线程问题,该问题导致了一段时间后所有内存的消耗,特别是我们在使用第三方库中的异步方法时未适当照顾那些资源(确保这些调用正确结束)在这种情况下)。
之所以能够检测到该问题,是因为我从一开始就在kubernete部署中使用了内存限制(这在生产环境中是一种很好的做法),然后我使用{{1} },最重要的是jstat, jcmd, visualvm, kill -3
标志在这方面给了我很多细节。