首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GCP为java应用程序调用OOMKiller,但是它不消耗允许的最大内存

GCP为java应用程序调用OOMKiller,但是它不消耗允许的最大内存
EN

Stack Overflow用户
提问于 2020-01-10 10:12:46
回答 3查看 1.8K关注 0票数 3

输入: GCP,Kubernetes,java 11 spring boot 2应用程序

容器的内存限制为1.6GB。Java应用程序也限制了-XX:MaxRAMPercentage=80.0的内存。在“沉重”(并不是真正的)负载下,大约每100毫秒就有一个http请求在大约4小时的时间内被OOMKiller杀死。内部诊断工具显示,内存是远远不够的:

然而,GCP工具显示了以下内容:

有人怀疑GCP在测量其他什么东西吗?POD只包含java应用程序(+jaeger代理)。奇怪的是,在重启之后,GCP显示的内存使用量几乎最大,而不是在内存泄漏的情况下缓慢增长。

编辑:

码头档案:

代码语言:javascript
复制
FROM adoptopenjdk/openjdk11:x86_64-ubuntu-jdk-11.0.3_7-slim
VOLUME /tmp
VOLUME /javamelody
RUN apt-get update && apt-get install procps wget -y
RUN mkdir /opt/cdbg && wget -qO- https://storage.googleapis.com/cloud-debugger/compute-java/debian-wheezy/cdbg_java_agent_gce.tar.gz | tar xvz -C /opt/cdbg
RUN apt-get install fontconfig ttf-dejavu -y
ARG JAR_FILE
ARG VERSION
ARG MODULENAME
ENV TAG=$VERSION
ENV MODULE=$MODULENAME
COPY target/${JAR_FILE} app.jar
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD java -agentpath:/opt/cdbg/cdbg_java_agent.so \
            -Dcom.google.cdbg.module=${MODULE} \
            -Dcom.google.cdbg.version=${TAG} \
            -Djava.security.egd=file:/dev/./urandom \
            -XX:MaxRAMPercentage=80.0 \
            -XX:+CrashOnOutOfMemoryError \
            -XX:ErrorFile=tmp/hs_err_pid%p.log \
            -XX:NativeMemoryTracking=detail \
            -XX:+UnlockDiagnosticVMOptions \
            -XX:+PrintNMTStatistics \
            -XX:+HeapDumpOnOutOfMemoryError \
            -XX:HeapDumpPath=tmp/ \
            -jar /app.jar

并与Kubernetes一起运行它(详细信息包括在内):

代码语言:javascript
复制
apiVersion: apps/v1
spec:
  replicas: {{ .Values.replicas }}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 50%
      maxUnavailable: 0
  template:
    spec:
      initContainers:
        bla-bla
      containers:
        lifecycle:
          preStop:
            exec:
              command: [
                # Gracefully shutdown java
                "pkill", "java"
              ]
        resources:
          limits:
            cpu: 1600
            memory: 1300
          requests:
            cpu: 1600
            memory: 1300

根据顶级命令更新内存限制也是远远不够的,但是在容器是OOMKilled之前,CPU利用率就达到了100%以上。Kubernetes是否有可能杀死试图获得更多CPU的容器?

代码语言:javascript
复制
Tasks:   5 total,   1 running,   4 sleeping,   0 stopped,   0 zombie
%Cpu(s): 34.1 us,  2.0 sy,  0.0 ni, 63.4 id,  0.0 wa,  0.0 hi,  0.5 si,  0.0 st
KiB Mem :  7656868 total,  1038708 free,  2837764 used,  3780396 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  4599760 avail Mem
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
      6 root      20   0 5172744 761664  30928 S 115.3  9.9  21:11.24 java
      1 root      20   0    4632    820    748 S   0.0  0.0   0:00.02 sh
    103 root      20   0    4632    796    720 S   0.0  0.0   0:00.00 sh
    108 root      20   0   38276   3660   3164 R   0.0  0.0   0:00.95 top
    112 root      20   0    4632    788    716 S   0.0  0.0   0:00.00 sh
command terminated with exit code 137

UPDATE2

代码语言:javascript
复制
# pmap -x 7
7:   java -agentpath:/opt/cdbg/cdbg_java_agent.so -Dcom.google.cdbg.module=engine-app -Dcom.google.cdbg.version= -Djava.security.egd=file:/dev/./urandom -XX:MaxRAMPercentage=80.0 -XX:+CrashOnOutOfMemoryError -XX:ErrorFile=tmp/hs_err_pid%p.log -XX:NativeMemoryTracking=detail -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=tmp/ -jar /app.jar
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- java
0000000000400000       0       0       0 r-x-- java
0000000000600000       4       4       4 r---- java
0000000000600000       0       0       0 r---- java
0000000000601000       4       4       4 rw--- java
0000000000601000       0       0       0 rw--- java
00000000006d5000    4900    4708    4708 rw---   [ anon ]
00000000006d5000       0       0       0 rw---   [ anon ]
00000000b0000000   86144   83136   83136 rw---   [ anon ]
00000000b0000000       0       0       0 rw---   [ anon ]
00000000b5420000  350720       0       0 -----   [ anon ]
00000000b5420000       0       0       0 -----   [ anon ]
00000000caaa0000  171944  148928  148928 rw---   [ anon ]
00000000caaa0000       0       0       0 rw---   [ anon ]
00000000d528a000  701912       0       0 -----   [ anon ]
00000000d528a000       0       0       0 -----   [ anon ]
0000000100000000   23552   23356   23356 rw---   [ anon ]
0000000100000000       0       0       0 rw---   [ anon ]
0000000101700000 1025024       0       0 -----   [ anon ]
0000000101700000       0       0       0 -----   [ anon ]
00007f447c000000   39076   10660   10660 rw---   [ anon ]
00007f447c000000       0       0       0 rw---   [ anon ]
00007f447e629000   26460       0       0 -----   [ anon ]
00007f447e629000       0       0       0 -----   [ anon ]
00007f4481c8f000    1280    1164    1164 rw---   [ anon ]
00007f4481c8f000       0       0       0 rw---   [ anon ]
00007f4481dcf000     784       0       0 -----   [ anon ]
00007f4481dcf000       0       0       0 -----   [ anon ]
00007f4481e93000    1012      12      12 rw---   [ anon ]
00007f4481e93000       0       0       0 rw---   [ anon ]
00007f4481f90000      16       0       0 -----   [ anon ]
...
00007ffcfcd48000       8       4       0 r-x--   [ anon ]
00007ffcfcd48000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- -------
total kB         5220936  772448  739852

这个pmap在OOMKilled之前不久就被调用了。5Gb?为什么托普没有展示这个?也不确定如何解释pmap命令结果。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-03-12 07:43:50

在我的例子中,问题在于位于Docker文件CMD行中的调试器组件。

代码语言:javascript
复制
-agentpath:/opt/cdbg/cdbg_java_agent.so \
            -Dcom.google.cdbg.module=${MODULE} \
            -Dcom.google.cdbg.version=${TAG} \
            -Djava.security.egd=file:/dev/./urandom \

拆除后,应用程序停止泄漏。但消失的只有本地内存泄漏。正如后面研究的那样,还存在由jaegger跟踪器组件导致的堆内存泄漏(幸运的是,这里我们有更多的工具)。去除后,应用变得稳定。我不知道这些组件本身是泄漏的,还是与其他组件结合起来的,但事实是,现在它是稳定的。

票数 1
EN

Stack Overflow用户

发布于 2020-01-10 15:51:33

根据日志文件,有超过10,000个已启动的线程。即使我们不考虑为容器保留的少于2个CPU/核心(limits.cpu = request.cpu = 1600毫升),这也是很多事情。

每个线程及其堆栈都在内存中分配,与堆分开。很有可能,大量启动线程是导致OOM问题的原因。

JVM由本机内存跟踪相关选项(-XX:NativeMemoryTracking=detail, -XX:+UnlockDiagnosticVMOptions, -XX:+PrintNMTStatistics) )启动,该选项可以帮助查看内存使用情况,包括这些线程所消耗的内存。这位医生可能是Java11的起点。

无论如何,强烈建议不要启动那么多线程。例如,使用游泳池,在不再需要的时候启动和阻止它们。

票数 4
EN

Stack Overflow用户

发布于 2020-01-13 13:39:55

容器被OOM杀死的原因有两个:容器配额和系统配额。

OOM Killer 只会引发内存相关问题的触发器。

如果您的系统还远远没有耗尽内存,那么您的容器中可能有一个限制。对于您在吊舱内的进程来说,pod资源限制就像整个系统是OOM。

  • 检查您的吊舱清单,可能有一个限制设置在豆荚中。

此外,检查Resource请求也是值得的,因为默认情况下没有设置资源请求。请求必须小于或等于容器限制。这意味着,如果多个容器同时使用比各自请求更多的内存,则容器可能会在节点上过度提交并被OOMK杀死。

  • 检查分配给每个吊舱的内存量以及进程在多长时间内实际使用的内存量。也许它保留的内存比实际需要的要多,并且导致您的内存使用从更高的层次开始。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59679605

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档