谷粒商城微服务分布式高级篇七——压力测试和性能优化

压力测试

压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。压测都是为了系统在线上的处理能力和稳定性维持在一个标准范围内,做到心中有数。
使用压力测试,我们有希望找到很多种用其他测试方法更难发现的错误。有两种错误类型是:内存泄漏,并发与同步
有效的压力测试系统将应用以下这些关键条件:重复,并发,量级,随机变化

性能指标

  • 响应时间(Response Time: RT)

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

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

  • TPS (Transaction per Second);,系統每秒处理交易数,单位是笔秒。

  • OPS (Query per Second) :系统每秒处理查询次数,单位是次秒。

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

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

金融行业: 1000TPS-50000TPs,不包括互联网化的活动
保险行业: 100TPS-100000Tps. 包括互联网化的活动
制造行业: 10TPS-5000TPS
互联网电子商务: 1000OTPS-1000000TPS
互联网中型网站: 1000TPS-50000TPS
互联网小型网站: 500TPS~1000TPS

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

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

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

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

吞吐量;每秒钟系统能够处理的请求数、任务数.
响应时间:服务处理一个请求或一个任务的耗时。
错误率:一批请求中结果出错的请求所占比例。

JMeter

JMeter安装

下载页
下载对应的压缩包,解压运行bin下的jmeter.bat即可
在这里插入图片描述
打开修改中文
在这里插入图片描述
添加线程组模拟用户
在这里插入图片描述
模拟200个用户1s内启动,循环100次,即20000个请求在这里插入图片描述
添加http请求
在这里插入图片描述
请求百度
在这里插入图片描述
添加查看结果树,汇总报告
在这里插入图片描述
请求项目测试
可参考

JMeter Address Already in use错误解决

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

1.cmd中,用regedit命令打开注册表
2在 HKEY LOCAL MACHINESYSTEM\CurrentControlSet\Services\Ticpip\lParameters 下,

1、右击parameters,添加一个新的DWORD.名字为MaxUserPort
2、然后双击MaxUserPort,输入数值数据为65534,基数选择十进制(如果是分布式运行的话,控制机器和负载机器都需要这样操作哦)
3、30s即回收端口 TCPTimedWaitDelay: 30

3,修改配置完毕之后记得重启机器才会生效

微软帮助文档

jconsole与jvisualvm

Jdk的两个小工具console visulvm (升级版的consoke),通过命令行启动,可监控本地和远程应用.远程应用需要配置
使用步骤

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

优化

中间件对性能的影响

对Nginx进行测试
在这里插入图片描述

监控nginx状态

docker stats

在这里插入图片描述
内存消耗少。多计算、耗cpu

对Gateway进行压测,同时监控内存
在这里插入图片描述
在这里插入图片描述
耗cpu
在这里插入图片描述
伊甸园区内存小,GC频繁

简单优化吞吐量测试

对简单请求进行压测

  /**
     * 简单请求
     * @return
     */
    @ResponseBody
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
网关+简单请求

- id: product_route
  #lb 表示转发至服务 服务也需注册到nacos
  uri: lb://mall-product
  predicates:
    #当请求为指定路径 断言为真 **代表任意 这个路径需往上写提高优先级不被/api/**给拦截
    - Path=/api/product/**,/hello
  filters:
    #断言为真,重写路径/api/(?<segment>.*)改为/$\{segment}
    #例请求http://localhost:88/api/product/category/list/tree会改为
    #http://mall-product端口/product/category/list/tree
    - RewritePath=/api/(?<segment>.*),/$\{segment}

在这里插入图片描述
吞吐量下降

三级分类数据测试

在这里插入图片描述

nginx动静分离

在这里插入图片描述
将静态资源static包传输到nginx的html文件夹下
在这里插入图片描述
修改之前conf.d下商品服务配置文件,添加上规则

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

重启nginx

docker restart nginx

注意html文件中路径应该加上static,比如

href="/static/index/css/swiper-3.4.2.min.css"

模拟线上应用内存崩溃宕机情况

200个线程 并行下载6
在这里插入图片描述

设置vm参数:-Xmx=100m
服务崩溃:
在这里插入图片描述
正确参数:
-Xmx=1024m -Xms1024m -Xmn512m
在这里插入图片描述

测试数据表格

压测内容压测线程数吞吐量/s90%响应时间99%响应时间
Nginx508931775
Gateway508972836
简单服务5058999143
首页一级菜单渲染50270267365
三级分类数据获取5071119212755
首页全量数据获取508/19
Nginx+Gateway50
Gateway 简单服务5019404496
全链路50968120350

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

由此推出:
单独网关服务,nginx,简单服务,吞吐量都很高,可是通过nginx代理到网关,然后网关路由到服务,吞吐量明显下降,可见调用链路越长,中间件越多,对性能影响越大。
性能优化从业务一般考虑如下几个方面:
1、DB(考虑sql加索引,sql优化,关日志)
2、模板渲染速度(thymeleaf线上要打开缓存,开发关闭)
3、静态资源(nginx动静分离)
4、visualvm查看GC情况,如果GC次数过多证明分配内存偏小
5、业务优化(优化掉频繁查库的操作)
6、加入redis缓存

优化三级分类数据获取

原有代码(查询了三次数据库):

    /**
     * 查出所有分类 返回首页json
     *
     * @return
     */
    @Override
    public Map<String, List<Catalog2Vo>> getCatalogJson() {


        //先查出所有一级分类
        List<CategoryEntity> level1Categorys = getLevel1Categorys();

        //封装数据 map k,v 结构
        Map<String, List<Catalog2Vo>> map = level1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //每一个的一级分类,查到这个一级分类的二级分类
            List<CategoryEntity> category2Entities = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", v.getCatId()));
            List<Catalog2Vo> catelog2Vos = null;

            if (category2Entities != null) {
                catelog2Vos = category2Entities.stream().map(level2 -> {
                    //封装catalog2Vo
                    Catalog2Vo catalog2Vo = new Catalog2Vo(v.getCatId().toString(), null, level2.getCatId().toString(), level2.getName());
                    //每一个二级分类,查到三级分类
                    List<CategoryEntity> category3Entities = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", level2.getCatId()));
                    if (category3Entities != null) {
                        List<Object> catalog3List = category3Entities.stream().map(level3 -> {
                            //封装catalog3Vo
                            Catalog2Vo.Catalog3Vo catalog3Vo = new Catalog2Vo.Catalog3Vo(level2.getCatId().toString(), level3.getCatId().toString(), level3.getName());
                            return catalog3Vo;
                        }).collect(Collectors.toList());
                        //封装catalog3Vo到catalog2Vo
                        catalog2Vo.setCatalog3List(catalog3List);
                    }
                    return catalog2Vo;
                }).collect(Collectors.toList());
            }
            //返回v=catalog2Vo
            return catelog2Vos;
        }));


        return map;

    }

应该第一次查询出来所有,后面拿查询出来的去操作
优化后:

    /**
     * 根据传进分类筛选出对应级别
     *
     * @param list
     * @param parent_cid
     * @return
     */
    public List<CategoryEntity> getCategorys(List<CategoryEntity> list, Long parent_cid) {

        List<CategoryEntity> collect = list.stream().filter(l -> parent_cid.equals(l.getParentCid())).collect(Collectors.toList());

        return collect;
    }

    /**
     * 查出所有分类 返回首页json
     *
     * @return
     */
    @Override
    public Map<String, List<Catalog2Vo>> getCatalogJson() {

        //查询出所有分类
        List<CategoryEntity> selectList = baseMapper.selectList(null);

        //先查出所有一级分类
        List<CategoryEntity> level1Categorys = getCategorys(selectList, 0L);

        //封装数据 map k,v 结构
        Map<String, List<Catalog2Vo>> map = level1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //每一个的一级分类,查到这个一级分类的二级分类
            List<CategoryEntity> category2Entities = getCategorys(selectList, v.getCatId());
            List<Catalog2Vo> catelog2Vos = null;

            if (category2Entities != null) {
                catelog2Vos = category2Entities.stream().map(level2 -> {
                    //封装catalog2Vo
                    Catalog2Vo catalog2Vo = new Catalog2Vo(v.getCatId().toString(), null, level2.getCatId().toString(), level2.getName());
                    //每一个二级分类,查到三级分类
                    List<CategoryEntity> category3Entities = getCategorys(selectList, level2.getCatId());
                    if (category3Entities != null) {
                        List<Object> catalog3List = category3Entities.stream().map(level3 -> {
                            //封装catalog3Vo
                            Catalog2Vo.Catalog3Vo catalog3Vo = new Catalog2Vo.Catalog3Vo(level2.getCatId().toString(), level3.getCatId().toString(), level3.getName());
                            return catalog3Vo;
                        }).collect(Collectors.toList());
                        //封装catalog3Vo到catalog2Vo
                        catalog2Vo.setCatalog3List(catalog3List);
                    }
                    return catalog2Vo;
                }).collect(Collectors.toList());
            }
            //返回v=catalog2Vo
            return catelog2Vos;
        }));


        return map;

    }

大型网站高性能架构

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值