最近,我所在的团队面临着部署微服务(Java+SpringMVC in Docker on AWS)的问题。主要问题是,很多非常轻巧的应用程序消耗了太多的内存。因此,我们经过多方尝试找到了在Docker中关于Java内存消耗的问题,并通过重构和迁移到Spring Boot实现了减少消耗的方法。本文,我将和大家分享这整个过程,希望能够对大家有所帮助。

在部署之前,我们要估计应用程序消耗多少内存。为此,我们制定了一个清晰简单的方程来找到RSS:

RSS = Heap size + MetaSpace + OffHeap size

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

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

让我们根据本地Java VisualVM值找到它:

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

所以,我们得出结果:大概600Mb就够了。我们选择了一个t2.micro AWS实例(具有1Gb RAM)进行部署,并开始部署应用程序。首先,通过JVM选项提供有关内存配置的一些信息:

此外,作为应用程序的基础图像,我们选择了 ,因为我们发现它是 Jetty Java *.wars中最轻量级的图像之一。

正如前文所提到的600Mb就足够了,所以启动了一个容器,其容量如下:

docker run -m 600m

那么你觉得这样会发生什么?我们的集装箱会由于内存不足被DD(Docker daemon)杀死。这个容器是在本地启动的,具有完全相同的参数,通过逐步增加容器的内存限制,我们达到了700…我开玩笑的,我们有850mb。

经过观察和阅读有用的文章,我们决定进行测量。结果是非常奇怪和有争议的。

Heap Size与我们本地相同:

  但Docker显示了一些疯狂的统计数据:

  发生了什么事?情况变得非常混乱...

我们花了很多时间去搞清楚这些数据为什么会有争议,在搜索过程中发现我们并不是个例。在查找了很多资料,分析了 应用之后,我们几乎找到了答案。大部分额外的内存都是被用于存储编译的类及其元数据。

那么有关JavaVM / Docker统计数据的争议数字呢?事实证明,Java VisualVM不了解OffHeap的内容,因此,使用此工具调查Java应用程序的内存消耗会非常棘手。此外,了解您使用的JVM选项也是至关重要。在我看来,指定-Xmx=512m告诉JVN分配512mb Heap,但是它并不告诉JVM整个内存使用要限制在512mb,所以就会出现代码缓存和其它非Heap数据占用内存直至超过。所以,要指定总内存需要使用XX:MaxRAM参数。请注意,使用MaxRam = 512m,你的Heap约为250mb,这时就要注意应用程序JVM选项。

星期一早上,寻找灵丹妙药...

NMT和Java VisualVM Memory Sampler 可以帮助我们发现内部核心框架在内存中多次重写的依赖,并且重复的数量等于微服务中子模块的数量。如果想要更好的掌握这一点,首先要说明一下我们的“微服务”结构:

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

据我所知,构建这样的应用程序是一个很大的错误。首先,每个* .war已经作为一个单独的应用程序部署在Jetty servlet容器中,这是非常奇怪的。因为根据定义,微服务应该是一个部署应用程序(部署单元)。其次,Jetty在内存中分别保存每个* .war的所有必需库,即使所有这些库具有相同的版本。因此,DB连接、核心框架的各种基本功能等都会在内存中重复。

一般的解决方案就是重构,让应用成为真正的微服务器。此外,我们可能还需要一整套的Jetty,但是一般人听到它的报价就能望而却步。圈内有句著名的评论“不要在Jetty中部署应用程序,而是要在应用程序中部署Jetty。

我们决定尝试使用嵌入式Jetty的Spring Boot,因为它是独立应用程序中最常用的工具,尤其是在我们的案例中。配置很少,没有XML,每个Spring框架都有优势,还有很多插件,自动配置。除此之外,网上还有大量的实用教程和文章,这些都让Spring Boot看起来是个不错的选择。

由于我们不再需要单独的Jetty应用程序服务器,所以我们将基础Docker的图像更改为轻量级的openjdk。

openjdk:8-jre-alpine

根据新的要求重构了应用程序之后,我们得到了类似下图的东西:

  现在一切都准备好了,我们来测试一下。

先从Java VirtualVM进行测试:

从数据中可以看出,虽然新版本有了一些改进,但是与之前的应用程序相比变化并没有那么大:

  然后,我们再来看看Docker的统计数据:

  结果很明显,我们已经减少了内存消耗。

结论

对我们团队来说,这是一个很有意思的挑战。找到导致错误或者某件事情的根本原因,会让你在特定领域中看得更深更广。网上的资源非常丰富,如果你下定决心去查找答案,那么就一定会找得到。另外,从这次事件中也认识到,不要完全信任Java VisualVM的内存消耗预计。

对于技术的学习和性能的提高,我有三个更多和大家分享,,改进更多,调查更多。另外,避免常规,尽可能自动化,这样你可以更有效的进行工作。

本文转自d1net(转载)

实例解读:如何减少Docker中的Java内存消耗相关推荐

  1. Docker中的Java内存消耗优化以及我们如何使用Spring Boot

    ---- / BEGIN/ ---- 如果您的Docker容器占用太多内存而无法达到最佳性能,请阅读下文以了解一个团队如何找到解决方案. 最近,我所在的团队在部署我们的微服务(AWS上Docker中的 ...

  2. 修改docker内java内存_在docker中使用java的内存情况

    Java和Docker不是天然的朋友. Docker可以设置内存和CPU限制,而Java不能自动检测到.使用Java的Xmx标识(繁琐/重复)或新的实验性JVM标识,我们可以解决这个问题. 虚拟化中的 ...

  3. Docker学习总结(24)——在Docker中监视Java应用程序的5种方法

    说明:根据国外https://www.javacodegeeks.com/2017/07/docker-monitoring-5-methods-monitoring-java-application ...

  4. java关闭服务_实现优雅地关闭Docker中的java服务

    时至今日,Docker在项目中的应用越来越普遍了,但往往会遭遇一些麻烦,比如说,有几个请求至Docker中的服务,发起了事务处理业务,但每个事务完成可能需要1-5分钟,而此时我们正要将Docker停机 ...

  5. 在Docker中安装Java

    所有的环境安装,都是在centos系统中操作的,并非本地windows系统. 查看 docker 中是否已经存在 java jdk 镜像:docker images 如果本地还没有,则可以进行搜索 D ...

  6. Java——聊聊JUC中的Java内存模型(JMM)

    文章目录: 1.CPU缓存模型 2.Java内存模型Java Memory Model 3.JMM规范下的三大特性 3.1 原子性 3.2 可见性 3.3 有序性 4.JMM规范下,多线程对变量的读写 ...

  7. 《深入理解JAVA虚拟机》详细解读(第二章 ):JAVA内存区域与内存溢出异常

    目录 一.JAVA内存区域与内存溢出异常 1. 概述 2. 运行时数据区域 2.1 程序计数器 2.2 Java虚拟机栈 2.3本地方法栈 2.4 堆 2.5 方法区 2.6 运行时常量池 2.7直接 ...

  8. c++ 进程快照_如何在 Linux 中找出内存消耗最大的进程

    很多次,你可能遇见过系统消耗了过多的内存.如果是这种情况,那么最好的办法是识别出 Linux 机器上消耗过多内存的进程. -- Magesh Maruthamuthu(作者) 很多次,你可能遇见过系统 ...

  9. 如何在 Linux 中找出内存消耗最大的进程

    很多次,你可能遇见过系统消耗了过多的内存.如果是这种情况,那么最好的办法是识别出 Linux 机器上消耗过多内存的进程.我相信,你可能已经运行了下文中的命令以进行检查.如果没有,那你尝试过哪些其他的命 ...

最新文章

  1. 创意赛第二季又来了,PaddleHub人脸关键点检测实现猫脸人嘴特效
  2. 谷歌新语言重写android,谷歌将推新设计语言 安卓APP用户界面将换新颜
  3. 新来乍到,谢谢大家捧场
  4. [HTML] 关于DIV被Flash或表单遮盖的解决方法
  5. Vijos P1335 数独验证【谜题】
  6. KNN——K nearest neighbor
  7. 【LeetCode】【数组】题号:56,重塑矩阵
  8. PHP-----strpos() 函数的用法
  9. C语言程序设计谭浩强(第四版)期末复习重点
  10. 深信服短信认证云信通短信配置说明
  11. tp5商城购物系统(后台管理+个人中心+购物车)
  12. RocketMQ(十)RocketMQ事务消息
  13. redis---sds(简单动态字符串)详解
  14. SAP中采购协议价格条件导致的物料成本核算取价问题实例
  15. 服务器主板存储系统信息,4核 ARM 存储服务器 ATX主板——领存技术
  16. 每个程序员都应该读的非编程书
  17. 将计算机移动到桌面,如何将图标移动到桌面 移动桌面图标的方法分享
  18. 计算机怎么打开隐藏的项目,展示win10系统怎么打开隐藏文件夹
  19. Nginx反向代理的两种配置方式
  20. android手机图标 足球球星,盘点六大世界足坛球星logo,贝尔艺术感十足

热门文章

  1. ios键盘弹回时顶上去得页面不会回来
  2. 小郡肝火锅点餐系统——项目文档
  3. python学习 day1 (3月1日)
  4. Springboot @Transactional Mysql事务 无效
  5. setCharacterEncoding 是在request.getParameter获取参数之前 设置request的编码格式 一步到位...
  6. 最近做项目遇到的一些小问题
  7. JDBC模板对象是多例的
  8. Java MVC框架性能比较
  9. VisualSVN Server 修改用户密码
  10. 诗与远方:无题(八十五)- 无字天书