【问题标题】:Memory builds up overtime on Kubernetes pod causing JVM unable to start内存在 Kubernetes pod 上超时累积,导致 JVM 无法启动
【发布时间】:2021-02-25 22:09:41
【问题描述】:

我们正在运行一个 kubernetes 环境,并且我们的 pod 遇到了内存问题。 pod 只运行一个容器,而这个容器负责全天运行各种实用程序作业。

问题是这个 pod 的内存使用量随着时间的推移而缓慢增长。此 pod 有 6 GB 的内存限制,最终,内存消耗会增长到非常接近 6GB。

我们的许多实用程序作业都是用 Java 编写的,当 JVM 为它们启动时,它们需要 -Xms256m 才能启动。然而,由于 pod 的内存随着时间的推移而增长,最终它达到了没有 256MB 可用空间来启动 JVM 的地步,Linux oom-killer 杀死了 java 进程。这是我在dmesg 看到的情况:

[Thu Feb 18 17:43:13 2021] Memory cgroup stats for /kubepods/burstable/pod4f5d9d31-71c5-11eb-a98c-023a5ae8b224/921550be41cd797d9a32ed7673fb29ea8c48dc002a4df63638520fd7df7cf3f9: cache:8KB rss:119180KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:119132KB inactive_file:8KB active_file:0KB unevictable:4KB
[Thu Feb 18 17:43:13 2021] [ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name
[Thu Feb 18 17:43:13 2021] [ 5579]     0  5579      253        1       4        0          -998 pause
[Thu Feb 18 17:43:13 2021] [ 5737]     0  5737     3815      439      12        0           907 entrypoint.sh
[Thu Feb 18 17:43:13 2021] [13411]     0 13411     1952      155       9        0           907 tail
[Thu Feb 18 17:43:13 2021] [28363]     0 28363     3814      431      13        0           907 dataextract.sh
[Thu Feb 18 17:43:14 2021] [28401]     0 28401   768177    32228     152        0           907 java
[Thu Feb 18 17:43:14 2021] Memory cgroup out of memory: Kill process 28471 (Finalizer threa) score 928 or sacrifice child
[Thu Feb 18 17:43:14 2021] Killed process 28401 (java), UID 0, total-vm:3072708kB, anon-rss:116856kB, file-rss:12056kB, shmem-rss:0kB

根据我一直在做的研究,here for example,随着各种缓存的增长,Linux 上的内存消耗随着时间的推移而增长似乎是正常的。据我了解,当新进程(例如我的 java 进程)开始运行时,也应该释放缓存的内存。

我的主要问题是:是否应该释放这个 pod 的内存以便这些 java 进程运行?如果是这样,我是否可以采取任何步骤来开始调试为什么这可能无法正确发生?

除了这个担忧之外,我还一直在尝试找出导致内存增长的原因。我能够将其缩小到每 15 分钟运行一次的某个工作。我注意到,每次运行后,Pod 的已用内存都会增加约 .1 GB。

我能够通过在每次执行作业之前和之后运行这个命令(在容器内)来解决这个问题:

cat /sys/fs/cgroup/memory/memory.usage_in_bytes | numfmt --to si

从那里我缩小了内存似乎持续增长的那段 bash 代码。该代码如下所示:

while [ "z${_STATUS}" != "z0" ]
do
    RES=`$CURL -X GET "${TS_URL}/wcs/resources/admin/index/dataImport/status?jobStatusId=${JOB_ID}"`
    _STATUS=`echo $RES | jq -r '.status.status' || exit 1`
    PROGRES=`echo $RES | jq -r '.status.progress' || exit 1`
    [ "x$_STATUS" == "x1" ] && exit 1
    [ "x$_STATUS" == "x3" ] && exit 3
    [ $CNT -gt 10 ] && PrintLog "WC Job ($JOB_ID) Progress: $PROGRES Status: $_STATUS " && CNT=0

    sleep 10
    ((CNT++))
done
[ "z${_STATUS}" == "z0" ] && STATUS=Success || STATUS=Failed

这段代码乍一看对我来说似乎无害,所以我不知道从哪里开始。

我非常感谢任何帮助,我这几天一直在努力解决这个问题。

【问题讨论】:

  • minimal reproducible example 会有所帮助;豆荚里有什么?您的所有 pod 是否都有适当的资源请求,以便它们不会被安排在完整节点上? JVM 会经常使用你给它的内存,那么如果你给它一个更可控的内存限制,你的应用程序是否正常运行?
  • 你用的是什么版本的jvm? jvm 8 及以下不知道容器提供的内存,可能会占用所有系统内存medium.com/faun/docker-sizing-java-application-326d39992592
  • 能否如 Malathi 所述提供您的 Pod 清单文件和 jvm 版本?
  • 大家好,感谢您的回复。我确实阅读了它们,但幸运的是我最终解决了我的问题。如果您想知道这个问题的解决方案,请随时阅读我的​​答案。谢谢!

标签: bash docker kubernetes memory jvm


【解决方案1】:

我最终确实找到了这个问题的根源,所以我想我会在这里发布我的解决方案。我在原始帖子中提到,我将问题缩小到我在上面的问题中发布的 while 循环。每次运行相关作业时,while 循环可能会迭代 10 次。在 while 循环完成后,我注意到每次使用的内存都非常一致地增加了 100MB。

凭直觉,我感觉循环中的CURL 命令可能是罪魁祸首。事实上,事实证明CURL 正在吃掉我的记忆,并且无论出于何种原因都没有释放它。而不是循环并运行以下 CURL 命令:

RES=`$CURL -X GET "${TS_URL}/wcs/resources/admin/index/dataImport/status?jobStatusId=${JOB_ID}"`

我用一个简单的 python 脚本替换了这个命令,该脚本利用requests 模块来检查我们的工作状态。

我仍然不确定为什么 CURL 是这种情况下的罪魁祸首。运行CURL --version 后,使用的底层库似乎是libcurl/7.29.0。也许该库版本中存在导致内存管理问题的错误,但这只是猜测。

无论如何,从使用 python 的 requests 模块而不是 CURL 切换已经解决了我的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-16
    • 2021-08-03
    • 2019-10-24
    • 2021-12-30
    • 2023-04-02
    • 2023-03-28
    • 2021-11-23
    • 2016-12-24
    相关资源
    最近更新 更多