java虚拟机12

压测工具AB

Ab(Apache Bench)

  • 安装
    • yum -y install httpd-tools
  • 测试 get 请求接口
    • ab -c 10 -n 100 http://www.test.api.com/test/login?userName=test&password=test
    • -c后面的10是10个并发,-n后面的100是100个总请求
  • 测试 post请求接口
    • ab -c 10 -n 100 -p ‘post.txt’ -T ‘application/x-www-form-urlencoded’ ‘http://www.test.api.com/test/register’
    • post.txt是post方法的请求体
  • 工具的输出,其中的一些核心参数
    • cocurent level,并发量
    • requests per second,每秒的吞吐量
    • time per requests,其中这个参数有两个,较大的那一个是用户的平均请求时间,较小的那一个是服务器平均处理时间
    • connection time,平均的连接时间
    • percentage of the requests served within a certain time(ms),多少百分比的请求在多少毫秒以内
  • 参数的含义
  • 性能指标

Linux服务器

  • 虚拟机配置的
    • 2核2G内存

内存调优案例

案例介绍

  • 模拟抢购接口

    • package cn.enjoyedu.controller;
      
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * 类说明:
       */
      @RestController
      @RequestMapping("/jvm")
      public class TestController {
          @RequestMapping("/heap")
          public String test(){
              List<Byte[]> list = new ArrayList<Byte[]>();
              Byte[] b = new Byte[1024*1024];
              list.add(b);
              return "success";
          }
      }
      
      
    • 模拟抢购、秒杀情况,此时会创建订单,然后会新建很多对象(5W的并发,创建的对象大概是20kb),这里模拟这种情况,就会创建一个1M大小的list,并发模拟是1000

  • 案例代码

服务器配置信息

  • 2核2G

GC监控

  • 因为需要压测,关心垃圾回收器的性能

    • jstat可以统计gc的情况

    • jstat -gc 进程号 5000 20

      每隔5000ms刷新20次

    • jstat -gc 进程号 5000 20 | awk ‘{print $13,$14,$15,$16,$17}’

      只显示13列,14列,15列,16列,17列,最后只显示younggc次数、younggc的时间、fullgc次数、fullgc的时间、总共gc花费的时间

堆空间监控

  • springboot项目启动后,内存空间默认是多少?
    • java -XX:+PrintFlagsFinal -version | grep HeapSize
    • 发现堆的初始大小是32M,堆的最大大小是480M
  • jmap -heap 进程号
      • eden区,128M
      • from区,3M
      • to区,4.5M
      • old区,18.5M
    • 为什么from区和to区不相等
      • 因为linux中默认垃圾回收器是Parallel Scavenge和Parallel old,这种回收器会自动调整eden:from:to区的比例,不一定就是8:1:1,但是这种处理gc的时候会stop the world,降低服务的吞吐量

测试案例场景

  • 10个并发用户/10万请求量

    • ab -c 10 -n 100000 http://127.0.0.1:8080/jvm/heap
  • 100个并发用户/10万请求量

    • ab -c 100 -n 100000 http://127.0.0.1:8080/jvm/heap
  • 1000个并发用户/10万请求量

    • ab -c 1000 -n 100000 http://127.0.0.1:8080/jvm/heap

内存调优压测及优化过程

  • 测试时第一次算热身,第二次的测试结果才会填入

优化方案一

  • java -jar -Xms1500m -Xmx1500m jvm-1.0-SNAPSHOT.jar

  • 堆加大,-Xms1500m,-Xmx1500m

    • 因为服务器本身只有2g,这差不多是极限值了
  • 重启项目

测试结果
  • 相比默认堆内存,不管是哪个数量级下,性能都降低了

优化方案二

  • java -jar -Xms1500m -Xmx1500m -Xmn1000m -XX:SurvivorRatio=8 jvm-1.0-SNAPSHOT.jar

  • 堆加大,新生代加大到1g,eden区和from区、to区的比例恒定为8:1:1,-Xms1500m,-Xmx1500m,-Xmn1000m,-XX:SurvivorRatio=8

测试结果
  • 在低并发情况下性能略低一点,在高并发情况下性能有提升

  • 参数配置性能指标10个并发/10万总请求100个并发/10万总请求1000个并发/10万总请求
    默认值吞吐量1050次每秒872次每秒781次每秒
    服务器平均处理时间0.952ms1.146ms1.279ms
    GC耗时2703次younggc,29秒,30次fullgc,1.6秒,总共30.6秒2722次younggc,51.5秒,57次fullgc,3.8秒,总共55.3秒2995次younggc,60秒,11次fullgc,1秒,总共61秒
    优化方案一吞吐量753次每秒620次每秒707次每秒(超频)
    服务器平均处理时间1.326ms1.61ms1.413ms(超频)
    GC耗时821次younggc,55秒,2次fullgc,3.8秒,总共58.8秒841次younggc,79秒,9次fullgc,8秒,总共87秒总共74秒(超频)
    优化方案二吞吐量1025次每秒923次每秒1024次每秒
    服务器平均处理时间0.975ms1.08ms0.976ms
    GC耗时412次younggc,16秒,2次fullgc,1.2秒,总共17.2秒总共37秒总共31秒

结果分析

GC 频率
  • 高频的 FullGC 会给系统带来非常大的性能消耗,虽然 MinorGC 相对 FullGC 来说好了许多,但过多的 MinorGC 仍会给系统带来压力。
内存
  • 这里的内存指的是堆内存大小,堆内存又分为年轻代内存和老年代内存。堆内存不足,会增加 MinorGC ,影响系统性能。
吞吐量
  • 频繁的 GC 将会引起线程的上下文切换,增加系统的性能开销,从而影响每次处理的线程请求,最终导致系统的吞吐量下降。
延时
  • JVM 的 GC 持续时间也会影响到每次请求的响应时间。

推荐策略

  • 在高并发情况下,所有对象都是朝生夕死的,把堆的新生代调大,老年代够用就行,eden:from:to可以调成8:1:1
  • 为什么单纯调大堆内存,效率反而降低了?
    • younggc回收有两步,首先扫描垃圾对象,然后是复制,空间大了,扫描时间也变多了,同时堆空间增大了,eden区的空间没有明显增大,由300M变成了500M
    • 而方案二中很大的新生代、小的老年代,因为测试方法对象的生命周期短,所以这种方案是适合的

如何优化GC

GC 性能衡量指标

  • 吞吐量
  • 停顿时间
  • 垃圾回收频率

GC 调优策略

  • 降低 Minor GC 频率
  • 降低 Full GC 的频率
  • 选择合适的GC回收器

分析 GC 日志

  • java -jar -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gclogs jvm-1.0-SNAPSHOT.jar

    • 通过这种方式创建gc日志文件
  • Gceasy这个工具收费,也可以用开源工具GCViewer

1000并发的默认方案和优化方案二对比(提前的测试结果)
  • 1.默认方案的堆内存是459M,优化方案二是1471M

  • 2.首先没有发生内存泄漏,因为在fullgc之后的堆内存使用空间在20%以下,说明空间都回收回去了,如果发生内存泄漏了,fullgc之后堆空间占用率应该还是很高的

  • 3.暂停时间对比

    • 默认方案暂停时间是58秒,方案二的暂停时间是15秒

实例说明

  • 加大新生代,会降低minorgc的频次,其中包括两部分时间,一是扫描时间t1,二是复制存活对象时间t2,两者加起来的时间就是minorgc花费的时间

  • 假设每300ms触发一次minorgc,并且一个对象在eden区能存活500ms

    • 在方案一中,由于eden区没有明显增大,minorgc还是会频繁触发,而且堆的空间又变大了,所以复制时间又会变长

    • 在方案二中,加大eden区,minorgc触发频次会变少,假设触发间隔变成600ms,对象存活时间还是500ms,由于触发间隔比较长,已经大于了对象存活时间,所以就不用复制存活对象了,因此虽然t1变大了,但是t2没有了

    • t1和t2的时间对比?

      扫描快,复制慢,因为在 JVM 中,复制对象的成本要远高于扫描成本

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值