2. 秒杀-页面优化

1.页面缓存

想象一下秒杀的场景,僧多粥少,在秒杀将要开始的半分钟内,用户可能会不断刷新秒杀页面,此时对于页面访问的流量将达到顶峰。

解决方案

  1. 服务端缓存页面:
    在服务端手动渲染商品详情页面,直接返回html给前端
    将页面加入redis缓存,设置合适的,较短的有效期,比如60s
    每次请求都先从redis中取,取不到再渲染并返回
  2. 客户端缓存页面:
    同时可以设置浏览器缓存该页面60s,这样在此期间浏览器、服务器就没有数据交互了
@GetMapping(value="/goods2",produces="text/html")
@ResponseBody
public String findAllGoods2(Model model,HttpServletRequest request, HttpServletResponse response){
    //TODO 此处想设置浏览器缓存该页面60s,但是好像不管用啊
    response.setHeader("Cache-Control", "max-age:60");
    //先从缓存中取,没有再渲染
    String html = redisTemplate.opsForValue().get("goods");
    if(!StringUtils.isEmpty(html)) {
        return html;
    }
    
    List goods = goodsService.findAllGoods();
    model.addAttribute("goods",goods);
    //设置秒杀开始时间 为了使用缓存,当前时间使用客户端自己的时间
    model.addAttribute("targetTime",Constant.BARGAIN_DASH_START_TIME);
    
    //手动渲染
    WebContext ctx = new WebContext(request,response,
            request.getServletContext(),request.getLocale(), model.asMap());
    html = thymeleafViewResolver.getTemplateEngine().process("goods", ctx);
    
    //将结果加入redis,设置有效期60s
    if(!StringUtils.isEmpty(html)) {
        redisTemplate.opsForValue().set("goods", html, 60, TimeUnit.SECONDS);
    }
    return html;
}

由于商品页面比较固定,客户端对于页面实时更新要求不会很高,所以可以加入redis缓存起来。

由于redis缓存了页面,所以页面的倒计时效果只能取客户端的时间作为当前时间了。在真正秒杀的时候,服务端会对秒杀是否开始了做一次判断。其实,即使采用服务端时间做当前时间,倒计时也不可能完全准确,最好还是后端再做判断,所以这里直接采用客户端的时间做当前时间,也是合适的。

我想在服务端指定客户端缓存该页面60s,但是实际测试好像没效果,仍然会每次都发get请求,可能是哪里没有设置对吧。如果可以在浏览器缓存,将会更进一步提高性能。

这里前端页面倒计时效果,使用的是tictac,是从github上搜索来的,这种小组件,直接上github上找,比百度要更快更好。
压力测试

2. 秒杀-页面优化_第1张图片
优化的商品列表

可以看到,该优化的效果还是极为明显的。

2.其他优化点

目前代码主要是从后端进行了优化,如果有专业前端支持,前后端共同协作,效果会更好。

  1. 这里thymeleaf的渲染毕竟还是在服务端完成的,如果有前端人员支持的话,可以考虑下最近流行的angular、veu,实现彻底的前后端分离。前端发起请求,后端将商品信息缓存到redis,前端渲染页面,缓存页面。将工作量分担给无数个客户端,减轻服务端压力。
  2. 静态资源压缩,js css html等进行压缩,降低流量消耗
  3. nginx静态资源缓存

附:所有代码在github上

你可能感兴趣的:(2. 秒杀-页面优化)