高並發10-微信搶紅包實現


- 如果上司給一個任務,讓我們在實現微信搶紅包這個功能,我們該怎么做?

 

 

 

  * 業務思考,實現方式千百種,不追求方法復制,只追求推導過程的思考總結

 

 

  * 功能點探索

    * 新建紅包:在DB、cache各新增一條記錄

    * 搶紅包:請求訪問cache,剩余紅包個數大於0則可拆開紅包

      * key:1,value:20 string decr原子減,每次減1 , 而decreby減指定數量N

    * 拆紅包: 20個紅包里面有500塊,key:1,value:50000(以分為單位) decreby 548,decreby 1055 ,decreby 2329

    * 請求訪問cache,剩余紅包個數大於0則繼續,同時獲取可搶紅包數與金額
    * 計算金額(從1分到剩余平均值2倍之間隨機數,如果不是最后一個紅包,剩余金額預留最少1分給cas更新失敗,最后一位拿紅包的人)
    * cas更新數據庫(更新紅包計數表記錄【剩余紅包個數、剩余紅包金額】、插入領取記錄)

    * 查看紅包記錄:用戶進來直接查DB即可

 

 

 

 

 

1微信紅包數據庫表設計

- 紅包流水表

CREATE TABLE `red_packet_info` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`red_packet_id` bigint(11) NOT NULL DEFAULT 0 COMMENT '紅包id,采用timestamp+5位隨機數', 
`total_amount` int(11) NOT NULL DEFAULT 0 COMMENT '紅包總金額,單位分',
`total_packet` int(11) NOT NULL DEFAULT 0 COMMENT '紅包總個數',
`remaining_amount` int(11) NOT NULL DEFAULT 0 COMMENT '剩余紅包金額,單位分',
`remaining_packet` int(11) NOT NULL DEFAULT 0 COMMENT '剩余紅包個數',
`uid` int(20) NOT NULL DEFAULT 0 COMMENT '新建紅包用戶的用戶標識',
`create_time` timestamp COMMENT '創建時間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間', 
PRIMARY KEY (`id`) )
ENGINE
=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='紅包信息表,新建一個紅包插入一條記錄';

- 紅包記錄表

CREATE TABLE `red_packet_record` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`amount` int(11) NOT NULL DEFAULT '0' COMMENT '搶到紅包的金額',
`nick_name` varchar(32) NOT NULL DEFAULT '0' COMMENT '搶到紅包的用戶的用戶名',
`img_url` varchar(255) NOT NULL DEFAULT '0' COMMENT '搶到紅包的用戶的頭像',
`uid` int(20) NOT NULL DEFAULT '0' COMMENT '搶到紅包用戶的用戶標識',
`red_packet_id` bigint(11) NOT NULL DEFAULT '0' COMMENT '紅包id,采用timestamp+5位隨機數', 
`create_time` timestamp COMMENT '創建時間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間', 
PRIMARY KEY (`id`) )
ENGINE
=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='搶紅包記錄表,搶一個紅包插入一條記錄';

- 將庫表導入數據庫

- 通過mybatis generator生成代碼

 2發紅包接口實現

- 發紅包功能接口開發

  * 新增一條紅包記錄
  * 往mysql里面添加一條紅包記錄
  * 往redis里面添加一條紅包數量記錄 decr
  * 往redis里面添加一條紅包金額記錄 decreby

- 搶紅包功能接口開發

  * 搶紅包功能屬於原子減操作
  * 當大小小於0時原子減失敗

- 當紅包個數為0時后面進來的用戶全部搶紅包失敗,並不會進入拆紅包環節

- 搶紅包功能擴展設計

  * 將紅包ID的請求放入請求隊列中,如果發現超過紅包的個數,直接返回
  * 類推出token令牌和秒殺設計原理

- 注意點

  * 搶到紅包不到能拆成功

  * 2014年的紅包一點開就知道金額,分兩次操作,先搶到金額,然后再轉賬。

    2015年后的紅包的拆和搶是分離的,需要點兩次,因此會出現搶到紅包了,但點開后告知紅包已經被領完的狀況。進入到第一個頁面不代表搶到,只表示當時紅包還有。

 

 

3 搶紅包接口實現

- 搶紅包功能接口開發

  * 在搶紅包這里並不能保證用戶已經能領到這個紅包

  - 搶紅包只是做了一個判斷,判斷當前是否還有紅包
  - 有紅包則返回可以領
  - 沒紅包則返回不可以領

- 拆紅包功能接口開發

  * 拆紅包才是用戶能領到紅包
  * 這時候要先減redis里面的金額和紅包數量
  * 減完金額再入庫

 

 

4微信紅包設計算法分析

- 玩法:微信金額是拆的時候實時算出來,不是預先分配的,采用的是純內存計算,不需要預算空間存儲
- 分配:
  * *發100塊錢,總共10個紅包,那么平均值是10塊錢一個,那么發出來的紅包的額度在0.01元~20元之間波動*
  * 當前面4個紅包總共被領了30塊錢時,剩下70塊錢,總共6個紅包,那么這7個紅包的額度在:0.01~(70➗6✖️2)=23.33之間波動(紅包金額/個數*2
  * 這樣算下去,可能會超過最開始的全部金額,因此到了最后面如果不夠這么算,那么會采取如下算法:保證剩余用戶能拿到最低1分錢即可
  - 存儲:數據庫會累加已經領取的個數與金額,插入一條領取記錄。入賬則是后台異步操作
  - 轉賬:通過財付通往紅包所得者賬戶轉賬,過程通過是異步操作

 

搶紅包項目總結

 

 - take all操作

  - 入庫轉賬時需要保證紅包個數和紅包剩余金額正確
- 高並發處理:紅包如何計算被搶完?
  - cache會抵抗無效請求,將無效的請求過濾掉,實際進入到后台的量不大。cache記錄紅包個數,原子操作進行個數遞減,到0表示被搶光
- 性能擴展
  * 多主sharding,水平擴展機器
  * 數據庫層面sharding分片
  * redis層面sharding分片技術
- 業務能動性,從發展的角度來看待業務
- 觀察總結,技術賦能業務

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM