性能测试与优化
性能压测
Jmeter官网:https://jmeter.apache.org/
添加线程组:
添加取样器:
添加监 听器,用来查看结果:
JVM内存模型
Java虚拟机(JVM)内存模型是Java应用程序在运行时使用的内存组织方式。它主要分为两部分:堆内存和方法区。
- 堆内存(Heap): 用于存储对象实例。堆内存被所有线程共享,其中包含了新生代和老年代两部分。新生代主要存放新创建的对象,而老年代则存放经过多次垃圾回收后仍然存活的对象。
- 方法区(Method Area): 存储类的元数据信息,如类的结构、字段、方法、接口等。与堆内存一样,方法区也是被所有线程共享的。
JVM内存模型中的其他重要概念包括:
- 栈内存(Stack): 为每个线程分配一个私有的栈,用于存储线程执行方法时的局部变量、操作数栈、动态链接、方法出口等信息。
- 程序计数器(Program Counter): 每个线程都有一个程序计数器,用于记录当前线程执行的字节码行号。在线程切换时,程序计数器的值被恢复,保证线程能够正确地执行。
- 本地方法栈(Native Method Stack): 与栈内存类似,但用于执行本地方法。在使用JNI(Java Native Interface)调用本地方法时,会使用本地方法栈。
- 直接内存(Direct Memory): 不是JVM内部的一部分,但与JVM密切相关。在使用NIO(New I/O)时,可以使用直接内存来提高I/O性能。直接内存不 受JVM堆内存限制,但受操作系统的限制。
jconsole和jvisualvm
控制台输入jconsole即可启动
jvisualvm在高版本的java(Java8_361以上)需要下载
https://visualvm.github.io/download.html
中间件性能测试
请求的过程:
nginx测试:
使用docker stats
检测nginx性能
初始状态:
开启jmeter
网关测试
中间件越多,性能损失越大,大多都损失在网络交互了:
业务:
- db
- 模版的渲染速度(缓存)
- 静态资源
压测统计(线程数50):
压测内容 | 吞吐量/s | 90%响应时间 | 99%响应时间 |
---|---|---|---|
简单服务 | 6537 | 11 | 68 |
首页一级菜单渲染 | 336 | 296 | 501 |
首页一级菜单渲染(开缓存) | 707 | 152 | 375 |
首页一级菜单渲染(开缓存,sql优化,日志优化) | 832 | 125 | 280 |
首页一级菜单渲染(开缓存,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;
}
给字段加索引:
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;
}