java 服务 容量评估,JVM容量评估及调优

工具

Jmeter

java 服务 容量评估,JVM容量评估及调优_第1张图片

基础使用和数据分析可以看这里->Jmeter接口测试+压力测试

JProfiler

java 服务 容量评估,JVM容量评估及调优_第2张图片

这是一个非常直观的可以看到线程内存占用和gc活动概览的工具,也可以分析堆栈日志和线程,但是线程分析的不够细致只能看个大概,看不到线程栈。

PerfMa

这是一个可以分析heap、thread和jvm启动参数的社区网站,这个thread分析还是很仔细有参考性的。

java 服务 容量评估,JVM容量评估及调优_第3张图片

4. GCeasy

java 服务 容量评估,JVM容量评估及调优_第4张图片

- 用来分析GC活动日志的网站,可以很直观的看到GC回收情况的各种图表。

容量评估

容量评估其实估算的事负载能力和存储能力,负载能力=1000ms/响应时间,也就是一秒能处理的请求数量。随着存储量的增多,负载能力会慢慢变差。

首先,需要从业务角度来定义业务的流量情况,当前情况的收集,看平时或者高峰的时候的请求流量,读流量写流量等,同时也需要对未来情况的预估。

从线上的前端监控Ajax访问后端的URL访问次数可以看到,每天访问次数6007次,因为是面向B端的系统,所以访问次数比较少,前端的大佬说有写不是ajax访问的,所以没有统计进来,那就先按照这个算吧。可以看到流量还是相对这个请求量来说还是比较大的,因为B端用户都是会看很多数据的。

8ac23c985f554b226bc5a5aab22a2570.png

因为这个平台的概览页面是没有平均请求时间的,所以我直接连上了后台的mongo库,聚合过滤了一下。

7f1aeb9bd6d04c15ba28eb4eeff547f1.png

1为正常请求时间的平局时间为199ms,2为慢请求的时间7.4s(。。。。no comment)。我们算一下tomcat处理请求的负载量,Tomcat负载=(1000ms/平均响应时间)X CPU核数(线上单台RDS核数为8) = 40/s,其实主要的时间都花在了数据库的查询。

看完这个负载能力,再看一下实际的单台服务器请求情况。

java 服务 容量评估,JVM容量评估及调优_第5张图片

java 服务 容量评估,JVM容量评估及调优_第6张图片

看到这个网络的请求情况,B端特性就很明显了,早上八点多到十点达到峰值,下午两点多开始到四点达到峰值,虽说是峰值其实连接数才300+。以此为例,现在的情况是三台RDS就撑起来了,所以并发也就1000+。

同时再看一下CPU和内存的使用情况。CPU其实也比较符合峰值的模型,但是内存使用率一直很低,应该是限定最大堆的大小。

java 服务 容量评估,JVM容量评估及调优_第7张图片

所以以上面的模型估算,1000的并发,tomcat的负载能力是40,那么需要1000/40=25台tomcat才行,实际上线上只有3台,这就很诡异了,虽然B端的用户一般来说并发度是很低的,但是这个估算数据也差的太多了,这个事情后面再说。其实反而和其他系统的数据同步反而会占用更多的CPU和内存。这里的算法存疑,影响因素过多。

压测调优

从上面的内存使用率来看,一直处于一个较低水平,并且没有设置JVM参数,下面看一下能不能压缩一下JVM的内存使用空间。测试机的配置是2核8G的配置,首先预留2G给操作系统,然后分配3G给我们的JVM。

首先,需要定义混合梯度交易测试的模型,其实就是定义出来同一时刻进行交易业务的类型和占比,比如查询录入数据的占比为70%,添加数据的占比为20%,导出数据的占比为10%,这样三个占比就构成了混合交易的模型。其实这三个交易类型,可以根据生产环境的请求占比来得出。

这里以录入数据查询的类型为例,来分析。首先需要得出查询类型的单模型压测数据。

单模型压测

交易名称平均响应时间(s)并发线程数数据量级(条)样本查询0.19851000

混合模型压测

因为录入查询的的占比为70%,所以假设目标TPS为72,那么查询的TPS=72*70%=50,所以查询的第一梯度的TPS就是50。

每个交易的并发线程数计算方式 并发线程数=目标TPS * 平均响应时间=50 * 0.198 = 10(上取整)

所以从这公示的可以得出,下一个梯度的并发线程数,是由目标TPS和本梯度的平均RT来决定的。

单交易目标TPS交易类型占比%平均响应时间(s)目标吞吐量(分钟)并发线程数50样本查询700.198300010

100样本查询700.263600027

200样本查询701.57512000112

其他的类型的业务以此类推,也可以计算出来这个表格。

最佳并发数

但是其实在第二梯度的时候,根据JMeter返回的Troughout数据来看,已经不满足目标的TPS了,因为JMeter的TPS和RT计算方式是:

TPS=(sample样本数)/(最后一个线程启动的时间+最后一个线程持续的时间-第一个线程启动的时间)

RT=所有sample样本响应时间和/样本个数

得到的数据结果已经满足不了梯度目标了,所以这个时候已经出现了TPS小于并发数了,说明并发数已经不能再往上加了,此时的并发数就是最佳并发数。

最大吞吐量

后面我们继续增大并发量,直到出现TPS不再增加并且开始下降的情况,得出来TPS的数据为61/s,这也就是最大的TPS。

最大并发数

我们继续加压,开到1000的时候,会发现开始出现报错了,错误率上升,这是查看压力机(jmeter所在机器)的资源消耗,CPU及内存均低于90,故已达到服务器的最大并发数。

JVM调优

以上的情况都是在默认JVM分配资源的情况下进行的,先用命令看一下他默认的资源分配到底是多少。

java -XX:+PrintFlagsFinal -version | grep HeapSize

864b6a1778bd188bc7cdd4c4bf741eeb.png

可以看到初始堆内存是250M,最大堆内存是大约是4g。再看下具体的应用进程的使用情况(这个其实已经是我更改后的)。

jmap -heap pid

java 服务 容量评估,JVM容量评估及调优_第8张图片

下面看一张图,说明了JVM参数以及基础调优的办法。

java 服务 容量评估,JVM容量评估及调优_第9张图片

所以首先将初始堆内存和最大堆内存设置为3g,避免重新不停的获取内存,这时候使用50并发进行压测,通过JProfiler进行观察,发现其实在频繁的GC。通过GCeasy分析之后,可以看到其实新生代的占用以及回收效率都是比较高的。

java 服务 容量评估,JVM容量评估及调优_第10张图片

java 服务 容量评估,JVM容量评估及调优_第11张图片

其实对于应答式的web应用,大部分对象都是新生代对象,通过minorGC都可以回收掉,所以适当的调大新生代的内存,通过-Xmn1500M将内存调为1.5g,再次压测可以看到回收频率低了很多,降低了平均RT,同时,因为内存回收也会影响响应时间,可以通过设置--XX:+UseParNewGC和--X:+UseConcMarkSweepGC,来使用并发的垃圾回收器来降低时延。

同时这里有一个问题,我们可以看到上面的JProfier的曲线图中,出现了BlockedTreads,这个时候可以通过jstack -l pid > jstack.txt导出线程栈文件,之后上传PerfMa分析线程,发现Block的线程其实是tocmat Nio工作线程池的线程。

java 服务 容量评估,JVM容量评估及调优_第12张图片

这里可以看到线程的阻塞原因是JUC锁的竞争,猜测是因为并发数上来之后,woker线程组的线程去Queue中poll任务的时候造成了JUC所得竞争,但是奇怪的现象是,将JVM设置内存在4g的时候,同样的并发数下,极少出现或者阻塞线程很少的状况。这里需要再查一下。

总结

首先需要定义出混合模型的场景以及目标的TPS,再根据具体的机器或者集群的基础设施配置进行压测,看能否达到目标TPS,就能判断出来所需应用容量以及基础资源容量。

你可能感兴趣的:(java,服务,容量评估)