1. 背景
电商系统里,支付系统的位置:
2. 支付的核心业务流程

支付系统还包含应用管理、账户管理、渠道管理、支付交易、对账管理、清算管理、结算管理等各种功能模块。
3. 分析系统压力
用户发起一个支付请求,会生成一个支付订单,比如一个PayOrder。
每日要发生百万次交易,从JVM的角度来看,就是每天会在JVM中创建上百万个支付订单对象。

支付系统的压力有很多方面,包括高并发访问、高性能处理请求、大量的支付订单数据需要存储,等等技术难点。但是抛开这些系统架构层面的东西,单单是在JVM层面,我们的支付系统最大的压力,就是每天JVM内存里会频繁的创建和销毁100万个支付订单。
核心问题:
- 多少台机器?配置?
- JVM堆内存大小?
4. 支付系统每秒需要处理多少笔支付订单
计算峰值:高峰期几个小时,100万支付订单,平均到每秒多少订单?
假设每秒100笔订单左右,部署4台机器,则每台机器每秒处理25笔订单,
5. 每个支付订单处理要耗时多久?
每台机器一秒钟接收到30笔支付订单的请求,然后在JVM的新生代里创建了30个支付订单的对象,做了写入数据库等处理
接着1秒之后,这30个支付订单就处理完毕,然后对这些支付订单对象的引用就回收了,这些订单在JVM的新生代里就是没人引用的垃圾对象了。
6. 每个支付订单大概需要多大的内存空间?
估算一个订单对象的大小:一个Integer类型的变量数据是4个字节,Long类型的变量数据是8个字节,
一般来说,比如支付订单这种核心类,你就按20个实例变量来计算,然后一般大概一个对象也就在几百字节的样子。我们算他大一点好了,就算一个支付订单对象占据500字节的内存空间,不到1kb。
7. 每秒发起的支付请求对内存的占用
30 * 1KB = 30KB
8. 让支付系统运行起来分析一下
业务系统运行模型:
- 系统每秒来30个支付请求,JVM创建30个支付订单对象,30kb。
- 1秒之后,这30个对象就没人引用了,就成为新生代里的垃圾,等待被回收。
- 系统持续创建30个支付订单对象,不停地在新生代中放入30个对象,新生代中的垃圾对象持续累加
- 直到某一刻,新生代快满了,触发MinorGC,回收掉新生代中的垃圾对象,腾出空间,继续在新生代中分配对象。
9. 对完整的支付系统内存占用需要进行预估
系统中除了核心的支付订单对象之外,还会有大量的其他对象。
怎么估算?
支付订单对象大小 * 10~20倍
几百kb~1M
10. 支付系统的JVM堆内存应该怎么设置?
常见的机器配置是2核4G,或者是4核8G。
如果选4G内存,JVM进程最多2G,这2G还得分配给方法区、栈内存、堆内存几块区域,那么堆内存可能最多就是个1G多的内存空间。堆内存还分新生代、老年代,则新生代最多就几百M。 按之前估算每秒产生1M大小的对象,那么相当于几百秒之后就进行MinorGC,GC有点频繁,会影响线上系统的性能稳定性。
可以考虑采用4核8G的机器来部署支付系统。
JVM进程可以分配到4G内存,新生代可以分配到2G 新生代每秒多1MB左右的内存,需要将近半小时到1小时才会让新生代触发Minor GC,大大降低了GC的频率 可以这样设置:-Xms3G -Xmx3G -Xmn2G
业务量增大,可以水平扩展(加机器)
11. 合理设置方法区
几百M,够用
12. 合理设置栈
默认就行,Linux/64 默认1024kb
11. 不合理的设置内存
流量暴增 —> 系统性能急速下降,响应、处理变慢 —> 少数请求需要几十秒处理 —> 老年代内存占用变大 —> 频繁FGC
12. 总结
- 抽象核心业务流程,预估系统业务量、访问量
- 分析系统压力,推算峰值的每秒并发量
- 计算每秒请求对内存的占用,即每秒钟产生对象的大小
- 选择合理的机器配置,设置合理的堆内存
- 不合理的预估业务系统压力,不合理的设置内存大小,就可能会导致很大的问题
- 上线新系统的时候,应该对系统压力作预估,JVM内存、磁盘、带宽、数据库压力等给出合理的配置
