秒殺系統中的頁面優化

秒殺系統中,併發的瓶頸在數據庫,如何有效的減少對數據庫的訪問呢?最有效的方法就是加緩存,頁面靜態化、前後端分離、


1.頁面緩存

什麼是頁面緩存呢,就是我們在訪問頁面時,不是直接讓系統幫我們渲染頁面,而是去緩存中去取,如果找到了就直接返回給客戶端,如果沒有我們就手動渲染模板,返回給客戶端的同時,將結果緩存到如redis之類的緩存中,以便下次使用。這裏我們使用Redis來緩存。

以前,我們直接將動態數據存入model中,然後返回HTML頁面,通過SpringMVC來幫我們渲染

@RequestMapping(value="/to_list")
public String list( Model model,User user) {
    model.addAttribute("user", user);
    List<GoodsVo> goodsList = goodsService.listGoodsVo();
    model.addAttribute("goodsList", goodsList);
    return "goods_list";
}

緩存就是,我們直接返回HTML的源代碼,將HTML源代碼存在redis中,通過手動渲染來返回頁面。 (這裏的模板語言使用的是Thymeleaf)

@RequestMapping(value="/to_list", produces="text/html")
@ResponseBody
public String list(HttpServletRequest request, HttpServletResponse response, Model model,MiaoshaUser user) {
    model.addAttribute("user", user);
    List<GoodsVo> goodsList = goodsService.listGoodsVo();
    model.addAttribute("goodsList", goodsList);

    //1.取緩存,看緩存中是否存在以有的緩存
    String html = redisService.get(GoodsKey.getGoodsList, "", String.class);
    if(!StringUtils.isEmpty(html)) {
        return html;
    }

    //2.如果是空的,我們就手動渲染
    //通過SpringWebContext取出動態數據
    SpringWebContext ctx = new SpringWebContext(request,response,
                request.getServletContext(),request.getLocale(), model.asMap(), applicationContext );
    //手動用thymeleaf的模板引擎來渲染
    html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);
    //存入redis中
    if(!StringUtils.isEmpty(html)) {
        redisService.set(GoodsKey.getGoodsList, "", html);
    }

    return html;
}

但是你需要控制好緩存的有效時間,來保證頁面的及時性。我這裏設置的是60秒,對於大多數人來說,看到的頁面是60秒之前的並無大礙。也可以設置更短的時間來保證更高的及時性。


2.對象緩存

對象緩存是更細粒度的緩存。

我們還是拿使用緩存之前和使用緩存之後的兩個代碼塊來進行比較,下面是一個普通的通過userId從數據庫中取用戶。

public User getById(long id) {
    return userDao.getById(id);
}

爲了減少對數據庫的讀寫,我們可以加一個緩存,先查看緩存中是否存在user信息,沒有再去數據庫中讀取。

public User getById(long id) {
    //1.取緩存 現在redis中看是否存在該user 沒有的話就去數據庫中取
    MiaoshaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoshaUser.class);
    if(user != null) {
        return user;
    }

    //2.取數據庫  從數據庫中取出後,記得要加到緩存中去
    user = miaoshaUserDao.getById(id);
    if(user != null) {
        redisService.set(MiaoshaUserKey.getById, ""+id, user);
    }
        return user;
}

如果我們需要修改用戶信息的話,也要修改緩存中對應的用戶信息。

public boolean updatePassword(String token, long id, String formPass) {
    //取user
    User user = getById(id);
    if(user == null) {
        throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
    }
    //更新數據庫
    User toBeUpdate = new User();
    toBeUpdate.setId(id);
    toBeUpdate.setPassword(MD5Util.formPassToDBPass(formPass, user.getSalt()));
    userDao.updateUser(toBeUpdate);
    //處理緩存
    redisService.delete(UserKey.getById, ""+id);
    user.setPassword(toBeUpdate.getPassword());
    redisService.set(UserKey.token, token, user);
    return true;
}

將頁面和對象加了緩存之後,QPS從1267翻倍到 2884. 可見網站的性能翻了一倍,就因爲減少了對MySQL的訪問。


3.頁面靜態化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章