前言
最近在工作中,新接了一個紅包功能的需求,這對于我來說,是非常感興趣的,但是又有點害怕,害怕自己做不好,也沒有了解過搶紅包功能的實作,最後隻能靠着百度,查詢到了幾篇非常好的文章,感謝大神的無私奉獻,對我來說簡直就是雪中送炭.
https://www.zybuluo.com/yulin718/note/93148
https://juejin.cn/post/6925947709517987848
需求
我這邊的業務是在直播房間類發送金币紅包,首先金币是沒有小數點的,是以不用考慮小數點的問題,一般就是最小就發 10金币。紅包類型分為 房間紅包和全服紅包,差別在于,房間紅包隻能在這個房間的人能搶,而全服紅包就是所有人都能搶,紅包又分為 普通紅包和随機紅包,普通紅包就簡單了,沒人平均去分,随機紅包就要用到微信的紅包算法了 額度在0.01和剩餘平均值*2之間 。
流程圖

紅包功能分為兩種實作,一種就是預配置設定 紅包,一種就是純記憶體計算,其實這種實作都可以,在看了微信紅包的架構中寫到 微信金額是拆的時候實時算出來,不是預先配置設定的,采用的是純記憶體計算,不需要預算空間存儲 ,這也就表示 微信紅包是純記憶體計算出來的,這種情況對于機器的預算是非常吃緊的,一般來說小的公司可以忽略這些,比較流量也不大,直接就用純記憶體計算就可以,預配置設定 : 在開獎之前就已經知道那些人能搶到紅包了,或者說有搶到紅包的資格,比如: 我們在看一些直播的時候,有一些搶紅包操作,但是通常都會說,先買一件商品才能搶,又或者,直播發紅包,要先點關注才能搶到紅包,這就是預配置設定法,這種好處就是,能抵擋一波流量。
Redis實作
實作以上功能最簡單的就是 使用 redis中的 list 結構來做了,先進行紅包拆分,然後寫入到 redis中,沒一個人來搶的時候就pop出去,一直到沒有就表示該紅包被搶光了,這裡建議大家看看,我發的連結上面有多紅包各種實作的分析,非常好,并且也說了這種方式的弊端:搶紅包時一旦從隊列彈出,此時系統崩潰,恢複後此隊列中的紅包明細資訊已丢失,需要人工補償。 确實這就是這種實作方式最大的問題,不過,小公司也不用考慮這些,大不了就做redis的高可用。
代碼實作
發紅包,紅包拆分:
/**
* redis list 結構實作 lpush 發紅包:
* @param type 0普通紅包 1.随機紅包
* @param number 紅包個數
* @param amount 紅包金額
*/
@PostMapping("/redWars")
public void redWars(Integer type,Integer number, Integer amount){
ArrayList<Integer> arrayList = new ArrayList<>();
//總金額: 發送紅包的總金币數
Integer money = number * amount;
//普通紅包拆分
if(type == 0){
arrayList = commonRed(money, number);
//随機紅包拆分
}else if(type == 1){
/**
* 由于我們金币是不需要小數的,我們值需要整數,是以下面代碼被我改了
* 如果是金額的紅包 請 參考 RoomTest
*/
arrayList = commonRoomRed(BigDecimal.valueOf(money),number);
}
//類型轉換:
List<String> collect = arrayList.stream().map(i -> String.valueOf(i)).collect(Collectors.toList());
//紅包key 過期時間 拆分的資料: 這就是搶紅包的金額:
redisService.lpush("1002",30, TimeUnit.HOURS,collect);
}
搶紅包:
/**
* list 資料接口給 lpop: 搶紅包
* @param key 紅包key
*/
@RequestMapping("/setLpop")
public void setLpop(String key){
String lpop = redisService.lpop(key);
if(!StringUtils.hasLength(lpop)){
System.out.println("目前紅包已搶光!");
}else{
System.out.println("恭喜你搶到紅包--->"+lpop);
}
}
完整代碼: spring-boot-redis-integrat
執行個體代碼在github上面需要的請自行拉取:spring-boot-integrate 然後後續會內建更多的子產品進去,需要請點個star。後續會內建更多的接口實作,有需要的請儲存。
如果這篇文章,有幫助到大家的,請給作者一個一鍵三連,謝謝