Docker 的 Java 内存消耗异常怎么办?

本文来自于HeapDump性能社区! !有性能问题,上HeapDump性能社区!
最近,我所在的团队在部署我们的微服务(AWS 上的 Docker 中的 Java+SpringMVC)时遇到了问题,一个非常轻量级的应用却消耗了太多内存。于是,我们在 Docker 中发现了许多关于 Java 内存的线索,并找到了通过重构和迁移到 Spring Boot 来减少其消耗的解决方法。

这里分享一下整个过程:

在部署微服务之前,我们惯例要预估下内存,于是制定了一个清晰且简单的方程式来找到RSS

RSS = Heap size + MetaSpace + OffHeap size

这里的OffHeap由线程堆栈、缓冲区、库 (*.jars) 和 JVM 代码本身组成。

Resident Set Size是当前分配给进程并由进程使用的 RAM 量。它包括代码、数据和共享库。

我们根据本地 Java VisualVM 值来查找:

1.png

2.png

3.png
RSS = 253(Heap) + 100(Metaspace) + 170(OffHeap) + 52*1(Threads) = 600Mb (max avarage)

……看完这个,当时觉得万事大吉,就等完成了撸串去!

既然大概600Mb就够了。我们就选择了一个 t2.micro AWS 实例(具有 1Gb RAM)进行了部署。

首先,去JVM 设置了一些和内存相关的配置:

-XX:MinHeapFreeRatio=10 \
-XX:MaxHeapFreeRatio=70 \
-XX:CompressedClassSpaceSize=64m \
-XX:ReservedCodeCacheSize=64m \
-XX:MaxMetaspaceSize=256m \
-Xms256m \
-Xmx750m \

然后,选择了 *jetty:9-alpine *作为程序的基础镜像,毕竟它是 Jetty 中 Java *.wars 最轻量级的镜像之一。

最后,既然 600Mb 就够了,那就得启动一下内存限制的docker容器:

docker run -m 600m

转折来了!

由于内存不足,启动以后,容器就被 DD(Docker 守护进程)杀死了

很奇怪,** 毕竟这个容器已经 使用完全相同的参数**在本地启动。

于是我们通过逐步增加容器的内存限制,我们达到了850Mb。

为什么?百思不得其解!

于是到处找了一些文章,看来别人的一些案例以后,我们决定进行了一些分析,尝试定位问题。

结果争议更大了!

  • 堆大小与我们之前的(本地)启动相同:


    selection-007.png
  • 但 Docker 显示了一些疯狂的统计数据:


    selection-010.png

why?问题越来越多了!

我们花了很多时间为这些有争议的数字寻找解释,发现并不是只有我们遇到了类似问题。

在阅读了更多文章,并使用 Native Memory Tracker 分析了程序以后,得出一个结论:

原来大多数额外内存已用于存储已编译的类及其元数据。你也许会问那JavaVM/Docker 统计数据呢?事实证明,Java VisualVM 对 OffHeap 一无所知,因此,使用此工具调查 Java 应用程序的内存消耗可能完全没用。

此外,了解你设置的 JVM 参数配置也很重要。我们发现虽然指定 - Xmx=512m告诉 JVM 分配一个512mb的堆,但是它并没有告诉 JVM 将其整个内存使用量限制为512mb

有代码缓存和各种其他堆外数据时,要指定总内存,您应该使用 -XX:MaxRAM参数。请注意,在MaxRam=512m时,您的堆大约为 250mb。小心并注意您的应用程序 JVM 选项。

于是我们继续深入,寻找解决方案:

NMT 和 Java VisualVM Memory Sampler 帮助我们发现我们的内部核心框架在内存中被多次复制为依赖项。重复的数量等于我们微服务中子模块的数量。为了更好地理解这一点,我想说明我们的“微服务”结构:


microservice.png

这是 NMT(在我的本地机器上)为一个模块(加载了73MB的类元数据、42MB线程和37MB的代码,包括库)的快照:

7.png

据我们所知,以这种方式构建我们的程序是一个大错误。首先,每个 *.war 都作为一个单独的应用程序部署在一个 Jetty servlet 容器中,这很奇怪,首先根据定义,微服务应该是一个用于部署的应用程序(部署单元)。

其次,Jetty 在内存中分别保存每个 *.war 所需的所有库,即使所有这些库都具有相同的版本。结果,数据库连接、核心框架中的各种基本功能等都在内存中复制。

一个常识性的解决方案是重构并使我们的应用程序成为真正的微服务。此外,我们怀疑我们是否需要一整包 Jetty,更何况网上都在警告:

“不要在 Jetty 中部署你的程序,要在你的程序中部署 Jetty。”

我们决定尝试使用嵌入式 Jetty 的 Spring Boot,因为它似乎是独立应用程序最常用的工具,尤其是在我们的案例中。很少的配置,没有 XML,每个 Spring 框架的优势和很多(很多)插件,它们会自动配置自己。有大量实用教程和文章展示了如何在互联网上使用它。

此外,由于我们不再需要单独的 Jetty 应用程序服务器,我们将基础 Docker 映像更改为简单的轻量级OpenJDK

openjdk:8-jre-alpine

然后,我们根据新的需求重构了我们的应用程序。在一天结束时,我们得到了类似的东西:


improved.png

既然有了想法,那就去试!

问题解决了么?

让我们从我们的 Java VirtualVM 进行测量。


selection-003.png

selection-005.png
selection-004.png

唔。看起来我们做了一些改进,但与以前版本的应用程序的所有努力和结果相比,并没有那么大:

table.png

但是让我们看一下 Docker 统计数据:


selection-006.png

万岁!我们的内存消耗减半。

结论

这对我们的团队来说是一个很好且有趣的挑战。试图找出问题的根因可以让你发现真相,并让你找到特定领域的知识盲区。

同时要相信社区的力量,不要重复造轮子,你遇到的问题别人也遇到过!你可以在社区找到各类案例和答案。另外,不要完全相信来自 Java VisualVM 的内存消耗估计,哈哈。

更多案例:
又发现一个导致JVM物理内存消耗大的Bug(已提交Patch)

一文深度分析Java内存模型

一次 Java 内存泄漏排查过程,涨姿势

小心踩雷,一次Java内存泄漏排查实战

分析和解决JAVA 内存泄露的实战例子

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容