每天百万交易的支付系统,生产环境该怎么设置JVM堆内存大小

时间:2022-07-22
本文章向大家介绍每天百万交易的支付系统,生产环境该怎么设置JVM堆内存大小,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前几天我们分享了我们java中的基石JVM的相关内存模型(要想精通java,你必须得知道java的内存模型,不忽悠)以及类加载机制(java类加载机制,再也不怕面试官的刁难),其实在我们平时开发中,大部分工程师在生产环境部署java的时候很少去思考这个JVM的相关参数到底怎么去设置,更很少去预估我们程序所需的内存以及并发量等等,或者是直接参考公司资深工程师写的配置。

这样的工程师虽然不能说你不够专业,但是我觉得你应该具备这样的思考能力,只有这样你才能才遇到自己程序各种线上异常的时候不用去请教公司大拿,你就应该自己成为这方面的大拿。好,那我们今天就结合实际案例来每日百万交易的支付系统,生产环境该怎么去设置JVM堆内存大小。

01

背景

支付在我们如今的生活中已无处不在,它时刻围绕着我们的吃喝住行,比如我们在电商里面购买一个商品的时候,就会涉及到支付系统,大体的流程是这个样子的:

从上图中,我们能看出支付系统是我们整个交易过程中核心且是不可或缺的系统之一,只有商家收到钱,才能卖给你东西。下面我们就来看看如何根据这个支付系统未来预估的业务量,访问量,去推算这个系统每秒钟的并发量,然后推算每秒钟的请求对内存空间的占用,进而推算出整个系统运行期间的JVM内存运转模型,只有这样我们才能很好的去合理的去设置JVM堆内存。

02

每日百万的支付系统压力体现在何处?

在这里我建议,在做任何系统的时候,我们都要去思考我们现在开发的这个系统将要面临什么压力,而这个压力又会体现在我们系统的哪个地方。那对于我们现在的支付系统对于我们的JVM来说,他的核心压力就在于,不停的创建支付单,支付单包括上游系统信息、创建时间、商品信息、用户信息、支付渠道等等。也就是说,我们的JVM中每天会有上百万的支付订单对象在频繁的创建和销毁。

弄清楚了我们系统的压力之后,我们接下来就要去思考另外一些直接影响我们业务的几个核心问题:

  • 我们的支付系统需要部署多少台机器。
  • 每台机器需要多大的内存。
  • 每台机器上启动的jvm需要给多大的内存,才能支撑我们百万的订单创建而不会内存溢出。

03

支付系统每秒钟需要处理多少笔支付订单

要想合理设置我们JVM堆内存大小,我们就得去计算出我们系统每秒会处理多少笔支付单。

我们都知道,在任何一个系统都会有高峰期和平稳期的,我们就可以拿高峰期来计算就行了。现在我们系统每天有100万的支付订单,高峰期一般在中午或者晚上,高峰期大概3个小时左右,也就是每秒大概有100个订单产生。

这样的话,我们就可以假设将支付系统先部署个3台机器,每台机器最普通的配置4CPU 8G的。也就是每台机器每秒处理大概30多个订单。

04

每个支付订单耗时多久

接下来,我们需要搞清楚另一个重要的问题,即每个支付订单大概要多长时间才处理的完?

从用户发送的一次支付请求,到JVM里创建支付单对象相关操作,再到持久化到数据库,或者调用第三方支付这一流程。现在我们就假设这些流程完成需要1秒的时间。

现在我们支付系统的模型是这个样子了:

  1. 每台机器每秒钟会收到30个支付订单的请求,接着就会在JVM的新生代内存区域创建30个支付订单对象,最后做相关写入数据库的相关操作;
  2. 然后1秒之后,这30个订单就处理完了,这些订单在JVM中就会成为没被引用的垃圾对象;
  3. 接着下一秒又来了30个支付单请求,重复之前的动作。

05

每个支付订单大概需要多大的内存空间

下面我们就要来算一算我们一个支付订单大概需要多少内存空间,这里教大家怎么去算一下,就是主要根据你的实体类的变量类型去算就行了,即Integer类型的变量占4个字节,Long类型的占8个字节,其他的网上查查哈,这样就可以推算出我们的当前实体类所需的内存大小了。

public class payOrder {
 private Integer orderId;
 private Integer userId;
 private Long createTime;
}

像我们这样的支付订单实体类大概也就20几个字段在几百个字节的样子,我们就算大一点就假设它500字节好了,不到1Kb

06

每秒发起的支付请求会占用多少内存

上面我们推算出来了每秒钟多少请求,同时推算了单个支付单的内存大小,现在我们看看每秒发起的请求一共要占用多少内存。

从图中也可以看出,每台机器每秒共30个支付单,也就是大概占用30 * 500字节 = 15000字节,大概也就在15Kb的样子,很小吧。

07

让支付系统跑起来

通过上面的分析,我们已经很清晰的知道了我们当前系统的各个核心问题,也弄清楚了每秒多少请求,每秒占用多少内存空间。现在我们先将我们的支付系统在我们脑海里运行一遍:

  1. 每秒30个请求,创建30个支付单对象,大概也就在kb级别的内存占用。
  2. 1秒之后,这30个对象就不会被引用,会成为JVM的新生代的垃圾
  3. 下一秒的时候,又有30个请求过来,新生代又会继续产生这些垃圾对象
  4. 如此往复着,知道有一刻,新生代里有几十万个对象了,大概占用几百兆的内存了,都快满了。
  5. 这个时候就会触发Minor GC,回收掉新生代的那些垃圾对象,以腾出更多空闲空间来让新的对象进来

好,这就是目前我们支付系统的运行模型,我们要在脑海里先自己跑一遍,才能更好的去配置生产环境。

08

对整个支付系统进行内存预估

我们上面估算的那些内存其实只是估算最核心的部分,真实的系统中,可能会随带好多对象的创建,所以依据我们的经验来看,将核心部分扩大10到20倍就差不多了。也就是,我们现在的支付系统大概在几百KB~1M之间。

然后每秒大概就有1M左右的垃圾对象存在新生代中,一直循环多次后,就会触发Minor GC回收掉这些垃圾,到目前为止我们就把完整的支付系统给运行起来了,最后,我们就要对其进行JVM内存设置了。

09

JVM堆内存该如何设置

这里建议,生产环境服务器至少最普通是4CPU 8G 来部署我们的支付系统,那么我们的JVM进程至少可以给4G以上内存,新生代在里面至少可以分配到2G内存空间,这样子就可以做到可能新生代每秒钟1MB左右的内存,但是需要将近半小时到1小时才会让新生代触发Minor GC。基本还可以的接受的,只有GC相关专题,我会在后面写的,敬请期待哈。

所以,在我这个支付系统里面,-Xms和-Xmx设置为3G,给整个堆内存3G内存空间,-Xmn设置为2G,给新生代2G内存空间。

当然,如果我们业务还需增长,我就部署5台机器或者10台机器,每台机器还可以申请更高的内存空间16G乃至32G都可以。

总结,今天我带着大家来分析了一个系统开发完,我们该怎么去再生产环境配置我们的JVM堆内存大小,主要需要考虑我们应该部署多少台机器?每台机器要多少内存?每台机器每秒钟能有多少的请求过来并且生成对象?然后基于这些参数判断多久触发一次Minor GC,这样一套流程下来,我们就能很好的掌握并且自己可根据复杂的业务变化来设置自己系统的JVM堆内存。