阿里技术面:每天100w次登陆请求, 8G 内存该如何设置JVM参数?
阅读本文大概需要 20 分钟。
来自:网络,侵删
既供大家实操参考
又供大家面试参考
每天100w次登陆请求, 8G 内存该如何设置JVM参数?
Step1:新系统上线如何规划容量?
计算业务系统每秒钟创建的对象会佔用多大的内存空间,然后计算集群下的每个系统每秒的内存佔用空间(对象创建速度)
设置一个机器配置,估算新生代的空间,比较不同新生代大小之下,多久触发一次MinorGC。
为了避免频繁GC,就可以重新估算需要多少机器配置,部署多少台机器,给JVM多大内存空间,新生代多大空间。
根据这套配置,基本可以推算出整个系统的运行模型,每秒创建多少对象,1s以后成为垃圾,系统运行多久新生代会触发一次GC,频率多高。
假设每天100w次登陆请求,登陆峰值在早上,预估峰值时期每秒100次登陆请求。
假设部署3台服务器,每台机器每秒处理30次登陆请求,假设一个登陆请求需要处理1秒钟,JVM新生代里每秒就要生成30个登陆对象,1s之后请求完毕这些对象成为了垃圾。
一个登陆请求对象假设20个字段,一个对象估算500字节,30个登陆佔用大约15kb,考虑到RPC和DB操作,网络通信、写库、写缓存一顿操作下来,可以扩大到20-50倍,大约1s产生几百k-1M数据。
假设2C4G机器部署,分配2G堆内存,新生代则只有几百M,按照1s1M的垃圾产生速度,几百秒就会触发一次MinorGC了。
假设4C8G机器部署,分配4G堆内存,新生代分配2G,如此需要几个小时才会触发一次MinorGC。
Step2:该如何进行垃圾回收器的选择?
吞吐量还是响应时间
垃圾回收器设计上的考量
JVM在GC时不允许一边垃圾回收,一边还创建新对象(就像不能一边打扫卫生,还在一边扔垃圾)。
JVM需要一段Stop the world的暂停时间,而STW会造成系统短暂停顿不能处理任何请求;
新生代收集频率高,性能优先,常用复制算法;老年代频次低,空间敏感,避免复制方式。
所有垃圾回收器的涉及目标都是要让GC频率更少,时间更短,减少GC对系统影响!
CMS和G1
延迟敏感的推荐CMS;
大内存服务,要求高吞吐的,采用G1回收器!
CMS垃圾回收器的工作机制
优点:并发收集、主打“低延时” 。在最耗时的两个阶段都没有发生STW,而需要STW的阶段都以很快速度完成。
缺点:1、消耗CPU;2、浮动垃圾;3、内存碎片
适用场景:重视服务器响应速度,要求系统停顿时间最短。
业务系统,延迟敏感的推荐CMS;
大内存服务,要求高吞吐的,采用G1回收器!
Step3:如何对各个分区的比例、大小进行规划
-Xms3072M
-Xmx3072M
-Xss1M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:SurvivorRatio=8
-Xms3072M
-Xmx3072M
-Xmn2048M
-Xss1M
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:SurvivorRatio=8
‐Xmn2048M ‐XX:SurvivorRatio=8
年轻代大小2g,eden与survivor的比例为8:1:1,也就是 1.6g:0.2g:0.2g
什么是JVM动态年龄判断规则呢?
应该如何去评估新生代内存和分配合适?
针对于无状态或者轻状态服务(现在最常见的业务系统如Web应用)来说,一般新生代甚至可以给到堆内存的3/4大小;
而对于有状态服务(常见如IM服务、网关接入层等系统)新生代可以按照默认比例1/3来设置。
step4:栈内存大小多少比较合适?
step5:对象年龄应该为多少才移动到老年代比较合适?
5*30s= 150s
),和几秒的时间相比,对象已经存活了足够长时间了。‐Xms3072M
‐Xmx3072M
‐Xmn2048M
‐Xss1M
‐XX:MetaspaceSize=256M
‐XX:MaxMetaspaceSize=256M
‐XX:SurvivorRatio=8
‐XX:MaxTenuringThreshold=5
step6:多大的对象,可以直接到老年代比较合适?
-XX:PretenureSizeThreshold
),一般可以结合自己系统看下有没有什么大对象 生成,预估下大对象的大小,一般来说设置为1M就差不多了,很少有超过1M的大对象,‐Xms3072M
‐Xmx3072M
‐Xmn2048M
‐Xss1M
‐XX:MetaspaceSize=256M
‐XX:MaxMetaspaceSize=256M
‐XX:SurvivorRatio=8
‐XX:MaxTenuringThreshold=5
‐XX:PretenureSizeThreshold=1M
step7:垃圾回收器CMS老年代的参数优化
-XX:+UseParallelGC
(年轻代)和-XX:+UseParallelOldGC
(老年代),ParNew+CMS(-XX:+UseParNewGC -XX:+UseConcMarkSweepGC)
XX:CMSInitiatingOccupancyFraction=70
XX:+UseCMSInitiatinpOccupancyOnly
-XX:+AlwaysPreTouch
‐Xms3072M
‐Xmx3072M
‐Xmn2048M
‐Xss1M
‐XX:MetaspaceSize=256M
‐XX:MaxMetaspaceSize=256M
‐XX:SurvivorRatio=8
‐XX:MaxTenuringThreshold=5
‐XX:PretenureSizeThreshold=1M
‐XX:+UseParNewGC
‐XX:+UseConcMarkSweepGC
‐XX:CMSInitiatingOccupancyFraction=70
‐XX:+UseCMSInitiatingOccupancyOnly
‐XX:+AlwaysPreTouch
‐Xms3072M ‐Xmx3072M
最小最大堆设置为3g,最大最小设置为一致防止内存抖动‐Xss1M
线程栈1m‐Xmn2048M ‐XX:SurvivorRatio=8
年轻代大小2g,eden与survivor的比例为8:1:1,也就是1.6g:0.2g:0.2g-XX:MaxTenuringThreshold=5
年龄为5进入老年代 5.‐XX:PretenureSizeThreshold=1M
大于1m的大对象直接在老年代生成‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC
使用ParNew+cms垃圾回收器组合‐XX:CMSInitiatingOccupancyFraction=70
老年代中对象达到这个比例后触发fullgc‐XX:+UseCMSInitiatinpOccupancyOnly
老年代中对象达到这个比例后触发fullgc,每次‐XX:+AlwaysPreTouch
强制操作系统把内存真正分配给IVM,而不是用时才分配。step8:配置OOM时候的内存dump文件和GC日志
-XX:+HeapDumpOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=${LOGDIR}/
-Xloggc:/dev/xxx/gc.log
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
一份通用的JVM参数模板
一般来说,大企业或者架构师团队,都会为项目的业务系统定制一份较为通用的JVM参数模板,但是许多小企业和团队可能就疏于这一块的设计,如果老板某一天突然让你负责定制一个新系统的JVM参数,你上网去搜大量的JVM调优文章或博客,结果发现都是零零散散的、不成体系的JVM参数讲解,根本下不了手,这个时候你就需要一份较为通用的JVM参数模板了,不能保证性能最佳,但是至少能让JVM这一层是稳定可控的, 在这里给大家总结了一份模板:
-Xms4g
-Xmx4g
-Xmn2g
-Xss1m
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=10
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+AlwaysPreTouch
-XX:+HeapDumpOnOutOfMemoryError
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
如果是GC的吞吐优先,推荐使用G1,基于8C16G系统的G1回收器模板:
XX:MaxGCPauseMillis=N
参数,这也符合G1的目的——让GC调优尽量简单!-Xms8g
-Xmx8g
-Xss1m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=150
-XX:InitiatingHeapOccupancyPercent=40
-XX:+HeapDumpOnOutOfMemoryError
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
-XX:MaxGCPauseMillis
来说,参数的设置带有明显的倾向性:调低↓:延迟更低,但MinorGC频繁,MixGC回收老年代区减少,增大Full GC的风险。调高↑:单次回收更多的对象,但系统整体响应时间也会被拉长。InitiatingHeapOccupancyPercent
来说,调参大小的效果也不一样:调低↓:更早触发MixGC,浪费cpu。调高↑:堆积过多代回收region,增大FullGC的风险。调优总结
上线之前,应先考虑将机器的JVM参数设置到最优;
减少创建对象的数量(代码层面);
减少使用全局变量和大对象(代码层面);
优先架构调优和代码调优,JVM优化是不得已的手段(代码、架构层面);
分析GC情况优化代码比优化JVM参数更好(代码层面);
什么是ZGC?
如何选择垃圾收集器?
-XX:+UseSerialGC
。-XX:+UseSerialGC
。-XX:+UseParallelGC
。-XX:+UseConcMarkSweepGC
、 -XX:+UseG1GC
、 -XX:+UseZGC
等。从上面这些出发点来看,我们平常的 Web 服务器,都是对响应性要求非常高的。Hotspot为什么使用元空间替换了永久代?
-XX:PremSize
:设置永久代的初始大小-XX:MaxPermSize
: 设置永久代的最大值,默认是64M
java.lang.OutOfMemoryError:PermGen space
错误,因为永久代空间配置有限嘛。最典型的场景是,在web开发比较多jsp页面的时候。-XX:MetaspaceSize
,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。-XX:MaxMetaspaceSize
,最大空间,默认是没有限制的。-XX:MinMetaspaceFreeRatio
,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集-XX:MaxMetaspaceFreeRatio
,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
什么是Stop The World ? 什么是OopMap?什么是安全点?
循环的末尾(非 counted 循环) 方法临返回前 / 调用方法的call指令后 可能抛异常的位置
推荐阅读:
互联网初中高级大厂面试题(9个G) 内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈!
⬇戳阅读原文领取! 朕已阅