Redis页面优化

news2024/11/16 16:20:30

文章目录

    • 1.Redis页面缓存
        • 1.思路分析
        • 2.首先记录一下目前访问商品列表页的QPS
          • 1.线程组配置10000次请求
          • 2.请求配置
          • 3.开始压测
            • 1.压测第一次 平均QPS为612
            • 2.压测第二次 平均QPS为615
            • 3.压测第三次 平均QPS为617
        • 3.然后记录一下访问商品详情页的QPS
          • 1.线程组配置10000次请求
          • 2.请求配置
          • 3.开始压测
            • 1.压测第一次 平均QPS为633
            • 2.压测第二次 平均QPS为642
            • 3.压测第三次 平均QPS为641
        • 4.商品列表页Redis缓存优化
          • 1.GoodsController.java
          • 2.启动报错 Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource
          • 3.发现是produces写错了,将冒号换成分号
          • 4.重新启动测试
            • 1.登录后访问 http://localhost:9092/seckill/goods/toList
            • 2.此时如果在数据库中修改信息,在60s内是不会刷新的
        • 5.商品详情页Redis缓存优化
          • 1.GoodsController.java
          • 2.测试
            • 1.登录后访问详情页
            • 2.在Redis中也有了缓存
        • 6.压力测试
          • 1.清空Redis
          • 2.清空用户表
          • 3.启动应用,重新生成2000个用户
          • 4.对访问列表页进行压测
            • 1.发现平均QPS只有80,比直接走数据库还慢
            • 2.由于六台机器都开启了RDB和AOF的持久化策略,现在分别将其关闭,然后重启redis
            • 3.再次压测,还是80
            • 4.那么就可能是网络原因了,因为服务器都在北京,所以将服务部署到生产环境然后再进行压力测试
    • 2.生产环境的压力测试
        • 1.首先将GoodsController.java的从db查询商品列表打开
        • 2.部署上线
          • 1.激活环境为prod
          • 2.maven打包
          • 3.上传到服务器然后重新启动
        • 3.UserUtil.java 获取用户信息
          • 1.修改环境变量
          • 2.获取cookie
        • 4.准备压测
          • 1.http请求默认值
          • 2.http请求信息
          • 3.修改cookie的域
          • 4.开始压测5000次请求,QPS为55
        • 5.使用redis缓存页面来优化并重新部署
        • 6.再次压测,QPS为80,有所提升
        • 7.关于Redis缓存页面与DB的数据同步问题
    • 3.对象缓存问题解决
        • 1.问题分析
        • 2.具体实现
          • 1.UserService.java
          • 2.UserServiceImpl.java
          • 3.UserController.java
        • 3.测试
          • 1.登录一下,得到票据
          • 2.Redis中有该用户信息
          • 3.更新密码 http://localhost:9092/seckill/user/updatePassword?userTicket=4dfaea799a9b438ea96ef61f7da435e3&password=666666
          • 4.刷新Redis,用户信息被删除

1.Redis页面缓存

1.思路分析

image-20240510103830900

2.首先记录一下目前访问商品列表页的QPS
1.线程组配置10000次请求

image-20240510104150231

2.请求配置

image-20240510104243589

3.开始压测
1.压测第一次 平均QPS为612

image-20240510104745555

2.压测第二次 平均QPS为615

image-20240510104836407

3.压测第三次 平均QPS为617

image-20240510104913070

3.然后记录一下访问商品详情页的QPS
1.线程组配置10000次请求

image-20240510104150231

2.请求配置

image-20240510114304155

3.开始压测
1.压测第一次 平均QPS为633

image-20240510114342610

2.压测第二次 平均QPS为642

image-20240510114510495

3.压测第三次 平均QPS为641

image-20240510114551866

4.商品列表页Redis缓存优化
1.GoodsController.java
    @Resource
    GoodsService goodsService;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private ThymeleafViewResolver thymeleafViewResolver;

    // 进入到商品首页-使用redis优化
    @RequestMapping(value = "/toList", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String toList(Model model, User user, HttpServletRequest request, HttpServletResponse response) {
        // 判断是否有用户信息
        if (null == user) {
            return "login";
        }
        // 先从redis中获取页面,如果有则直接返回
        String html = (String) redisTemplate.opsForValue().get("goodsList");
        if (StringUtils.hasText(html)) {
            return html;
        }
        // 如果没有就从数据库中查询,然后存入redis中

        // ------------------------------db查询商品列表------------------------------
        // 查询商品列表
        model.addAttribute("goodsList", goodsService.findGoodsVo());
        // 将用户信息存入model中
        model.addAttribute("user", user);
        // ------------------------------db查询商品列表------------------------------

        // 渲染页面
        // 1.首先构建一个webContext对象,用来存放model
        WebContext context = new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());
        // 2.渲染页面
        html = thymeleafViewResolver.getTemplateEngine().process("goodsList", context);
        // 3.判断html是否为空,不为空则存入redis中,设置过期时间为60s
        if (StringUtils.hasText(html)) {
            redisTemplate.opsForValue().set("goodsList", html, 180, TimeUnit.SECONDS);
        }
        return html;
    }
2.启动报错 Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource

image-20240510112622807

3.发现是produces写错了,将冒号换成分号

image-20240510112644275

4.重新启动测试
1.登录后访问 http://localhost:9092/seckill/goods/toList

image-20240510113319062

2.此时如果在数据库中修改信息,在60s内是不会刷新的

image-20240510113453521

image-20240510113501947

5.商品详情页Redis缓存优化
1.GoodsController.java
    // 进入到商品详情页
    @RequestMapping(value = "/toDetail/{goodsId}", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String toDetail(Model model, User user, @PathVariable Long goodsId, HttpServletRequest request, HttpServletResponse response) {
        // 判断是否有用户信息
        if (null == user) {
            return "login";
        }
        // 先从redis中获取页面,如果有则直接返回
        String html = (String) redisTemplate.opsForValue().get("goodsDetail:" + goodsId);
        // 如果有则直接返回
        if (StringUtils.hasText(html)) {
            return html;
        }
        // 如果没有就从数据库中查询,然后存入redis中
        // ------------------------------db查询商品详情------------------------------
        // 查询商品详情
        GoodsVo goodsVoByGoodsId = goodsService.findGoodsVoByGoodsId(goodsId);
        model.addAttribute("goods", goodsVoByGoodsId);

        // secKillStatus:秒杀状态 0:未开始 1:进行中 2:已结束
        // remainSeconds:秒杀剩余时间 >0:未开始 0:进行中 -1:已结束
        // 获取该商品的秒杀开始时间和结束时间
        long startAt = goodsVoByGoodsId.getStartDate().getTime();
        long endAt = goodsVoByGoodsId.getEndDate().getTime();
        long now = System.currentTimeMillis();

        // 根据当前时间与秒杀开始时间和结束时间的比较,判断秒杀状态
        int secKillStatus = 0;
        int remainSeconds = 0;
        if (now < startAt) {
            // 秒杀未开始
            secKillStatus = 0;
            remainSeconds = (int) ((startAt - now) / 1000);
        } else if (now > endAt) {
            // 秒杀已结束
            secKillStatus = 2;
            remainSeconds = -1;
        } else {
            // 秒杀进行中
            secKillStatus = 1;
            remainSeconds = 0;
        }
        // 将秒杀状态和剩余时间存入model中,返回到前端
        model.addAttribute("secKillStatus", secKillStatus);
        model.addAttribute("remainSeconds", remainSeconds);
        // 将用户信息存入model中,返回到前端
        model.addAttribute("user", user);
        // ------------------------------db查询商品详情------------------------------

        // 渲染页面
        // 1.首先构建一个webContext对象,用来存放model
        WebContext context = new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());
        // 2.渲染页面
        html = thymeleafViewResolver.getTemplateEngine().process("goodsDetail", context);
        // 3.判断html是否为空,不为空则存入redis中,设置过期时间为60s
        if (StringUtils.hasText(html)) {
            redisTemplate.opsForValue().set("goodsDetail:" + goodsId, html, 180, TimeUnit.SECONDS);
        }
        return html;
    }
2.测试
1.登录后访问详情页

image-20240510115537167

2.在Redis中也有了缓存

image-20240510115506347

6.压力测试
1.清空Redis

image-20240510131337298

2.清空用户表

image-20240510131408927

3.启动应用,重新生成2000个用户

image-20240510131906293

4.对访问列表页进行压测
1.发现平均QPS只有80,比直接走数据库还慢

image-20240510133226209

2.由于六台机器都开启了RDB和AOF的持久化策略,现在分别将其关闭,然后重启redis

image-20240510134438566

3.再次压测,还是80

image-20240510135137575

4.那么就可能是网络原因了,因为服务器都在北京,所以将服务部署到生产环境然后再进行压力测试

2.生产环境的压力测试

1.首先将GoodsController.java的从db查询商品列表打开

image-20240510140806413

2.部署上线
1.激活环境为prod

image-20240510141002410

2.maven打包

image-20240510141329259

3.上传到服务器然后重新启动

image-20240510141219305

image-20240510141322995

3.UserUtil.java 获取用户信息
1.修改环境变量

image-20240510141454701

2.获取cookie

image-20240510141645300

4.准备压测
1.http请求默认值

image-20240510141746474

2.http请求信息

image-20240510141913477

3.修改cookie的域

image-20240510142730644

4.开始压测5000次请求,QPS为55

image-20240510144422400

5.使用redis缓存页面来优化并重新部署

image-20240510144638573

6.再次压测,QPS为80,有所提升

image-20240510145440390

7.关于Redis缓存页面与DB的数据同步问题

image-20240510150344168

3.对象缓存问题解决

1.问题分析

在校验用户是否登录时,会根据cookie在Redis中查询用户信息,但是如果在DB中的用户信息更改了,那么就会发生数据不一致的问题

2.具体实现
1.UserService.java
    /**
     * 更新密码
     * @param userTicket
     * @param password
     * @param request
     * @param response
     * @return
     */
    public RespBean updatePassword(String userTicket, String password, HttpServletRequest request, HttpServletResponse response);
2.UserServiceImpl.java
    @Override
    public RespBean updatePassword(String userTicket, String password, HttpServletRequest request, HttpServletResponse response) {
        // 根据ticket获取用户
        User user = getUserByCookie(userTicket, request, response);
        if (null == user) {
            throw new GlobalException(RespBeanEnum.MOBILE_NOT_EXIST);
        }
        // 更新密码
        user.setPassword(MD5Util.inputPassToDBPass(password, user.getSlat()));
        int result = userMapper.updateById(user);
        if (1 == result) {
            // 删除redis中的用户信息
            redisTemplate.delete("user:" + userTicket);
            return RespBean.success();
        }
        return RespBean.error(RespBeanEnum.PASSWORD_UPDATE_FAIL);
    }
3.UserController.java
    // 更新密码
    @RequestMapping("/updatePassword")
    @ResponseBody
    public RespBean updatePassword(String userTicket, String password, HttpServletRequest request, HttpServletResponse response) {
        return userService.updatePassword(userTicket, password, request, response);
    }
3.测试
1.登录一下,得到票据

image-20240510154410627

2.Redis中有该用户信息

image-20240510154635876

3.更新密码 http://localhost:9092/seckill/user/updatePassword?userTicket=4dfaea799a9b438ea96ef61f7da435e3&password=666666

image-20240510154823197

4.刷新Redis,用户信息被删除

image-20240510154850757

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SwiftUI 利用 Swizz 黑魔法为系统创建的默认对象插入新协议方法(五)

功能需求 在 SwiftUI 的开发中,我们往往需要借助底层 UIKit 的“上帝之手”来进一步实现额外的定制功能。比如,在可拖放(Dragable)SwiftUI 的实现中,会缺失拖放取消的回调方法让我们这些秃头码农们“欲哭无泪” 如上图所示,我们在拖放取消时将界面中的一切改变都恢复如初…

python怎么退出help

Python中查看帮助可以在命令提示行中输入“help()”即可。 如果想要退出帮助&#xff0c;有三种方法&#xff0c;具体如下&#xff1a; 1、直接按键盘上的“enter”键退出帮助。 2、按键盘上的“q”键退出帮助。 3、按键盘上的“CtrlZ”键退出帮助。

带DSP音效处理D类数字功放TAS5805M中文资料

国产替代D类数字功放中文资料访问下方链接 ACM8628 241W立体声182W单通道数字功放中文寄存器表 内置DSP多种音频处理效果ACM8628M-241W立体声或182W单通道数字功放 1 特性 具有增强处理能力和低功率损耗的 TAS5805M 23W、无电感器、数字输入、立体声、闭环 D 类音频放大器 …

AI网络爬虫:用GraphQL查询爬取动态网页数据

任务&#xff1a;爬取网站www.skillshare.com搜索结果页面数据&#xff1a; 查看网站的请求信息&#xff1a; 请求网址: https://www.skillshare.com/api/graphql 请求方法: POST 状态代码: 200 OK 远程地址: 127.0.0.1:10809 引荐来源网址政策: strict-origin-when-…

【微信小程序开发】小程序中的上滑加载更多,下拉刷新是如何实现的?

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

什么是泛洪攻击?DDos攻击也是泛洪攻击的一种?

在数字化时代的浪潮中&#xff0c;网络安全已成为一场没有硝烟的战争。其中&#xff0c;泛洪攻击作为一种常见的网络攻击手段&#xff0c;对个人用户、企业乃至国家网络安全构成了严重威胁。本文将对泛洪攻击进行深入剖析&#xff0c;包括其定义、原理、类型、影响以及应对策略…

计算机基础(5)——进制与进制转换

&#x1f497;计算机基础系列文章&#x1f497; &#x1f449;&#x1f340;计算机基础&#xff08;1&#xff09;——计算机的发展史&#x1f340;&#x1f449;&#x1f340;计算机基础&#xff08;2&#xff09;——冯诺依曼体系结构&#x1f340;&#x1f449;&#x1f34…

用增之Firebase

目录 简介 开发准备&#xff1a; 1、在Firebase平台创建项目 2、将项目关联到应用 3、项目配置 简介 前面讲了google ddl部分&#xff0c;本篇为Firebase的事件上报部分&#xff0c;包括在FireBase平台创建应用 &#xff0c; 如果有用到ddl…

element-plus日历组件el-calendar自定义内容,每天绑定不同的值

效果 代码 <template><el-calendar v-model"calendarDate"><template #date-cell"{ data }"><p :class"data.isSelected ? is-selected : ">{{ data.day.split("-").slice(1).join("-") }}{{ d…

使用Redis常遇到的问题

文章目录 概述缓存雪崩、穿透、击穿大key问题热Key问题缓存和数据库双写一致性问题缓存并发竞争Redis线上阻塞要如何排查Redis 常见的性能问题都有哪些Redis 如何做内存优化Redis数据倾斜 概述 在使用Redis时&#xff0c;有几个常见的问题可能会出现&#xff0c;包括但不限于以…

计算机网络ppt和课后题总结(上)

试在下列条件下比较电路交换和分组交换。要传送的报文共 x(bit)。从源点到终点共经过 k 段链路&#xff0c;每段链路的传播时延为 d(s)&#xff0c;数据率为 b(b/s)。在电路交换时电路的建立时间为 s(s)。在分组交换时分组长度为 p(bit)&#xff0c;且各结点的排队等待时间可忽…

进程同步的基本元素

目录 临界资源 临界区 信号量机制 整形信号量 记录型信号量 AND信号量 信号量集 信号量的应用 实现进程互斥 实现前驱关系 管程机制 总结 临界资源 I/O设备属于临界资源。著名的生产者-消费者问题就是关于临界资源的争夺产生的进程同步的问题。 生产者-消费者 描…

阅读 Spring(SpringBoot)源码的一些实用技巧

前言 我们在阅读Spring&#xff08;SpringBoot&#xff09;源码的时候&#xff0c;有可能会被一下前置知识点卡住&#xff0c;影响继续阅读的动力。根据我对Spring的理解&#xff0c;整理一些实用的技巧&#xff0c;减少大家的阅读障碍。如果有什么不正确的地方欢迎大家指正、…

辞职后,如何理性面对公司的挽留?我的职场选择之路

辞职后&#xff0c;面对公司的挽留&#xff0c;你会决定留下还是离开呢&#xff1f;这是一个让人犹豫不决的问题。 让我们来分析一下个人在职场中的价值和期望。每个人都有自己的职业规划和发展目标&#xff0c;这是非常正常的。在工作中&#xff0c;我们希望自己能够得到充分的…

React路由(React笔记之五)

本文是结合实践中和学习技术文章总结出来的笔记(个人使用),如有雷同纯属正常((✿◠‿◠)) 喜欢的话点个赞,谢谢! React路由介绍 现在前端的项目一般都是SPA单页面应用,不再是以前多个页面多套HTML代码项目了,应用内的跳转不需要刷新页面就能完成页面跳转靠的就是路由系统 R…

IPFS节点部署及连接java服务接口

文章目录 引言前言&#xff1a;IPFS网络部署1.下载安装文件2.安装及初始化3.测试上传文件 引入IPFS 依赖包初始化IPFS创建接口类以及实现类创建前端访问的控制类前端设计及验证 引言 该篇文章是记录使用IPFS存储文件与java的Springboot项目连接的过程&#xff0c;前端简单地用…

傲医医疗集成引擎 Rhapsody 在超融合信创平台表现如何?

作者&#xff1a;SmartX 商业团队 黄玉辉 随着越来越多的医疗用户基于超融合基础设施实现 IT 基础架构信创转型&#xff0c;超融合信创架构在医疗业务场景中的实际表现也得到更多关注。尤其是集成平台业务场景——作为三甲医院互联互通评级中不可缺少的核心业务系统&#xff0…

使用Ollama+OpenWebUI本地部署Gemma谷歌AI开放大模型完整指南

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月4日10点50分 &#x1f004;️文章质量&#xff1…

Spring Boot既打jar包又打war包如何做

你好&#xff0c;我是柳岸花开。 引言 在软件开发中&#xff0c;根据不同的部署需求&#xff0c;我们可能需要将应用打包成不同的格式。Spring Boot作为目前流行的Java应用开发框架&#xff0c;提供了一种简单的方式来打包应用。本文将介绍如何利用Maven Profiles在Spring Boot…

Photoshop版本选择及系统要求

1、ps2018cc/2020cc版本 适合新手&#xff0c;增加了很多智能化操作&#xff0c;非常方便好上手。 2020&#xff1a; 2、ps2015版本 cc2015版本不论是功能还是硬件上&#xff0c;都是不二选择&#xff0c;适合于配置较低的电脑&#xff0c;该有的基本功能它都有。 3、2021/2…