日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Java秒杀系统优化(高性能高并发)

發布時間:2023/12/15 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java秒杀系统优化(高性能高并发) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

源碼免費下載地址:關注微信公眾號“蝦米聊吧”,回復關鍵字“秒殺

主題:在大并發大流量的情況下如何提升吞吐量或者說QPS?

而秒殺活動恰恰就是屬于大并發的情形,因此下面簡單來談談大并發下秒殺方案的優化。

項目采用技術:SpringBoot + MyBatis + MySql + RabbitMq + Redis

RabbitMq安裝參考:https://blog.csdn.net/zwx19921215/article/details/103255834

?

文章首先說明優化思路方案和步驟,然后闡述代碼具體實現,最后采用JMeter進行簡單壓測。

?

  • 針對大并發的主體優化常見有如下幾種方式:

1.頁面緩存 + URL緩存 + 對象級緩存

2.頁面靜態化(瀏覽器緩存),前后端分離+ajax

3.靜態資源優化(js/css壓縮,減少流量),多個js/css組合,減少連接數

4.CDN優化

?

而作為一個程序猿我們都知道并發最大的瓶頸基本就是數據庫因此最好就是減少數據庫的訪問次數即加緩存。

?

  • 從訪問開始到后端返回整個緩存鏈可以是:

瀏覽器端緩存(頁面靜態化)--> CDN --> nginx緩存 --> 后端服務緩存(頁面緩存、對象級緩存等) --> 數據庫

?

而作為一名后端工程師的優化則主要是針對接口優化,這也是我們的重頭戲;

  • 接口優化大概通過如下步驟處理:

1.redis預減庫存減少 數據庫訪問?

2.內存標記減少redis訪問?

3.請求先入隊緩沖,異步下單 ,增強用戶體驗

?

  • 針對秒殺接口優化:

核心思路:減少數據庫訪問(數據庫瓶頸)

1.系統初始化,把商品庫存數量加載到redis

2.收到請求,redis預減庫存,庫存不足,直接返回,否則進入3

3.請求入隊,立即返回 排隊中

4.請求出隊,生成訂單,減少庫存

5.客戶端輪詢,是否秒殺成功

?

  • 針對安全方面優化:

1.秒殺接口地址隱藏

2.數學公式驗證碼

3.接口限流防刷

?

  • 秒殺接口地址隱藏:

思路:秒殺開始之前,先去請求接口獲取秒殺地址?

1.接口改造 ,帶上PathVariable參數

2.添加生成地址的接口

3.秒殺收到請求,先驗證PathVariable

?

  • 數學公式驗證碼:

目的:防機器人,分散請求

思路:點擊秒殺之前,先輸入驗證碼,分散用戶的請求

1.添加生成驗證碼接口

2.在獲取秒殺路徑的時候,驗證驗證碼

?

  • 接口防刷限流:

1.利用redis緩存:比如限制用戶1min中內只允許訪問多少次

2.可以利用攔截器減少對業務代碼的入侵

?

  • 解決超賣問題:

1.數據庫加唯一索引:防止用戶重復購買?

2.更新庫存sql增加庫存數量判斷:防止庫存變成負數?

(update table set count=count-1 where count>0)?

?

  • 秒殺優化后的主體詳細流程大致可以分為如下步驟:
  • 程序啟動后將秒殺庫存寫入redis,設置內存標記商品是否已秒殺完
  • 加入驗證碼
  • 秒殺前首先獲取秒殺路徑
  • 開始秒殺:
  • ?a.判斷用戶登錄信息是否異常b.驗證秒殺路徑c.獲取秒殺商品內存標記并判斷是否已秒殺完d.redis獲取用戶訂單,判斷該用戶是否是重復秒殺e.如果是正常秒殺,對于未秒殺完的商品進行redis減庫存操作f.如果redis庫存已<0,標記內存商品已秒殺完g.秒殺正常則加入隊列,異步處理訂單入庫,返回排隊中

    5.前端輪詢訂單結果(是否秒殺成功)

    ?

    • 實現效果如下:

    用戶登錄界面

    描述商品列表頁:

    秒殺商品詳情頁(增加驗證碼):

    增加訪問限制(防刷限流):

    重復秒殺處理:

    換一個秒殺商品重新秒殺:

    秒殺成功進入訂單詳情頁:

    數據庫查看庫存正常減1

    項目結構如下:

    秒殺接口部分核心代碼如下:

    獲取驗證碼:

    @AccessLimit(seconds = 5, maxCount = 5, needLogin = true)@RequestMapping(value = "/path", method = RequestMethod.GET)@ResponseBodypublic Result<String> getMiaoshaPath(HttpServletRequest request, MiaoshaUser user,@RequestParam("goodsId") long goodsId,@RequestParam(value = "verifyCode", defaultValue = "0") int verifyCode) {if (user == null) {return Result.error(CodeMsg.SESSION_ERROR);}boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);if (!check) {return Result.error(CodeMsg.REQUEST_ILLEGAL);}String path = miaoshaService.createMiaoshaPath(user, goodsId);return Result.success(path);}

    獲取秒殺路徑:?

    @RequestMapping(value = "/verifyCode", method = RequestMethod.GET)@ResponseBodypublic Result<String> getMiaoshaVerifyCod(HttpServletResponse response, MiaoshaUser user,@RequestParam("goodsId") long goodsId) {if (user == null) {return Result.error(CodeMsg.SESSION_ERROR);}try {BufferedImage image = miaoshaService.createVerifyCode(user, goodsId);OutputStream out = response.getOutputStream();ImageIO.write(image, "JPEG", out);out.flush();out.close();return null;} catch (Exception e) {e.printStackTrace();return Result.error(CodeMsg.MIAOSHA_FAIL);}}

    執行秒殺:

    @RequestMapping(value = "/{path}/do_miaosha", method = RequestMethod.POST)@ResponseBodypublic Result<Integer> miaosha(Model model, MiaoshaUser user,@RequestParam("goodsId") long goodsId,@PathVariable("path") String path) {model.addAttribute("user", user);if (user == null) {return Result.error(CodeMsg.SESSION_ERROR);}//驗證pathboolean check = miaoshaService.checkPath(user, goodsId, path);if (!check) {return Result.error(CodeMsg.REQUEST_ILLEGAL);}//內存標記,減少redis訪問if (localOverMap.size() > 0) {boolean over = localOverMap.get(goodsId);if (over) {return Result.error(CodeMsg.MIAO_SHA_OVER);}}//判斷是否已經秒殺到了MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);if (order != null) {return Result.error(CodeMsg.REPEATE_MIAOSHA);}//預減庫存long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);//10if (stock < 0) {localOverMap.put(goodsId, true);return Result.error(CodeMsg.MIAO_SHA_OVER);}//mq入隊MiaoshaMessage mm = new MiaoshaMessage();mm.setUser(user);mm.setGoodsId(goodsId);sender.sendMiaoshaMessage(mm);return Result.success(0);//排隊中
    • 采用JMeter做個簡單的壓力測試

    JMeter簡單使用參考:https://blog.csdn.net/zwx19921215/article/details/103261289

    操作系統:centos 虛擬機雙核

    測試參數:生成5000個用戶(token信息),設置5000個線程數循環10次,即運行50000次,然后查看聚合報告中的吞吐量。

    虛擬機測試結果吞吐量為2000左右,取決于機器配置

    注:該接口是在未加入驗證碼動態獲取秒殺路徑的前提下測試的

    ?

    項目完整代碼下載地址:http://zyshare.cn/resource/detail/22

    源碼免費下載地址:關注微信公眾號“蝦米聊吧”,回復關鍵字“秒殺

    關注微信公眾號“蝦米聊吧”,后續持續放送“技術架構和資料”干貨!!!

    ? ?一個熱衷于分享技術和生活的程序猿,讓我們一起交流吧~??????

    ? ? ? ? ? ? ???? ? ?

    ? ? ? ? ? ? ? ? ? 微信掃描二維碼,關注我的公眾號

    總結

    以上是生活随笔為你收集整理的Java秒杀系统优化(高性能高并发)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。