为什么要使用页面缓存技术?

系统都是逐渐演进的,一个系统在运行中必须是根据场景逐渐地提高优化性能。高并发就是对资源的节约的考验,这种考验除了更换优秀和先进的技术,优化架构,还在于从小处出发,对尽可能节约的资源进行节约。而在一个系统的数据访问中,系统的瓶颈往往是来自于数据库,因此我们要尽可能减少对数据库的访问!在不影响用户体验的情况下,对于一些静态或者变化不大的页面,我们使用缓存来减少对数据库的访问!

缓存技术的原理

在一个请求中,逻辑越复杂,调用,依赖,访问数据库的越多,耗时也就越长,响应时间也就越长,性能也就越差!因此降低逻辑复杂度,减低耦合,提高内聚,减少数据库访问,将频繁用到的变化不大的数据给缓存起来也就成为了提高性能的主要核心。

缓存雪崩-数据穿透问题

缓存穿透

缓存雪崩

缓存击穿

下面是一个我在开发秒杀项目的时候,一些优化的地方,例如在进入商品列表的时候,我是直接采用Thymeleaf模板动态渲染了,这样的处理效率不高,不适合高并发,所以采用页面缓存进行优化,将页面的源代码缓存到Redis中,这样可以减少对数据库的访问,从而减少对数据库访问的耗时。

如下代码是进入商品列表的源代码,只是简单的将数据放进model里,然后返回页面,但是每次加载的时候,都会进行一次数据库访问,如果在是高并发的情况下,会加剧数据库的访问,造成加载时间变慢,甚至导致数据库宕机等情况发生,所以我们需要采用一些缓存技术进行优化。

@RequestMapping("to_list")
public String toList(Model model,MiaoshaUser user){
    if(user == null)
        return "login";
    model.addAttribute("user",user);
    List<GoodsVo> goodsVoList = goodsService.getGoodsVoList();
    model.addAttribute("goodsList",goodsVoList);
    return "goods_list";
}

如下代码是经过了页面缓存优化后的代码,每次进入方法前,先取缓存,看看缓存中是否含有之前缓存的html源码,如果有,则返回。如果没有,则进行数据库访问等操作,然后用thymeleafViewResolver进行手动渲染,将渲染后的结果放进html中,然后放进缓存,再返回给浏览器解析。
注意:缓存的有效时间不宜过长,也不宜过短,本文中的优化,我是设置了60s的缓存有效时间,用户看到60s前的页面,也还是正常的。

    @RequestMapping(value ="/to_list",produces = "text/html")
    @ResponseBody
    public String toList(HttpServletRequest request,HttpServletResponse response, Model model, MiaoshaUser user){
        model.addAttribute("user",user);

        //取缓存
        String html = redisService.get(GoodsKey.getGoodsList,"",String.class);
        if (!StringUtils.isEmpty(html)){
            return html;
        }
        //查询商品列表
        List<GoodsVo> goodsList = goodsService.listGoodsVo();
        model.addAttribute("goodsList",goodsList);

        IWebContext ctx = new WebContext(request,response,
                request.getServletContext(),request.getLocale(),model.asMap());
        //手动渲染
        html = thymeleafViewResolver.getTemplateEngine().process("goods_list",ctx);
        if (!StringUtils.isEmpty(html)){
            redisService.set(GoodsKey.getGoodsList,"",html);
        }
        return html;
    }

上面的代码有一处地方需要注意一下,有些同学用的WebContextSpringWebContext由于我采用的是thymeleaf.spring5的版本,大部分API被移到了IWebContext下面。可能会有些小差别,在此说明一下。

07-26 22:12