09_每日百万交易的支付系统反面案例
944字约3分钟
2024-08-10
不合理的 JVM 内存设置
假设没有经过合理的内存预估,直接选择了一台 2核4G
的机器来部署支付系统,而且就只用了一台机器
然后 JVM
给的堆内存大小只有 1G
,扣除老年代之后,新生代只剩几百 MB
的内存空间
按照上一节估算的压力,每秒有 100
个支付订单对象被创建,总共 50kb
左右,再按照全局预估的思路,内存占用扩大 10
到 20
倍
假设我们扩大 20
倍,一秒内总共会创建出来 1MB
左右的对象无法被回收
大促销时瞬时流量激增
按照估算出来的内存压力,每秒新增 1MB
对象,几百秒后新生代满了触发 Young GC
,回收掉垃圾对象
其实这还不算什么大问题,顶多就是发现系统每隔几分钟略微卡顿一下,因为垃圾回收会影响系统性能
假设现在搞大促销活动,很可能导致系统的压力增加 10
倍,此时可能系统每秒钟上千笔订单
这个时候系统压力就会很大,不光是内存,还有线程资源、CPU
资源几乎都会打满,内存更是岌岌可危
少数请求处理慢,导致老年代内存占用变大
假设现在每秒 1000
笔交易请求,那么每秒钟系统对内存的占用增加到 10MB
以上
最可怕的是,每秒过来的 1000
笔交易订单,不再是 1
秒钟就可以处理完毕的,因为压力骤增,导致系统性能下降,可能出现每个请求处理完毕需要几秒钟,甚至几十秒
假设你的新生代里已经积压了很多数据,都快满了
这个时候再去新生代里分配对象,就会触发一次 Young GC
去回收新生代
但是可能在回收掉大量对象之后,还存在几十 MB
的对象还在,因为请求处理慢,很快新生代再次被填满,再次触发 Young GC
,然后少数几十 MB
对象还在,经过多次之后,就会被转移到老年代去
老年代对象越来越多导致频繁垃圾回收
上述流程如果反复多次,有少数请求特别慢,创建的对象在新生代反复多次都没法被回收,就会被转移到老年代去
后续处理完之后,老年代里的对象就没人引用了,成了垃圾对象
重复多次这个过程,老年代里的垃圾对象也就会越来越多
一旦老年代的垃圾对象越来越多,迟早会满,然后就会触发老年代的垃圾回收,而且这个老年代被占满的频率还很高,可能就会频繁的触发老年代的垃圾回收
老年代的垃圾回收速度是很慢的,然后频繁的垃圾回收,对系统的性能影响很大
如何合理设置永久代、栈内存大小
一般刚开始上线一个系统,永久代大小的设置没太多可以参考的规范,一般设置几百 MB
都是够用的,因为里面主要就存放一些类的信息
栈内存大小设置一般也不会特别的去预估和设置,一般默认的 512KB
到 1MB
就差不多够了,每个线程的栈内存空间是用来存放线程执行方法期间的各种局部变量