瘋狂漲知識!「高并發秒殺」微信搶紅包實戰案例幫你突破瓶頸

推薦閱讀:

  • 阿里二面涼經:設計模式+緩存+Spring+虛擬機+MySQL+中間件+并發等難題,全部迎刃而解
  • 阿里巴巴字節跳動那些大廠必問的HTTP該怎么學?我建議你看看這篇文章!
  • 螞蟻、字節、PDD社招面經Java崗(分布式+線程安全+MySQL+CAS)

前言

群里有小伙伴咨詢微信紅包的架構,對于我來說,顯然是不知道的,但是寫一個相對高并發的搶紅包案例還是完全可以的。

架構流程

架構設計

  • 老板發紅包,此時緩存初始化紅包個數,紅包金額(單位分),并異步入庫。

  • 搶紅包,判斷緩存剩余紅包金額,剩余金額大于零則搶到紅包,否則手慢了,紅包派完了

  • 拆紅包,根據?redPacketId?獲取分布式鎖,如果獲取到鎖,紅包個數減一,如果剩余紅包個數大于零搶紅包成功、否則失敗。成功則計算紅包金額,緩存總紅包金額減去搶到的紅包金額,異步入庫、異步到賬。

  • 若獲取分布式鎖失敗,使用?Redis的?decr命令對紅包個數加一。

數據庫設計

  • 紅包信息表
CREATE TABLE `red_racket` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',`red_packet_id` bigint(20) NOT NULL COMMENT '紅包唯一ID',`total_amount` int(11) NOT NULL COMMENT '紅包金額單位分',`total_packet` int(11) NOT NULL COMMENT '紅包個數',`type` int(11) NOT NULL COMMENT '紅包類型',`create_time` datetime DEFAULT NULL COMMENT '創建時間',`version` int(11) NOT NULL COMMENT '版本號',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='紅包信息表'
  • 搶紅包記錄表
CREATE TABLE `red_packet_record` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',`amount` int(11) NOT NULL COMMENT '搶到紅包的金額',`red_packet_id` bigint(20) NOT NULL COMMENT '紅包ID',`uid` int(11) NOT NULL COMMENT '搶到紅包用戶的用戶標識',`create_time` datetime DEFAULT NULL COMMENT '創建時間',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='搶紅包記錄表'

代碼案例

老板發了10個紅包一共200人民幣,100個人同時搶紅包,偽代碼分別為拆紅包和搶紅包相關業務邏輯。模擬搶紅包偽代碼:

   /*** 搶紅包 拆紅包 搶到不一定能拆到* @param redPacketId* @return*/@ApiOperation(value="搶紅包二",nickname="爪哇筆記")@PostMapping("/startTwo")public Result startTwo(long redPacketId){int skillNum = 100;final CountDownLatch latch = new CountDownLatch(skillNum);//N個搶紅包/*** 初始化紅包數據,搶紅包攔截*/redisUtil.cacheValue(redPacketId+"-num",10);/*** 初始化紅包金額,單位為分*/redisUtil.cacheValue(redPacketId+"-money",20000);/*** 模擬100個用戶搶10個紅包*/for(int i=1;i<=skillNum;i++){int userId = i;Runnable task = () -> {/*** 搶紅包 判斷剩余金額*/Integer money = (Integer) redisUtil.getValue(redPacketId+"-money");if(money>0){/*** 雖然能搶到 但是不一定能拆到* 類似于微信的 點擊紅包顯示搶的按鈕*/Result result = redPacketService.startTwoSeckil(redPacketId,userId);if(result.get("code").toString().equals("500")){LOGGER.info("用戶{}手慢了,紅包派完了",userId);}else{Double amount = DoubleUtil.divide(Double.parseDouble(result.get("msg").toString()), (double) 100);LOGGER.info("用戶{}搶紅包成功,金額:{}", userId,amount);}}else{/*** 直接顯示手慢了,紅包派完了*///LOGGER.info("用戶{}手慢了,紅包派完了",userId);}latch.countDown();};executor.execute(task);}try {latch.await();Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());LOGGER.info("剩余金額:{}",restMoney);} catch (InterruptedException e) {e.printStackTrace();}return Result.ok();}

業務層拆紅包:

    @Override@Transactionalpublic Result startTwoSeckil(long redPacketId, int userId) {Integer money = 0;boolean res=false;try {/*** 獲取鎖 保證紅包數量和計算紅白金額的原子性操作*/res = RedissLockUtil.tryLock(redPacketId+"", TimeUnit.SECONDS, 3, 10);if(res){long restPeople = redisUtil.decr(redPacketId+"-num",1);if(restPeople>0){/*** 如果是最后一人*/if(restPeople==1){money = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());}else{Integer restMoney = Integer.parseInt(redisUtil.getValue(redPacketId+"-money").toString());Random random = new Random();//隨機范圍:[1,剩余人均金額的兩倍]money = random.nextInt((int) (restMoney / (restPeople+1) * 2 - 1)) + 1;}redisUtil.decr(redPacketId+"-money",money);/*** 異步入庫*/RedPacketRecord record = new RedPacketRecord();record.setMoney(money);record.setRedPacketId(redPacketId);record.setUid(userId);record.setCreateTime(new Timestamp(System.currentTimeMillis()));saveRecord(record);/*** 異步入賬*/}else{return Result.error("手慢了,紅包派完了");}}else{/*** 獲取鎖失敗相當于搶紅包失敗,紅包個數加一*/redisUtil.incr(redPacketId+"-num",1);}} catch (Exception e) {e.printStackTrace();}finally {if(res){//釋放鎖RedissLockUtil.unlock(redPacketId+"");}}return Result.ok(money);}

演示

在?Application中有接口演示說明,你可以在搶紅包?Red Packet Controller接口中輸入任何參數進行測試,也可以配合數據庫稍加修改即可作為生產環境的搶紅包功能模塊。

源碼

最后

如果覺得本文對你有幫助的話,不妨給我點個贊,關注一下吧!

資料免費領取方式:點擊這里

esult.ok(money);

}
## **演示**在?`Application`中有接口演示說明,你可以在搶紅包?`Red Packet Controller`接口中輸入任何參數進行測試,也可以配合數據庫稍加修改即可作為生產環境的搶紅包功能模塊。## **源碼**### 最后**如果覺得本文對你有幫助的話,不妨給我點個贊,關注一下吧!****[資料免費領取方式:點擊這里](https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB)**[外鏈圖片轉存中...(img-qm6jDdfJ-1623502396052)]![](https://img-blog.csdnimg.cn/img_convert/6e6463247e74e06477dd5eb773261f4b.png)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386080.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386080.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386080.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2016面試——騰訊、螞蟻金服、蘑菇街

騰訊TST技術面&#xff1a; 先羅列一下問題吧: 編程語言編譯的過程 同樣的邏輯,golang的二進制代碼比C語言的二進制代碼長很多.試分析原因 項目 ,三個項目都有聊.因為現場面,可以用紙寫,所以描述的更清楚些 N * N的方格紙,里面有多少個正方形 兩個數組求交集 什么樣的…

Android開發;Activity-Hook你了解多少?一起來debug

享學課堂特邀作者&#xff1a;周周 轉載請聲明出處&#xff01; 前言 手把手講解系列文章&#xff0c;是我寫給各位看官&#xff0c;也是寫給我自己的。文章可能過分詳細&#xff0c;但是這是為了幫助到盡量多的人&#xff0c;畢竟工作5,6年&#xff0c;不能老吸血&#xff0c;…

牛客網筆記之JAVA運算符

計算機的最基本用途之一就是執行數學運算&#xff0c;作為一門計算機語言&#xff0c;Java也提供了一套豐富的運算符來操縱變量。我們可以把運算符分成以下幾組&#xff1a; 算術運算符 關系運算符 位運算符 邏輯運算符 賦值運算符 其他運算符 邏輯運算符結果 ~a是按位非&#…

Android架構師談:View-Pager-性能優化之-無限循環

作者&#xff1a;享學課堂Alvin老師 轉載請聲明出處&#xff01; ViewPager實現無限滑動 **方案一&#xff1a;**將viewpager上限設置成一個很大的數&#xff0c;第一個頁面設置到中間。然后滑動的時候&#xff0c;用當前的序號與viewpager頁面數取余得到目標頁面的序號&#…

你知道如何用面向對象思想寫好并發編程嗎?

在工作中&#xff0c;我發現很多人在設計之初都是直接按照單線程的思路來寫程序的&#xff0c;而忽略了本應該重視的并發問題&#xff1b;等上線后的某天&#xff0c;突然發現詭異的 Bug&#xff0c;再歷經千辛萬苦終于定位到問題所在&#xff0c;卻發現對于如何解決已經沒有了…

你知道怎么在生產環境下部署tomcat嗎?

享學課堂特邀作者&#xff1a;老顧 轉載請聲明出處&#xff01; 一、前言 小伙伴們在網上看到的很多文章&#xff0c;都是對tomcat的一些介紹&#xff0c;什么配置啊&#xff0c;怎么啟動。其實在生產環境中怎么部署&#xff0c;和網上介紹的有很大區別。這篇文章老顧就帶著大…

淺談HashMap

Java集合類的整體架構 比較重要的集合類圖如下&#xff1a; 有序否 允許元素重復否 Collection 否 是 List 是 是 Set AbstractSet 否 否 HashSet TreeSet 是&#xff08;用二叉樹排序&#xff09; Map AbstractMap 否 使用 key-value 來映射和存儲數據&#xff0c; Key 必須惟…

matlab實現一元線性回歸和多元線性回歸

在回歸分析中,如果有兩個或兩個以上的自變量,就稱為多元回歸。事實上,一種現象常常是與多個因素相聯系的,由多個自變量的最優組合共同來預測或估計因變量,比只用一個自變量進行預測或估計更有效,更符合實際。 在實際經濟問題中,一個變量往往受到多個變量的影響。例如,家…

互聯網寒冬!“996”為什么還沒實行?我還等著早點下班呢!

“喊了十多個月的‘996’&#xff0c;說要實行‘996’&#xff0c;上班上到現在&#xff0c;影子都沒看到&#xff0c;我還能早點下班嗎&#xff1f;” 我一個在廣州上班的朋友小李&#xff0c;在我去廣州出差期間&#xff0c;與他聊天的時候發出了這樣的牢騷&#xff0c;我剛…

matlab求解常微分方程組/傳染病模型并繪制SIR曲線

看了很多關于傳染病模型的matlab程序,大都是繪制出兩條曲線(I、S)的,本文最大的不同是繪出SIR三條曲線。 先給出SIR微分方程組 函數文件: run的程序:

互聯網寒冬!技術站最全MySQL數據庫實戰規范

享學課堂特邀作者&#xff1a;老顧 轉載請聲明出處&#xff01; 前言 我們小伙伴們經常使用到mysql數據庫&#xff0c;一般就這么一用&#xff0c;很少會考慮mysql里面的細節問題&#xff0c;如sql語句的規范&#xff0c;或索引有沒有起到相應的效果&#xff0c;今天老顧就給大…

SQL求一個表中非重復數據及其出現的次數

mysql中&#xff0c;我們可以用distinct求不重復的數據有多少&#xff0c;也可以用group by。 這里有個例子&#xff0c;如下表sheet1&#xff0c;共有5411條數據 查詢語句 共有3446條不重復數據&#xff0c;每條不重復數據出現的次數在第二列顯示&#xff1a;

什么是微服務擴展性和高可用-可擴展性、高可用性和性能

歡迎關注專欄&#xff1a;Java架構技術進階。里面有大量batj面試題集錦&#xff0c;還有各種技術分享&#xff0c;如有好文章也歡迎投稿哦。 Overview 可擴展性、高可用性和性能 術語可擴展性、高可用性、性能和關鍵任務對于不同的組織或組織內的不同部門來說可能意味著不同的…

SQL實現當前行等于前面兩行數據之和

sql實現類似斐波那契數列的功能&#xff0c;即當前數據等于前面兩個數據之和&#xff0c;詳看本文例子 原表&#xff1a; sql語句&#xff08;此處要熟悉JION ON的用法&#xff09; 結果

【大牛系列教學】靠著這份面試題跟答案

開篇閑扯 打工人&#xff0c;打工魂&#xff0c;我們生而人上人。當“資本主義”逐漸禁錮我們人&#xff08;大&#xff09;上&#xff08;韭&#xff09;人&#xff08;菜&#xff09;肉體的時候&#xff0c;那一刻我才明白那個日不落帝國資本主義收割機瑞民族之光幸瑞幸咖啡…

matlab實現二項分布

二項分布 1. 求n次獨立重復試驗中事件A恰好發生k次的概率P。 命令:pdf 或 binopdf 格式:pdf (‘bino’, k, n, p) 或 binopdf (k, n, p) 說明:該命令的功能是計算二項分布中事件A恰好發生k次的概率。pdf為通用函數,bino表示二項分布,binopdf為專用函數,n為試驗總次數,…

【工作感悟】成功入職阿里月薪45K

前言 苦苦尋覓找工作之間&#xff0c;殊不知今日之時乃我心之痛&#xff0c;難道是我不配擁有工作嘛。自面試后他所謂的等待都過去一段時日&#xff0c;可惜在下京東上的小金庫都要見低啦。每每想到不由心中一緊。正處為難之間&#xff0c;手機忽然來了個短信預約后續面試。 我…

Mysql優化技巧

索引優化&#xff0c;查詢優化&#xff0c;查詢緩存&#xff0c;服務器設置優化&#xff0c;操作系統和硬件優化&#xff0c;應用層面優化&#xff08;web服務器&#xff0c;緩存&#xff09;等等。這里的記錄的優化技巧更適用于開發人員&#xff0c;都是從網絡上收集和自己整理…

【工作經驗分享】不會真有人覺得mybatis很難學吧

什么是自旋鎖和互斥鎖&#xff1f; 由于CLH鎖是一種自旋鎖&#xff0c;那么我們先來看看自旋鎖是什么&#xff1f; 自旋鎖說白了也是一種互斥鎖&#xff0c;只不過沒有搶到鎖的線程會一直自旋等待鎖的釋放&#xff0c;處于busy-waiting的狀態&#xff0c;此時等待鎖的線程不會…

華為面試題

技術面試&#xff1a; java&#xff1a; java學了幾年&#xff0c;看過什么書&#xff0c;有沒有看過thinking in java這本書 java的公共父類是什么&#xff0c;object類中有什么方法 object中有個hashcode方法&#xff0c;這個方法是用來做什么的&#xff0c; equal 與 的區…