JVM堆内存大小是越大越好吗?

国际新闻 阅读(813)

我想在4天前分享前锋JAVA开发学院

本文为您提供了生产环境的实践经验:部署在线系统时,JVM堆内存大小越大越好?

让我谈一个前提。本文主要讨论两个分布式系统Kafka和Elasticsearch的在线部署,而不是普通的Java应用程序系统。

1.它是否依赖Java系统自身的内存来处理数据?

首先,无论是我们自己的Java应用程序系统还是某个中间件系统,您都需要根据自己的Java进程的内存来选择是否处理数据。

每个人都应该知道Java,Scala和其他编程语言都依赖于底部的JVM,因此,只要您使用JVM,就可以考虑将大量数据放置在JVM进程的内存中。

让我给你举个例子。您应该记得之前谈论过中间件系统。

例如,系统A可以将消息发送到系统B,然后中间层需要依赖消息中间件,系统A必须首先将消息发送到消息中间件,然后系统B使用消息中间件中的消息。

让我们看看下面的示意图

每个人都应该知道,在将消息发送到消息中间件之后,有一种方法可以将该数据缓冲在其自己的JVM内存中。

然后过一会儿,从您自己的内存刷新到磁盘,这样您就可以保留此消息,如下所示。

2,依靠Java系统自身的内存缺陷

如果使用与上述类似的方法来依靠Java系统自身的内存来处理数据,例如设计一个内存缓冲区来缓冲同时写入的大量消息,则存在缺陷。

最大的缺陷实际上是JVM的GC问题。此GC是垃圾回收。这是正在发生的事情的简要说明。

您可以考虑一下。如果Java进程总是放入大量数据,则使用该数据将其缓冲在内存中,但是过一会儿,该数据将被写入磁盘。

然后,写入磁盘后,数据是否需要继续保存在内存中?

显然不需要。此时,依靠JVM垃圾收集机制,将回收内存中不需要的数据,并释放内存空间。

但是,当JVM进行垃圾回收时,有一种情况称为“停止世界”,也就是说,他将停止您的工作线程,特别是让他进行垃圾回收。

这时,当他处于垃圾回收中时,中间件系统可能无法运行。

例如,如果您向他发送请求,他可能无法响应您,因为他的接收请求的工作线程已停止,并且此人后台的垃圾收集线程现在正在回收垃圾对象。

让我们看一下下面的图片:

尽管JVM垃圾收集器一直在不断发展和发展,但从CMS到G1尽可能地减少垃圾收集的影响,减少工作线程的暂停。

但是,如果您完全依靠JVM内存来管理大量数据,那么它对垃圾回收的影响或多或少。

因此,特别是对于某些大数据系统,中间件系统,这个JVM的GC(垃圾收集器,垃圾收集)问题确实令人头疼。

3.优化以依赖OS Cache而不是JVM

因此,尽管分布式中间件系统(如Kafka和Elasticsearch)虽然运行在JVM上,却选择依靠OS Cache来管理大量数据。

换句话说,它是操作系统管理的内存缓冲区,而不是依靠JVM自己的内存来管理大量数据。

具体来说,例如,Kafka,如果您向Kafka写入数据,他实际上将直接写入磁盘文件。

但是磁盘文件实际上会在写入之前进入os缓存,这是操作系统管理的内存空间。一段时间后,操作系统本身将选择将其os缓存的数据刷新到磁盘。

然后,实际上,在随后的数据消耗中,它还将优先从os缓存(内存缓冲区)读取数据。

写入数据和读取数据的等效性基于os缓存。它完全取决于操作系统级别的内存区域,并且读写性能非常高。

此外,还有另一个好处:不要依靠自己的JVM来缓冲大量数据,从而避免了复杂而费时的JVM垃圾回收操作。

看下面的图片,它实际上是一个典型的Kafka运行过程。

然后,像Elasticsearch一样,他是最受欢迎的分布式搜索系统,并且使用类似的机制。

大量的os缓存用于缓冲大量数据,并且在搜索和查询时,可以首先从os缓存(内存区域)读取数据,从而可以保证很高的读写性能。

4.谈论经验

取决于os缓存的JVM内存越大,效果越好?

现在您可以输入主题,上面提到的kafka,elasticsearch和其他系统,在线生产环境的部署,依靠os缓存来缓冲大量数据。

那么,分配给它们的JVM堆内存越大越好?

显然没有,如果您有一台计算机,则需要32GB的内存,如果您无法弄清情况,您会傻傻地认为分配给JVM的内存越大,例如为JVM提供16G堆内存空间就越好。

然后分配它,操作系统缓存的剩余内存可能少于10GB,因为其他程序本身会占用几GB的内存。

如果是这种情况,将导致在写入磁盘时os缓存可以容纳的数据量有限。

例如,如果要总共将20G数据写入磁盘,则os缓存中只能放置10GB的数据,然后只能在磁盘上放置另外10GB的数据。

此时,在读取数据时,必须至少从磁盘读取一半的读取请求,而不能从os缓存中读取,如下所示:

此时,您的请求中有一半正在从磁盘读取数据,这将不可避免地导致性能下降。

如此之多的人在使用Elastic搜索时就遇到了这样的问题,总觉得ES的读取速度慢,亿万数据写入ES,读取时间需要几秒钟。

可以花几秒钟吗?如果部署ES群集,则会在JVM中保留过多的内存,而在OS缓存中保留几GB的内存,从而导致数亿的数据主要在磁盘上,而不是在OS缓存中。最终读取大量磁盘是很正常的,这需要花费几秒钟的时间。

5.正确练习

为方案合理地为OS缓存提供更多内存

因此,在部署诸如Kafka和Elasticsearch之类的生产系统时,您应该为JVM提供6GB或数GB的内存。

因为它们可能不需要占用过多的内存空间,所以不必依赖JVM内存管理数据,当然,具体的设置数量需要精确测量和优化。

但是对于此类系统,应为OS缓存提供足够的内存空间

例如,一台32GB的内存计算机可以为OS缓存保留20 GB以上的内存空间。这时,假设您的计算机总共写入了20 GB的数据,则可以全部驻留在OS缓存中。

然后,当您查询数据时,您无法完全依靠内存从OS缓存中读取所有数据,那么您的性能必须以毫秒为单位,这不可能在几秒钟内完成查询。

整个过程如下所示:

因此,建议在将任何技术引入在线生产系统时,我们应该首先对该技术的原理,甚至是源代码有透彻的了解,以了解具体的工作流程,然后设计该产品的部署计划。生产环境,以确保最佳的生产性能。

馆藏报告投诉

在本文中,我们将讨论生产环境的实践经验:在部署在线系统时,JVM堆内存大小越大越好?

让我们从一个前提开始。本文主要讨论Kafka和Elasticsearch分布式系统的在线部署,而不是普通的Java应用程序系统。

1. Java系统是否依靠自己的内存来处理数据?

首先,无论是开发自己的Java应用程序系统还是某些中间件系统,我们都需要根据自己的Java进程的内存来选择是否处理数据。

众所周知,Java,Scala和其他编程语言在底部都依赖JVM,因此,只要您使用JVM,就可以考虑将大量数据放入JVM进程的内存中。

仍然给您一个例子,您应该记得之前谈论过消息中间件系统。

例如,系统A可以向系统B发送消息,因此它需要依赖消息中间件。系统A首先将消息发送到消息中间件,然后系统B使用消息中间件中的消息。

让我们看一下下面的草图。

众所周知,在将消息发送到消息中间件之后,有一种处理消息的方法,即将数据缓存在其自己的JVM内存中。

然后,在一段时间后,将消息从内存刷新到磁盘,以便可以保留该消息,如下所示。

2,依靠Java系统自身的内存缺陷

如果使用与上述类似的方法来依靠Java系统自身的内存来处理数据,例如设计一个内存缓冲区来缓冲同时写入的大量消息,则存在缺陷。

最大的缺陷实际上是JVM的GC问题。此GC是垃圾回收。这是正在发生的事情的简要说明。

您可以考虑一下。如果Java进程总是放入大量数据,则使用该数据将其缓冲在内存中,但是过一会儿,该数据将被写入磁盘。

然后,写入磁盘后,数据是否需要继续保存在内存中?

显然不需要。此时,依靠JVM垃圾收集机制,将回收内存中不需要的数据,并释放内存空间。

但是,当JVM进行垃圾回收时,有一种情况称为“停止世界”,也就是说,他将停止您的工作线程,特别是让他进行垃圾回收。

这时,当他处于垃圾回收中时,中间件系统可能无法运行。

例如,如果您向他发送请求,他可能无法响应您,因为他的接收请求的工作线程已停止,并且此人后台的垃圾收集线程现在正在回收垃圾对象。

让我们看一下下面的图片:

尽管JVM垃圾收集器一直在不断发展和发展,但从CMS到G1尽可能地减少垃圾收集的影响,减少工作线程的暂停。

但是,如果您完全依靠JVM内存来管理大量数据,那么它对垃圾回收的影响或多或少。

因此,特别是对于某些大数据系统,中间件系统,这个JVM的GC(垃圾收集器,垃圾收集)问题确实令人头疼。

3.优化以依赖OS Cache而不是JVM

因此,尽管分布式中间件系统(如Kafka和Elasticsearch)虽然运行在JVM上,却选择依靠OS Cache来管理大量数据。

换句话说,它是操作系统管理的内存缓冲区,而不是依靠JVM自己的内存来管理大量数据。

具体来说,例如,Kafka,如果您向Kafka写入数据,他实际上将直接写入磁盘文件。

但是磁盘文件实际上会在写入之前进入os缓存,这是操作系统管理的内存空间。一段时间后,操作系统本身将选择将其os缓存的数据刷新到磁盘。

然后,实际上,在随后的数据消耗中,它还将优先从os缓存(内存缓冲区)读取数据。

写入数据和读取数据的等效性基于os缓存。它完全取决于操作系统级别的内存区域,并且读写性能非常高。

此外,还有另一个好处:不要依靠自己的JVM来缓冲大量数据,从而避免了复杂而费时的JVM垃圾回收操作。

看下面的图片,它实际上是一个典型的Kafka运行过程。

然后,像Elasticsearch一样,他是最受欢迎的分布式搜索系统,并且使用类似的机制。

OS缓存会缓存大量数据,然后在进行搜索和查询时,可以首先从OS缓存(内存区域)读取数据,这可以确保非常高的读写性能。

4.经验

依赖于OS缓存的系统的JVM内存越大,效果越好?

现在我们可以进入主题。对于上述kafka,弹性搜索和其他系统,在线生产环境部署依赖于OS缓存来缓冲大量数据。

那么,当为它们分配JVM堆内存大小时,越大越好吗?

显然不是。如果您有一台具有32GB内存的机器,您会愚蠢地认为分配给JVM的内存越大,则不知道情况就越好,例如分配给JVM的16GB堆内存。

因此,以这种方式分配时,OS缓存的剩余内存可能少于10 GB,因为其他程序本身需要占用几GB的内存。

在这种情况下,将导致在写入磁盘时操作系统缓存可以容纳的数据量有限。

例如,总共有20GB的数据要写入磁盘,现在OS缓存中只能放置10GB的数据,然后其他10GB的数据只能放置在磁盘上。

此时,在读取数据时,必须至少从磁盘而非操作系统缓存中读取一半的读取请求,如下图所示:

此时,您的请求中有一半是从磁盘读取的,这将不可避免地导致性能下降。

很多人在遇到这样的问题时都会使用elasticsearch,总觉得es的读取速度很慢,上亿的数据被写入es,读取需要几秒钟的时间。

能花上几秒钟吗?如果部署es集群,jvm内存太大,只为os缓存留有几gb的内存,导致数亿数据大部分在磁盘上,而不是os缓存中。最后一次读取时,通常要花几秒钟时间读取大量磁盘。

5,正确的方法

为场景提供更多的操作系统缓存内存。

因此,在部署像kafka或elasticsearch这样的生产系统时,应该给jvm提供6gb或几gb的内存。

因为它们可能不需要消耗太多的内存空间,不依赖jvm的内存管理数据,当然要设置多少,需要精确的压力测量和优化。

但是对于这种类型的系统,您应该为操作系统缓存留有足够的内存空间

例如,一台具有32 GB内存的机器可以完全为OS缓存保留超过20 G的内存空间。然后假设该机器总共写入了20 GB的数据,并且它都可以驻留在OS缓存中。

然后,当查询数据时,不能读取OS缓存中的数据。这取决于记忆。您的性能必须为毫秒。不可能在几秒钟内完成查询。

整个过程,如下所示:

因此,建议在网上介绍生产系统的任何技术时,首先要了解该技术的原理甚至源代码,知道其具体的工作流程是什么,然后根据合理的设计来设计生产环境。这个程序保证了最佳的生产性能。