1. 程式人生 > >秒殺系統個人總結

秒殺系統個人總結

       對於高併發的專案,處理原則是儘量在上游處理,優先順序:客戶端-》後端記憶體-》redis-》資料庫;如果能在客戶端處理的,儘量不交給tomcat,能在tomcat處理的,儘量不要交給redis,畢竟tomcat-redis也存在網路互動,能在redis處理的,儘量不交給資料庫,一般高併發的瓶頸都是在資料庫。

      另外可以使用nignx做負載均衡,橫向擴充套件處理伺服器,這時session一般就要儲存在redis,這個也是分散式session;可以使用rabbitMQ作為訂單的的處理,rabbitMQ是分散式訊息佇列系統,需要安裝,個人感覺什麼分散式開源系統,原理都是統一處理多個來源資訊,支援叢集;

     在高併發環境下,可以限制使用者某時間段內的訪問次數,加驗證碼等手段減輕伺服器壓力;另外在高併發下也很容易出現數據錯誤的情況,例如這裡的多個使用者同時獲得剩餘商品都是1,然後就出現訂單多於總商品的情況,對於這種情況,可以:1,在資料庫表中合適的新增唯一值索引,2,利用rabbitMQ來延遲處理訂單,rabbitMQ是通過佇列的處理訊息,成功進入佇列的訂單給使用者返回排隊中的提示資訊,後面使用者方面可以通過輪詢的方式去查詢資料庫,如果資料庫存在該使用者的訂單資訊,即提示秒殺成功,如果資料庫的商品為0且訂單表不存在該使用者資訊,提示秒殺失敗,否則提示排隊中

1、頁面靜態化,頁面快取:

將頁面的寫成html,所有的資料都通過js非同步獲取,並且在頁面中加入快取功能,設定快取時間,springboot提供快取統一設定:

#static
spring.resources.add-mappings=true
spring.resources.cache-period= 3600
spring.resources.chain.cache=true
spring.resources.chain.enabled=true
spring.resources.chain.gzipped=true
spring.resources.chain.html-application-cache=true
spring.resources.static-locations=classpath:/static/

2、nignx負載均衡

  upstream server_pool_miaosha{
        server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=1;
    }
    server {
        listen       81;
        server_name  localhost;
   
        location / {
   proxy_pass http://server_pool_miaosha;

        }

3、分散式session 

,隨機生成一個token作為key,當前使用者user作為value儲存在redis中,並且將該token儲存在客戶端的cookie中,對於客戶端每次請求都會自動的將cookie資訊傳遞到伺服器,這時我們就可以通過CooKi_NAME-TOKEN獲取token,進而去redis獲取使用者資訊

redisService.set(MiaoshaUserKey.token, token, user);
Cookie cookie = new Cookie(COOKI_NAME_TOKEN, token);
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
    HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
    if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
        return null;
}
    String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
    return userService.getByToken(response, token);
}
private String getCookieValue(HttpServletRequest request, String cookiName) {
    Cookie[]  cookies = request.getCookies();
    if(cookies == null || cookies.length <=0){
        return null;
}
    for(Cookie cookie : cookies) {
        if(cookie.getName().equals(cookiName)) {
            return cookie.getValue();
}
    }
    return null;
}
4、隱藏秒殺地址

主要是通過客戶端在呼叫秒殺介面前要先到伺服器獲取一個隨機數,這個隨機數會儲存在redis中,然後在訪問地址中帶上這個隨機數

@RequestMapping(value="/{path}/do_miaosha", method= RequestMethod.POST)
@ResponseBody
public Result<Integer> miaosha(Model model, MiaoshaUser user,
@RequestParam("goodsId")long goodsId,
@PathVariable("path") String path) {

客戶端呼叫秒殺介面前:

$.ajax({
    url:"/miaosha/path",
type:"GET",
data:{
        goodsId:goodsId,
verifyCode:$("#verifyCode").val()
    },
success:function(data){
        if(data.code == 0){
            var path = data.data;
console.info("path:"+path);
doMiaosha(path);
}else{
            layer.msg(data.msg);
}
    },

客戶端呼叫秒殺介面:

$.ajax({
   url:"/miaosha/"+path+"/do_miaosha",
type:"POST",
data:{
      goodsId:$("#goodsId").val(),
},
success:function(data){
      if(data.code == 0){
               getMiaoshaResult($("#goodsId").val());
//window.location.href="/order_detail.htm?orderId="+data.data.id;
}else{
         layer.msg(data.msg);
}
   },

這個即能達到隱藏介面的功能

5、介面限流:


public class AccessInterceptor  extends HandlerInterceptorAdapter{
   
   @Autowired
MiaoshaUserService userService;
@Autowired
RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {
      if(handler instanceof HandlerMethod) {
         MiaoshaUser user = getUser(request, response);
UserContext.setUser(user);
HandlerMethod hm = (HandlerMethod)handler;
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
         if(accessLimit == null) {
            return true;
}
         int seconds = accessLimit.seconds();
         int maxCount = accessLimit.maxCount();
         boolean needLogin = accessLimit.needLogin();
String key = request.getRequestURI();

通過自定義註解,新增攔截器,redis記錄通過設定超時時間來限制該使用者的某時間段內的訪問次數

6、jmeter工具壓測

一個完整的jmeter壓測包括執行緒組,HTTP請求預設值,HTTP請求,CSV Data Set Config ,聚合報告