第16天-性能压测:压力测试,性能监控,优化QPS,Nginx动静分离

1.性能监控



1.1.JVM架构

在这里插入图片描述
运行时数据区:

  • 方法区:最重要的内存区域,多线程共享,保存了类的信息(名称、成员、接口、父类),反射机制是重要的组成部分,动态进行类操作的实现;

  • 堆内存(Heap):保存对象的真实信息,该内存牵扯到释放问题(GC);

  • 栈内存(Stack):线程的私有空间,在每一次进行方法调用的时候都会存在有栈帧,采用先进后出的设计原则;

    1、本地变量表;局部参数或形参,允许保存有32位的插槽(Solt),如果超过了32位的长度就
    需要开辟两个连续性的插槽(long、double)—— volatile关键字问题;
    2、操作数栈:执行所有得方法计算操作;
    3、常量池引用:String类实例、Integer类实例
    4、返回地址:方法执行完毕后的恢复执行的点;

  • 程序计数器:执行指令的一个顺序编码,该区域的所占比率几乎可以忽略;

  • 本地方法栈:与栈内存功能类似,区别在于是为本地方法服务的;



1.2.堆

在这里插入图片描述
所有的对象实例以及数组都要在堆上分配。堆是垃圾收集器管理的主要区域,也被称为 GC堆 ,是优化最多考虑的地方。
堆可以细分为:

  • 新生代

    1、Eden 空间
    2、From Survivor 空间(S0)
    3、To Survivor 空间(S1)

  • 老年代

  • 永久代/元空间

    JDK8以前永久代,受JVM管理,JDK8以后元空间,直接使用物理内存。因此默认情况下,元空间的大小仅受本地内存限制。



1.3.GC


1.3.1.GC流程

Oracle官网:https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.3.2.GC收集器比较

在这里插入图片描述

  • JDK8默认:Parallel Scavenge
  • JDK9默认:G1


1.4.jconsole与jvisualvm

JDK的两个小工具jconsole、jvisualvm(升级版的jconsole),通过命令行启动,可监控本地和远程应用。

1.4.1.jvisualvm能干什么

监控内存泄漏,跟踪垃圾回收,执行时内存、CPU分析,线程分析…

线程状态:在这里插入图片描述

  • 运行:正在运行的
  • 休眠:sleep方法
  • 等待:wait方法
  • 驻留:线程池里面的空闲线程
  • 监视:阻塞的线程,正在等待锁

1.4.2.安装插件方便查看gc

工具 -> 插件 -> 可用插件->Visual GC

插件中心对应的URL:http://visualvm.github.io/pluginscenters.html

在这里插入图片描述



1.5.监控指标


1.5.1.中间件指标

Nginx

docker stats

每秒会动态刷新下面的监控数据

在这里插入图片描述

添加Nginx访问取样器

在这里插入图片描述

压测

在这里插入图片描述

Gateway

添加取样器

在这里插入图片描述

压测

在这里插入图片描述


1.5.2.数据库指标

  • SQL耗时越小越好,一般情况下微妙级别
  • 命中率越高越好,一般情况下不能低于95%
  • 锁等待次数越低越好,等待时间越短越好

1.5.3.JMeter压测报告分析

在这里插入图片描述

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

业务逻辑:

  • 数据库(MySQL优化,上线关闭SQL日志)
  • 模板的渲染速度(开发环境是关闭缓存的,生产环境开启缓存)
  • 静态资源(Nginx动静分离)

线上OOM演示(服务崩溃)

  • 将应用 VM options调整为 -Xmx100m
  • 使用JMeter,设置200个线程进行压测
  • 应用后台抛出 OOM 异常,系统不能正常访问

优化

  • 调整vm参数:-Xmx1024m -Xms1024m -Xmn512m
  • 修改业务实现代码,减少数据库访问次数


1.6.JVM分析与调优


1.6.1.几个常用工具

  • Arthas:https://arthas.aliyun.com/zh-cn/
  • GCeasy:https://gceasy.io/

1.6.2.命令示例

JDK监控和故障处理命令有

  • jps
  • jstat
  • jmap
  • jhat
  • jstack
  • jinfo

1.6.3.jmap生成dump

jps
# pid:通过jps可以查看到进程id
jmap -dump:live,format=b,file=c:\test.dump <pid>

分析:使用jvisualvm导入dump文件进行分析

1.6.4.JVM调优项

常用 JVM 参数:

  • -Xms :初始堆大小,默认为物理内存的1/64(<1GB);默认(MinHeapFreeRatio参数可以调 整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制
  • -Xmx :最大堆大小,默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM 会减少堆直到 -Xms的最小限制
  • -Xmn :新生代的内存空间大小,注意:此处的大小是(eden+ 2 survivor space)。与jmap - heap中显示的New gen是不同的。整个堆大小=新生代大小 + 老生代大小 + 永久代大小。在保
    证堆大小不变的情况下,增大新生代后,将会减小老生代大小。此值对系统性能影响较大,Sun 官方推荐配置为整个堆的3/8。
  • -XX:SurvivorRatio :新生代中Eden区域与Survivor区域的容量比值,默认值为8。两个 Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。
  • -Xss :每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小 为256K。应根据应用的线程所需内存大小进行适当调整。在相同物理内存下,减小这个值能
    生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值 在3000~5000左右。一般小的应用, 如果栈不是很深, 应该是128k够用的,大的应用建议使
    用256k。这个选项对性能影响比较大,需要严格的测试。和threadstacksize选项解释很类
    似,官方文档似乎没有解释,在论坛中有这样一句话:"-Xss is translated in a VM flag named
    ThreadStackSize”一般设置这个值就可以了。

Spring Boot 部署运行方案:

使用默认JVM配置运行

  • 前台运行,关闭窗口后退出:java -jar /jar包路径
  • 后台运行:nohup java -jar /jar包路径
  • #后台运行,指定启动日志记录文件:nohub java -jar /jar包路径 > /指定日志文件路径

配置JVM参数运行
  • 前台运行
    java -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m - Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -jar /jar包路径
  • 后台运行
    nohup java -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -jar /jar包路径

JVM参数说明:

  • -XX:MetaspaceSize=128m (元空间默认大小)
  • -XX:MaxMetaspaceSize=128m (元空间最大大小)
  • -Xms1024m (初始化堆大小)
  • -Xmx1024m (最大堆大小)
  • -Xmn256m (新生代大小)
  • -Xss256k (栈最大深度大小)
  • -XX:SurvivorRatio=8 (新生代分区比例 8:2)
  • -XX:+UseConcMarkSweepGC (指定使用的垃圾收集器,这里使用CMS收集器)

知识点

JDK8之后把-XX:PermSize 和 -XX:MaxPermGen移除了,取而代之的是-XX:MetaspaceSize=128m (元空间默认大小)-XX:MaxMetaspaceSize=128m (元空间最大大小)

JDK 8开始把类的元数据放到本地化的堆内存(native heap)中,这一块区域就叫Metaspace,中文名叫元空间。

使用本地化的内存有什么好处呢?

最直接的表现就是java.lang.OutOfMemoryError: PermGen空间问题将不复存在,因为默认的类的 元数据分配只受本地内存大小的限制,也就是说本地内存剩余多少,理论上Metaspace就可以有多
大(貌似容量还与操作系统的虚拟内存有关),这解决了空间不足的问题。不过,让Metaspace变
得无限大显然是不现实的,因此我们也要限制Metaspace的大小:使用-XX:MaxMetaspaceSize参
数来指定Metaspace区域的大小。JVM默认在运行时根据需要动态地设置MaxMetaspaceSize的大 小。



2.压力测试

压力测试考察当前硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。压测都是为了系统在线上的处理能力和稳定性维持在一个标准范围之内,做到心中有数。

使用压力测试,我们有希望找到很多种用其它测试方法更难发现的错误。有两种错误类型是:内存泄漏,并发与同步

有效的压力测试系统将应用以下这些关键条件:重复,并发,量级,随机变化



2.1.性能指标

响应时间(Response Time:RT)

响应时间指用户从客户端发起一个请求开始,到客户端接收到从服务器返回的响应结束,整个过程所耗费的时间。

HPS(Hits Per Second)每秒点击次数,单位是次/秒

TPS(Transaction Per Seconde)系统每秒处理交易数,单位是笔/秒

QPS(Query Per Second)系统每秒处理查询次数,单位是次/秒

对于互联网业务中,如果某些业务有且仅有一个请求连接,那么TPS=QPS=HPS,一般情况下使用TPS来衡量整个业务流程,用QPS来衡量接口查询次数,用HPS来表示对服务器单机请求。

无论TPD、QPS、HPS,这些指标是衡量系统处理能力非常重要的指标,越大越好,根据经验,一般情况下:

金融行业:1000TPS ~ 50000TPS,不包括互联网化的活动(比如秒杀,营销活动等)

保险行业:100TPS ~100000TPS,不包括互联网化的活动(比如秒杀,营销活动等)

制造行业:10TPS ~ 5000TPS

电商网站:10000TPS ~1000000TPS

中型网站:1000TPS ~ 50000TPS

小型网站:500TPS ~ 10000TPS

最大响应时间(Max Response Time)指用户发出请求或者指令到系统做出反应(响应)的最大时间

最少响应时间(Mininum Response Time)指用户发出请求或者指令到系统做出反应(响应)的最少时间

90%响应时间(90% Response Time)指所有用户的响应时间进行排序,第90%的响应时间


从外部看,性能测试主要关注如下三个指标

吞吐量:每秒系统能够处理的请求数、任务数

响应时间:服务处理一个请求或一个任务的耗时

错误率:一批请求中结果出错的请求所占比例

影响性能考虑点包括:

  • 数据库、应用程序、中间件(Tomcat、Nginx等)、网络和操作系统等方面
  • 首先考虑自己的应用属于CPU密集型还是IO密集型


2.2、性能测试工具

常用的性能测试工具有很多,在这里列举几个比较实用的。对于开发人员来说,首选是一些开源免费的性能(压力)测试软件,例如ab(ApacheBench)、JMeter 等;对于专业的测试团队来说,付费版的LoadRunner 是首选。当然,也有很多公司是自行开发了一套量身定做的性能测试软件,优点是定制化强,缺点则是通用性差。

在这里插入图片描述



3.JMeter



3.1.JMeter安装

  • 官网下载:https://jmeter.apache.org/download_jmeter.cgi
  • 解压安装,运行 jmeter.bat



3.2、JMeter基本使用


3.2.1.新建测试计划


3.2.2.添加线程组

在这里插入图片描述

在这里插入图片描述

3.2.3.添加取样器

在这里插入图片描述

3.2.4.添加监听器

在这里插入图片描述

3.2.5.启动压测&查看分析

在这里插入图片描述



3.3.Address Already in use 错误解决

原因:windows本身提供的端口访问机制的问题,windows提供给 TCP/IP 连接的端口为 1024 - 5000,并且要四分钟来循环回收,就导致我们在短时间内跑大量的请求时将端口占满了。

解决方案:

  • Win+R打开运行窗口,输入 regedit 命令打开注册表

  • 在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
    下,

    1、右击Parameters,添加一个新的DWORD,名字为 MaxUserPort,双击 MaxUserPort,输入数值数据为 65534,基数选择十进制(若分布式运行,控制机器和负载机器都需要这样操作)
    2、右击Parameters,添加一个新的DWORD,名字为 TCPTimedWaitDelay,双击
    TCPTimedWaitDelay,输入数值数据为 30,基数选择十进制(若分布式运行,控制机器和负载机器都需要这样操作)

  • 修改配置完毕后需要重启机器才会生效



4.Nginx动静分离



4.1.架构

在这里插入图片描述

  • 将所有项目的静态资源都需放在nginx里面
  • 规则:/nginx/html/static/**
  • 所有静态资源请求都统一由nginx直接返回



4.2.静态资源迁移

  • gmall-product\resources\static\index 整个文件夹上传到
    /mydata/nginx/html/static
  • 删除 gmall-product\resources\static\index 整个文件夹



4.3.修改index.html模板页面

在所有模板页面用到的静态资源统一加上 /static/ 前置路径



4.4.Nginx配置

gmall.conf

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

重启nginx容器

docker restart nginx



4.5.首页全量数据获取压测

即使提高压测线程数,也不会造成JMeter卡死情况



5.三级分类数据获取优化



5.1.优化代码实现逻辑

优化业务实现的代码逻辑:将数据库的多次查询变为一次

/**
 * 查询首页展示分类列表
 * @return
 */
@Override
public Map<String, List<Catalog2VO>> getCatalogJson() {
    // 查询出所有的分类数据
    List<CategoryEntity> entities = list(null);

    // 查询所有一级分类
    List<CategoryEntity> level1Categories = getParents(entities, 0L);

    // 封装数据
    Map<String, List<Catalog2VO>> map = level1Categories.stream().collect(
            Collectors.toMap(k -> k.getCatId().toString(), v -> {

                // 查询当前一级分类的所有二级分类,封装成vo
                List<CategoryEntity> level2Categories = getParents(entities, v.getCatId());

                List<Catalog2VO> catalog2VOS = null;
                if (level2Categories != null) {
                    catalog2VOS = level2Categories.stream().map(category2 -> {
                        Catalog2VO catalog2VO = new Catalog2VO(
                                v.getCatId().toString(),
                                null,
                                category2.getCatId().toString(),
                                category2.getName());

                        // 查询当前二级分类的所有三级分类,封装为vo
                        List<CategoryEntity> level3Categories = getParents(entities, category2.getCatId());
                        if (level3Categories != null) {
                            List<Catalog2VO.Catalog3VO> catalog3VOS = level3Categories.stream().map(catalog3 -> {
                                Catalog2VO.Catalog3VO catalog3VO = new Catalog2VO.Catalog3VO(
                                        category2.getCatId().toString(),
                                        catalog3.getCatId().toString(),
                                        catalog3.getName());
                                return catalog3VO;
                            }).collect(Collectors.toList());
                            catalog2VO.setCatalog3List(catalog3VOS);
                        }
                        return catalog2VO;
                    }).collect(Collectors.toList());
                }
                return catalog2VOS;
            }));

    return map;
}

/**
 * 根据分类父id查找所有的子分类
 * @param categories 所有分类数据
 * @param parentId 分类父id
 * @return
 */
private List<CategoryEntity> getParents(List<CategoryEntity> categories, Long parentId) {
    List<CategoryEntity> entities = categories.stream()
            .filter(categoryEntity -> categoryEntity.getParentCid().equals(parentId))
            .collect(Collectors.toList());
    return entities;
}


5.2.JMeter压测结果对比

  • 未加索引和代码逻辑未优化
    QPS:5/s
  • pms_category 表给 parent_cid 字段加索引
    QPS:25/s
  • 优化代码逻辑
    QPS:395/s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/2578.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[排序算法]堆排序

参考&#xff1a;《漫画算法-小灰的算法之旅》 目录 一、堆排序过程 二、堆排序的代码实现 三、时间复杂度和空间复杂度 四、从宏观上看&#xff0c;堆排序和快速排序相比&#xff0c;有什么区别和联系呢 回顾二叉堆&#xff1a; 1.最大堆的堆顶是整个堆中的最大元素。 2…

基于SpringBoot的外卖项目(详细开发过程)

基于SpringBootMyBatisPlus的外卖项目1、软件开发整体介绍软件开发流程角色分工2、外卖项目介绍项目介绍产品展示后台系统管理移动端技术选型功能结构角色3、开发环境的搭建开发环境说明建库建表Maven项目搭建项目的目录结构pom.xmlapplication.ymlReggieApplication启动类配置…

[JAVA]继承

目录 1.继承的概念 2.继承的语法 3.父类成员访问 3.1子类中访问父类成员变量 3.2子类中访问父类成员方法 4.super关键字 5.子类构造方法 6.继承方式 7.final关键字和类的关系 面向对象思想中提出了继承的概念&#xff0c;专门用来进行共性抽取&#xff0c;实现代码复…

2023年顶级编程语言趋势

对于开发人员和软件工程师来说&#xff0c;选择更优秀的编程语言使编写可以在任何地方运行的软件变得更加容易&#xff0c;工作效率更高。从 Java 的缓慢衰落到 MATLAB 的惊人流行&#xff0c;对当今最流行的编程语言的分析&#xff0c;可以帮助你了解最新趋势并响应最新趋势。…

总结:K8S运维常用命令

一、部署./kubectl apply -f biz-healing-pod.yaml 二、查看部署的资源1、podkubectl get pod -A&#xff1a;获取所有pod没有IP&#xff1f;用-o wide参数看详细信息&#xff1a;./kubectl get pod -n deepflow -o wide2、service查看hubble-manager命名空间下有哪些service/d…

Excel函数公式大全—函数真经

EXCEL系列文章目录 Excel系列文章是本人亲身经历职场之后萌发的想法&#xff0c;为什么Excel覆盖如此之广&#xff0c;几乎每个公司、学校、家庭都在使用&#xff0c;但是它深藏的宝藏功能却很少被人使用&#xff0c;PQ、BI这些功能同样适用于数据分析&#xff1b;并且在一些需…

ViewService——一种保证客户端与服务端同步的方法

简介在分布式系统中&#xff0c;最常见的场景就是主备架构。但是如果主机不幸宕机&#xff0c;如何正确的通知客户端当前后端服务器的状况成为一个值得研究的问题。本文描述了一种简单的模型用于解决此问题。背景以一个分布式的Key-Value数据库为背景。数据库对外提供3个接口Ge…

有哪些计算机网络和通讯领域的SCI期刊推荐? - 易智编译EaseEditing

IEEE/ACM Transactions on Networking: 这是由IEEE和ACM联合出版的计算机网络领域的顶级期刊&#xff0c;涵盖了网络协议、体系结构、性能评估、网络管理、安全等多个方面。 Computer Networks: 这是一本综合性的计算机网络期刊&#xff0c;包括分布式系统、网络协议、移动计…

Spring注册Bean的方式

文章目录一、xml方式注册Bean二、ConfigurationBean注册Bean三、ComponentScan注册Bean1. 使用XML文件配置包扫描2. 使用注解配置包扫描3. ComponentScans源码4. ComponentScan源码5. ComponentScan value includeFilters6. ComponentScan value excludeFilters7. Componen…

rabbitMQ介绍及使用方法

目录 一、MQ概述 二、RabbitMQ简介 三、RabbitMQ的五种工作模式 1、简单模式 2、work queues工作队列模式 3、Pub/Sub 订阅模式 4、Routing 路由模式 5、Topics 通配符模式 一、MQ概述 MQ全称Message Queue (消息队列)&#xff0c;是在消息的传输过程中保存消息的容器…

电商项目后端框架SpringBoot、MybatisPlus

后端框架基础 1.代码自动生成工具 mybatis-plus &#xff08;1&#xff09;首先需要添加依赖文件 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.2</version></dependency><de…

【linux】进程信号——信号的产生

进程信号一、信号概念1.1 信号理解二、产生信号2.1 通过键盘产生信号2.2 捕捉信号自定义signal2.3 系统调用接口产生信号2.3.1 向任意进程发送任意信号kill2.3.2 给自己发送任意信号raise2.3.3 给自己发送指定信号abort2.3.4 理解2.4 硬件异常产生信号2.4.1 除0异常2.4.2 野指针…

蓝桥杯刷题冲刺 | 倒计时17天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.长草2.分考场1.长草 题目 链接&#xff1a; 长草 - 蓝桥云课 (lanqiao.cn) 题目描述 小明有一…

Feign远程调用

之前在一篇博客中写了利用RestTemplate发起远程调用的代码&#xff0c;但是存在一下问题&#xff1a;代码可读性差&#xff0c;编程体验不统一&#xff1b;如果参数特别多的话&#xff0c;参数复杂URL难以维护。Feign官方地址&#xff1a;https://github.com/OpenFeign/feignFe…

行业观察 | 来了解一下AI加速器

本文参考网上可查询到的资料简要总结AI加速器的概念和应用等信息 1。 未完待续 更新&#xff1a; 2023 / 3 / 22 行业观察 | 来了解一下AI加速器前言加速器处理器处理器是什么&#xff1f;处理器进化史加速器架构指令集 ISA特定领域的指令集 ISA超长指令字&#xff08;VLIW&a…

如何使用子项目管理方案?

在项目进行中经常发生这样的情况&#xff1a;当你开始为一个项目制定时间表时&#xff0c;你会发现任务的数量太多。你需要把它们全部分组到一些摘要任务中。但随后你看到一堆摘要任务&#xff0c;也想把它们再分组。 这样一来&#xff0c;该项目变得很麻烦&#xff0c;甚至项目…

Matlab进阶绘图第10期—带填充纹理的柱状图

带填充纹理的柱状图是通过在原始柱状图的基础上添加不同的纹理得到的&#xff0c;可以很好地解决由于颜色区分不足而导致的对象识别困难问题。 由于Matlab中未提供纹理填充选项&#xff0c;因此需要大家自行设法解决。 本文使用Kesh Ikuma制作的hatchfill2工具&#xff08;Ma…

gin框架使用websocket实现进入容器内部执行命令

文章目录1. 先决条件2. gin框架实现3. 测试用html文件4. 需要完善1. 先决条件 docker开放远程API端口 2. gin框架实现 type GetCommandResultRequire struct {IpAddr string json:"ip_addr" //传入要控制容器的ip地址ContainerUuid string json:"cont…

对堆题的总体思路

浅说一下pwn堆并用一个简单的例子具体说明给刚入坑堆的小朋友说的一些思路说一下堆是什么堆你可以看成一个结构体数组&#xff0c;然后数组里每个元素都会开辟一块内存来存储数据那么这块用来存储数据的内存就是堆。结构体数组在BSS段上&#xff0c;其内容就是堆的地址&#xf…

动态SQL必知必会

动态SQL必知必会1、什么是动态SQL2、为什么使用动态SQL3、动态SQL的标签4、if 标签-单标签判断5、choose标签-多条件分支判断6、set 标签-修改语句7、foreach标签7.1 批量查询7.2 批量删除7.3 批量添加8、模糊分页查询1、什么是动态SQL 动态 SQL 是 MyBatis 的强大特性之一。如…