欢迎关注微信公众号:石杉的架构笔记(id:shishan100)编程
个人新课**《C2C 电商系统微服务架构120天实战训练营》在公众号儒猿技术窝**上线了,感兴趣的同窗,能够点击下方连接了解详情:微信
《C2C 电商系统微服务架构120天实战训练营》markdown
“ 这篇文章,给你们聊一个生产环境的实践经验:线上系统部署的时候,JVM堆内存大小是越大越好吗?架构
先说明白一个前提,本文主要讨论的是Kafka和Elasticsearch两种分布式系统的线上部署状况,不是普通的Java应用系统。并发
先说明一点,不论是咱们本身开发的Java应用系统,仍是一些中间件系统,在实现的时候都须要选择是否基于本身Java进程的内存来处理数据。app
你们应该都知道,Java、Scala等编程语言底层依赖的都是JVM,那么只要是使用JVM,就能够考虑在JVM进程的内存中来放置大量的数据。elasticsearch
仍是给你们举个例子,你们应该还记得以前聊过消息中间件系统。编程语言
好比说系统A能够给系统B发送一条消息,那么中间须要依赖一个消息中间件,系统A要先把消息发送到消息中间件,而后系统B从这个消息中间件消费到这条消息。分布式
你们看下面的示意图。微服务
你们应该都知道,一条消息发送到消息中间件以后,有一种处理方式,就是把这条数据先缓冲在本身的JVM内存里。
而后过一段时间以后,再从本身的内存刷新到磁盘上去,这样能够持久化保存这条消息,以下图。
若是用相似上述的方式,依赖Java系统自身内存处理数据,好比说设计一个内存缓冲区,来缓冲住高并发写入的大量消息,那么是有其缺陷的。
最大的缺陷,其实就是JVM的GC问题,这个GC就是垃圾回收,这里简单说一下他是怎么回事。
你们能够想一下,若是一个Java进程里总是塞入不少的数据,这些数据都是用来缓冲在内存里的,可是过一下子这些数据都会写入磁盘。
那么写入磁盘以后,这些数据还须要继续放在内存里吗?
明显是不须要的了,此时就会依托JVM垃圾回收机制,把内存里那些不须要的数据给回收掉,释放掉那些内存空间腾出来。
可是JVM垃圾回收的时候,有一种状况叫作stop the world,就是他会中止你的工做线程,就专门让他进行垃圾回收。
这个时候,他在垃圾回收的时候,有可能你的这个中间件系统就运行不了了。
好比你发送请求给他,他可能都无法响应给你,由于他的接收请求的工做线程都停了,如今人家后台的垃圾回收线程正在回收垃圾对象。
你们看下图。
虽说如今JVM的垃圾回收器一直在不断的演进和发展,从CMS到G1,尽量的在下降垃圾回收的时候的影响,减小工做线程的停顿。
可是你要是彻底依赖JVM内存来管理大量的数据,那在垃圾回收的时候,或多或少老是有影响的。
因此特别是对于一些大数据系统,中间件系统,这个JVM的GC(Garbage Collector,垃圾回收)问题,真是最头疼的一个问题。
因此相似Kafka、Elasticsearch等分布式中间件系统,虽然也是基于JVM运行的,可是他们都选择了依赖OS Cache来管理大量的数据。
也就是说,是操做系统管理的内存缓冲,而不是依赖JVM自身内存来管理大量的数据。
具体来讲,好比说Kafka吧,若是你写一条数据到Kafka,他实际上会直接写入磁盘文件。
可是磁盘文件在写入以前其实会进入os cache,也就是操做系统管理的内存空间,而后过一段时间,操做系统本身会选择把他的os cache的数据刷入磁盘。
而后后续在消费数据的时候,其实也会优先从os cache(内存缓冲)里来读取数据。
至关于写数据和读数据都是依托于os cache来进行的,彻底依托操做系统级别的内存区域来进行,读写性能都很高。
此外,还有另一个好处,就是不要依托自身JVM来缓冲大量的数据,这样能够避免复杂并且耗时的JVM垃圾回收操做。
你们看下面的图,其实就是一个典型的Kafka的运行流程。
而后好比Elasticsearch,他做为一个如今最流行的分布式搜索系统,也是采用类相似的机制。
大量的依赖os cache来缓冲大量的数据,而后在进行搜索和查询的时候,也能够优先从os cache(内存区域)中读取数据,这样就能够保证很是高的读写性能。
因此如今就能够进入咱们的主题了,那么好比就以上述说的kafka、elasticsearch等系统而言,在线上生产环境部署的时候,你知道他们是大量依赖于os cache来缓冲大量数据的。
那么,给他们分配JVM堆内存大小的时候是越大越好吗?
明显不是的,假如说你有一台机器,有32GB的内存,如今你若是在搞不清楚情况的状况下,要是傻傻的认为仍是给JVM分配越大内存越好,此时好比给了16G的堆内存空间给JVM,那么os cache剩下的内存,可能就不到10GB了,由于自己其余的程序还要占用几个GB的内存。
那若是是这样的话,就会致使你在写入磁盘的时候,os cache能容纳的数据量颇有限。
好比说一共有20G的数据要写入磁盘,如今就只有10GB的数据能够放在os cache里,而后另外10GB的数据就只能放在磁盘上。
此时在读取数据的时候,那么起码有一半的读取请求,必须从磁盘上去读了,无法从os cache里读,谁让你os cache里就只能放的下10G的一半大小的数据啊,另一半都在磁盘里,这也是没办法的,以下图。
那此时你有一半的请求都是从磁盘上在读取数据,必然会致使性能不好。
因此不少人在用Elasticsearch的时候就是这样的一个问题,总是以为ES读取速度慢,几个亿的数据写入ES,读取的时候要好几秒。
那能不花费好几秒吗?你要是ES集群部署的时候,给JVM内存过大,给os cache留了几个GB的内存,致使几亿条数据大部分都在磁盘上,不在os cache里,最后读取的时候大量读磁盘,耗费个几秒钟是很正常的。
因此说,针对相似Kafka、Elasticsearch这种生产系统部署的时候,应该要给JVM好比6GB或者几个GB的内存就能够了。
由于他们可能不须要耗费过大的内存空间,不依赖JVM内存管理数据,固然具体是设置多少,须要你精准的压测和优化。
可是对于这类系统,应该给os cache留出来足够的内存空间,好比32GB内存的机器,彻底能够给os cache留出来20多G的内存空间,那么此时假设你这台机器总共就写入了20GB的数据,就能够所有驻留在os cache里了。
而后后续在查询数据的时候,不就能够所有从os cache里读取数据了,彻底依托内存来走,那你的性能必然是毫秒级的,不可能出现几秒钟才完成一个查询的状况。
整个过程,以下图所示:
因此说,建议你们在线上生产系统引入任何技术的时候,都应该先对这个技术的原理,甚至源码进行深刻的理解,知道他具体的工做流程是什么,而后针对性的合理设计生产环境的部署方案,保证最佳的生产性能。
END