当前位置: 首页 > news >正文

053 性能压测 单机锁 setnx

文章目录

  • 性能压测-压力测试
    • 索引
    • thymeleaf
    • nginx
    • 减少数据库查询(代码有bug)
    • 缓存
  • 安全
    • 单机锁(防止缓存击穿)
    • setnx
  • pom.xml

性能压测-压力测试

1 响应时间(Response Time: RT):响应时间指用户从客户端发起一个请求开始,到客户端接收到从服务器端返回的响应结束,整个过程所耗费的时间。
HPS(Hits Per Second):每秒点击次数,单位是次/秒
TPS(Transaction per Second):系统图每秒处理交易数,单位是笔/秒
OPS(Query per Second):系统每秒处理查询次数,单位是次/秒
2 性能测试主要关注如下三个指标:
吞吐量:每秒钟系统能够处理的请求数、任务数
响应时间:服务处理一个请求或一个任务的耗时
错误率:一批请求中结果出错的请求所占比例
https://jmeter.apache.org/download_jmeter.cgi

索引

索引

thymeleaf

spring:
  thymeleaf:
    cache: true

nginx

conf.d


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

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

减少数据库查询(代码有bug)

    /**
     * 获取三级分类
     * @return
     */
    @Override
    public List<CategoryVo> getLevel1Categorys() {

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

        List<CategoryEntity> categoryEntities = getParentId(selectList,0);

        List<CategoryVo> CategoryVoList = categoryEntities.stream().map(categoryEntity -> {
            CategoryVo categoryVo = new CategoryVo();
            BeanUtils.copyProperties(categoryEntity, categoryVo);

            //查询一级分类下的二级分类
            List<CategoryEntity> level2Categorys = getParentId(selectList,categoryEntity.getId());

            //将当前一级分类下的二级分类封装成Vo
            if (level2Categorys != null) {
                List<Category2Vo> category2VoList = level2Categorys.stream().map(level2Category -> {
                    Category2Vo category2Vo = new Category2Vo();
                    category2Vo.setId(level2Category.getId().toString());
                    category2Vo.setName(level2Category.getName());
                    category2Vo.setCategory1Id(categoryEntity.getId().toString());

                    //查询二级分类下的三级分类
                    List<CategoryEntity> level3Categorys = getParentId(selectList,level2Category.getId());

                    //将当前二级分类下的三级分类封装到Vo
                    if (level3Categorys != null) {
                        List<Category3Vo> category3VoList = level3Categorys.stream().map(level3Category -> {
                            Category3Vo category3Vo = new Category3Vo();
                            category3Vo.setId(level3Category.getId().toString());
                            category3Vo.setName(level3Category.getName());
                            category3Vo.setCategory2Id(category2Vo.getId());

                            return category3Vo;
                        }).collect(Collectors.toList());
                        category2Vo.setCategory3VoList(category3VoList);
                    }

                    return category2Vo;
                }).collect(Collectors.toList());
                categoryVo.setCategory2VoList(category2VoList);
            }

            return categoryVo;

        }).collect(Collectors.toList());

        return CategoryVoList;
    }

    private List<CategoryEntity> getParentId(List<CategoryEntity> selectList, Integer parentId) {
        List<CategoryEntity> collect = selectList.stream().filter(item -> {
            return item.getParentId() == parentId;
        }).collect(Collectors.toList());

        return collect;
    }

缓存

缓存使用

    /**
     * 使用redis改造三级分类
     * @return
     */
    public List<CategoryVo> getLevel1Categorys() {
        //1.从缓存中查询数据
        String categoryJSON = redisTemplate.opsForValue().get("categoryJSON");

        if (StringUtils.isEmpty(categoryJSON)) {
            //2.缓存中没有数据,查询数据库,从数据库查询分类数据
            List<CategoryVo> categoryJsonFromDb = getCategoryJsonFromDb();
            //3.查询的数据放入缓存中,将对象转换为json传入
            redisTemplate.opsForValue().set("categoryJSON", JSON.toJSONString(categoryJsonFromDb));
            return categoryJsonFromDb;
        }

        //4.如果缓存中有数据,将查询出的数据转换为java对象,指明转为的对象类型
        List<CategoryVo> categoryVos = JSON.parseObject(categoryJSON, new TypeReference<List<CategoryVo>>() {
        });

        return categoryVos;

    }

安全

单机锁(防止缓存击穿)

单机锁


    /**
     * 使用redis改造三级分类
     * @return
     */
    public List<CategoryVo> getLevel1Categorys() {
        //1.从缓存中查询数据
        String categoryJSON = redisTemplate.opsForValue().get("categoryJSON");

        if (StringUtils.isEmpty(categoryJSON)) {
            System.out.println("缓存不命中,查询数据库。。。");
            //2.缓存中没有数据,查询数据库,从数据库查询分类数据
            List<CategoryVo> categoryJsonFromDb = getCategoryJsonFromDb();

            return categoryJsonFromDb;
        }

        System.out.println("缓存命中。。。");
        //4.如果缓存中有数据,将查询出的数据转换为java对象,指明转为的对象类型
        List<CategoryVo> categoryVos = JSON.parseObject(categoryJSON, new TypeReference<List<CategoryVo>>() {
        });

        return categoryVos;

    }


    /**
     * 获取三级分类
     * @return
     */

    public List<CategoryVo> getCategoryJsonFromDb() {

        synchronized (this){
            //得到锁之后,去查看缓存中是否有数据,如果没有数据,继续查询数据库
            String categoryJSON = redisTemplate.opsForValue().get("categoryJSON");
            if(!StringUtils.isEmpty(categoryJSON)){
                List<CategoryVo> categoryVos = JSON.parseObject(categoryJSON, new TypeReference<List<CategoryVo>>() {
                });
                return categoryVos;
            }
            System.out.println("查询了数据库。。。");

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

            List<CategoryEntity> categoryEntities = getParentId(selectList,0);

            List<CategoryVo> CategoryVoList = categoryEntities.stream().map(categoryEntity -> {
                CategoryVo categoryVo = new CategoryVo();
                BeanUtils.copyProperties(categoryEntity, categoryVo);

                //查询一级分类下的二级分类
                List<CategoryEntity> level2Categorys = getParentId(selectList,categoryEntity.getId());

                //将当前一级分类下的二级分类封装成Vo
                if (level2Categorys != null) {
                    List<Category2Vo> category2VoList = level2Categorys.stream().map(level2Category -> {
                        Category2Vo category2Vo = new Category2Vo();
                        category2Vo.setId(level2Category.getId().toString());
                        category2Vo.setName(level2Category.getName());
                        category2Vo.setCategory1Id(categoryEntity.getId().toString());

                        //查询二级分类下的三级分类
                        List<CategoryEntity> level3Categorys = getParentId(selectList,level2Category.getId());

                        //将当前二级分类下的三级分类封装到Vo
                        if (level3Categorys != null) {
                            List<Category3Vo> category3VoList = level3Categorys.stream().map(level3Category -> {
                                Category3Vo category3Vo = new Category3Vo();
                                category3Vo.setId(level3Category.getId().toString());
                                category3Vo.setName(level3Category.getName());
                                category3Vo.setCategory2Id(category2Vo.getId());

                                return category3Vo;
                            }).collect(Collectors.toList());
                            category2Vo.setCategory3VoList(category3VoList);
                        }

                        return category2Vo;
                    }).collect(Collectors.toList());
                    categoryVo.setCategory2VoList(category2VoList);
                }

                return categoryVo;

            }).collect(Collectors.toList());

            //3.查询的数据放入缓存中,将对象转换为json传入
            redisTemplate.opsForValue().set("categoryJSON", JSON.toJSONString(CategoryVoList),1, TimeUnit.DAYS);

            return CategoryVoList;


        }





    }

    private List<CategoryEntity> getParentId(List<CategoryEntity> selectList, Integer parentId) {
        List<CategoryEntity> collect = selectList.stream().filter(item -> {
            return item.getParentId() == parentId;
        }).collect(Collectors.toList());

        return collect;
    }

setnx

setnx

    /**
     * 获取三级分类(redis分布式锁)
     * @return
     */

    public List<CategoryVo> getCategoryJsonFromWithRedisLock() {

        String uuid = UUID.randomUUID().toString();
            //1.占分布式
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,30,TimeUnit.SECONDS);

        if (lock){
            //加锁成功,执行业务
            //设置过期时间
            //redisTemplate.expire("lock",30,TimeUnit.SECONDS);
            //List<CategoryVo> dataFromDb = getDataFromDb();
            //删除锁
//            String lockValue = redisTemplate.opsForValue().get("lock");
//            if (uuid.equals(lockValue)) {
//                //删除自己的锁
//                redisTemplate.delete("lock");
//            }
            List<CategoryVo> dataFromDb = null;

            try {
                dataFromDb = getDataFromDb();
            } finally {
                //删除锁
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                redisTemplate.execute(new DefaultRedisScript<Integer>(script, Integer.class), Arrays.asList("lock"), uuid);

            }





            return dataFromDb;

        } else {
            //加锁失败,重试
            return getCategoryJsonFromWithRedisLock();//自旋
        }











    }

    private List<CategoryVo> getDataFromDb() {
        //得到锁之后,去查看缓存中是否有数据,如果没有数据,继续查询数据库
        String categoryJSON = redisTemplate.opsForValue().get("categoryJSON");
        if(!StringUtils.isEmpty(categoryJSON)){
            List<CategoryVo> categoryVos = JSON.parseObject(categoryJSON, new TypeReference<List<CategoryVo>>() {
            });
            return categoryVos;
        }
        System.out.println("查询了数据库。。。");

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

        List<CategoryEntity> categoryEntities = getParentId(selectList,0);

        List<CategoryVo> CategoryVoList = categoryEntities.stream().map(categoryEntity -> {
            CategoryVo categoryVo = new CategoryVo();
            BeanUtils.copyProperties(categoryEntity, categoryVo);

            //查询一级分类下的二级分类
            List<CategoryEntity> level2Categorys = getParentId(selectList,categoryEntity.getId());

            //将当前一级分类下的二级分类封装成Vo
            if (level2Categorys != null) {
                List<Category2Vo> category2VoList = level2Categorys.stream().map(level2Category -> {
                    Category2Vo category2Vo = new Category2Vo();
                    category2Vo.setId(level2Category.getId().toString());
                    category2Vo.setName(level2Category.getName());
                    category2Vo.setCategory1Id(categoryEntity.getId().toString());

                    //查询二级分类下的三级分类
                    List<CategoryEntity> level3Categorys = getParentId(selectList,level2Category.getId());

                    //将当前二级分类下的三级分类封装到Vo
                    if (level3Categorys != null) {
                        List<Category3Vo> category3VoList = level3Categorys.stream().map(level3Category -> {
                            Category3Vo category3Vo = new Category3Vo();
                            category3Vo.setId(level3Category.getId().toString());
                            category3Vo.setName(level3Category.getName());
                            category3Vo.setCategory2Id(category2Vo.getId());

                            return category3Vo;
                        }).collect(Collectors.toList());
                        category2Vo.setCategory3VoList(category3VoList);
                    }

                    return category2Vo;
                }).collect(Collectors.toList());
                categoryVo.setCategory2VoList(category2VoList);
            }

            return categoryVo;

        }).collect(Collectors.toList());

        //3.查询的数据放入缓存中,将对象转换为json传入
        redisTemplate.opsForValue().set("categoryJSON", JSON.toJSONString(CategoryVoList),1, TimeUnit.DAYS);

        return CategoryVoList;
    }

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.18.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xd.cubemall</groupId>
    <artifactId>cubemall-product</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cubemall-product</name>
    <description>cubemall-product</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>
    <dependencies>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>



        <!--当修改页面后不需要再重启项目-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <!--引入common公共模块-->
        <dependency>
            <groupId>com.xd.cubemall</groupId>
            <artifactId>cubemall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>


        <!--添加模板技术渲染页面-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>



        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>






        <!--阿里云OSS-->
<!--        <dependency>-->
<!--            <groupId>com.aliyun.oss</groupId>-->
<!--            <artifactId>aliyun-sdk-oss</artifactId>-->
<!--            <version>3.17.4</version>-->
<!--        </dependency>-->


    </dependencies>
    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>



            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


相关文章:

  • buu-[OGeek2019]babyrop-好久不见41
  • C++ 设计模式-状态模式
  • 在s32ds for platform平台debug编译能正常编译,但是切换到release编译时报错
  • DeepSeek vs ChatGPT:AI 领域的华山论剑,谁主沉浮?
  • Uniapp判断设备是安卓还是 iOS,并调用不同的方法
  • 了解大数据
  • 虚拟机的创建及配置
  • Lineageos 22.1(Android 15)Launcer简单调整初始化配置
  • Qt学习(六) 软件启动界面 ,注册表使用 ,QT绘图, 视图和窗口绘图,Graphics View绘图框架:简易CAD
  • 数据库索引:缺点与类型全解析
  • CSS 布局技术深度解析:从传统到现代的核心布局方案
  • Arm64架构CentOS7服务器搭建Fabric环境
  • RPC:分布式系统的通信桥梁
  • 毕业项目推荐:基于yolov8/yolov5/yolo11的番茄成熟度检测识别系统(python+卷积神经网络)
  • 华为S系列交换机安全加固解决方案
  • Secured Finance携手Axelar及Squid提升流动性,迎接USDFC主网
  • 宇树科技13家核心零部件供应商梳理!
  • chmod命令修改rwxr-x---只读权限为rwxr-xr-x
  • C语言学习【1】C语言关于寄存器的封装
  • 数字化营销时代,我们需要有哪些思维?
  • 一周文化讲座|“我的生命不过是温柔的疯狂”
  • 清雪车司机未拉手刹下车导致溜车被撞亡,事故调查报告发布
  • “AD365特应性皮炎疾病教育项目”启动,助力提升认知与规范诊疗
  • 特朗普促卡塔尔说服伊朗放弃核计划,伊朗总统:你来吓唬我们?
  • 经济日报评外卖平台被约谈:行业竞争不能背离服务本质
  • 为何选择上海?两家外企提到营商环境、人才资源……