跳到主要内容

性能测试与优化

性能压测

Jmeter官网:https://jmeter.apache.org/

添加线程组:

image-20240130104738424

添加取样器:

image-20240130104842927

添加监听器,用来查看结果:

image-20240130104955143

JVM内存模型

Java虚拟机(JVM)内存模型是Java应用程序在运行时使用的内存组织方式。它主要分为两部分:堆内存方法区

  1. 堆内存(Heap): 用于存储对象实例。堆内存被所有线程共享,其中包含了新生代和老年代两部分。新生代主要存放新创建的对象,而老年代则存放经过多次垃圾回收后仍然存活的对象。
  2. 方法区(Method Area): 存储类的元数据信息,如类的结构、字段、方法、接口等。与堆内存一样,方法区也是被所有线程共享的。

JVM内存模型中的其他重要概念包括:

  • 栈内存(Stack): 为每个线程分配一个私有的栈,用于存储线程执行方法时的局部变量、操作数栈、动态链接、方法出口等信息。
  • 程序计数器(Program Counter): 每个线程都有一个程序计数器,用于记录当前线程执行的字节码行号。在线程切换时,程序计数器的值被恢复,保证线程能够正确地执行。
  • 本地方法栈(Native Method Stack): 与栈内存类似,但用于执行本地方法。在使用JNI(Java Native Interface)调用本地方法时,会使用本地方法栈。
  • 直接内存(Direct Memory): 不是JVM内部的一部分,但与JVM密切相关。在使用NIO(New I/O)时,可以使用直接内存来提高I/O性能。直接内存不受JVM堆内存限制,但受操作系统的限制。

image-20240130131607337

jconsole和jvisualvm

控制台输入jconsole即可启动

image-20240130134051095

jvisualvm在高版本的java(Java8_361以上)需要下载

https://visualvm.github.io/download.html

image-20240130134223908

中间件性能测试

请求的过程:

image-20240130134709896

nginx测试:

使用docker stats 检测nginx性能

初始状态:

image-20240130140154107

开启jmeter

image-20240130140520195

image-20240130140127522

网关测试

image-20240130140733314

中间件越多,性能损失越大,大多都损失在网络交互了:

业务:

  • db
  • 模版的渲染速度(缓存)
  • 静态资源

压测统计(线程数50):

压测内容吞吐量/s90%响应时间99%响应时间
简单服务65371168
首页一级菜单渲染336296501
首页一级菜单渲染(开缓存)707152375
首页一级菜单渲染(开缓存,sql优化,日志优化)832125280

首页一级菜单渲染(开缓存,sql优化,日志优化)

  thymeleaf:
cache: true
logging:
level:
org.org.springframework.web: error
com.cxk.gulimall: error

统计sql用时

@Override
public List<CategoryEntity> getLevel1Categories() {
long l = System.currentTimeMillis();
List<CategoryEntity> categoryEntities = this.baseMapper.selectList(new LambdaQueryWrapper<CategoryEntity>()
.eq(CategoryEntity::getParentCid, 0));
System.out.println("消耗时间:"+(System.currentTimeMillis() - l));
return categoryEntities;
}

image-20240130153207998

给字段加索引:

image-20240130153302738

nginx动静分离

将前端页面放在自己挂载的nginx/static目录下面

修改配置

    location /static/ {
root /usr/share/nginx/html;
}

location / {
proxy_set_header Host $host;
proxy_pass http://gulimall;
}

重启docker

优化代码,少于数据库做交互:

@Override
public Map<String, List<Catelog2Vo>> getCatalogJson() {
List<CategoryEntity> selectedList = baseMapper.selectList(null);
//查出所有1级分类
List<CategoryEntity> level1Categories = this.getLevel1Categories();

//封装数据
Map<String, List<Catelog2Vo>> parentCid = level1Categories.stream().collect(Collectors.toMap(k -> {
return k.getCatId().toString();
}, v -> {
//每一个1级分类,查到这个一级分类的二级分类
List<CategoryEntity> categoryEntities = getParentCid(selectedList,v.getCatId());
//封装数据
List<Catelog2Vo> collect = null;
if (categoryEntities != null) {
collect = categoryEntities.stream().map(level2 -> {
Catelog2Vo catelog2Vo = new Catelog2Vo(v.getCatId().toString(), null,
level2.getCatId().toString(), level2.getName());
//找当前二级分类的三级分类封装成vo
List<CategoryEntity> level3Catelog = getParentCid(selectedList,level2.getCatId());
if (level3Catelog != null) {
List<Catelog2Vo.Catalog3Vo> catalog3Vos = level3Catelog.stream().map(level3 -> {
Catelog2Vo.Catalog3Vo catalog3Vo = new Catelog2Vo.Catalog3Vo(level2.getCatId().toString(),
level3.getCatId().toString(), level3.getName());
return catalog3Vo;
}).collect(Collectors.toList());
catelog2Vo.setCatalog3List(catalog3Vos);
}
return catelog2Vo;
}).collect(Collectors.toList());
}
return collect;
}));
return parentCid;
}

private List<CategoryEntity> getParentCid(List<CategoryEntity> selectList, Long v) {
List<CategoryEntity> collect = selectList.stream().filter(item ->
item.getParentCid().equals(v)).collect(Collectors.toList());
return collect;
}