最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Redis實現(xiàn)搶紅包和發(fā)紅包功能

 更新時間:2024年04月17日 10:09:54   作者:京東云開發(fā)者  
搶紅包是我們生活常用的社交功能, 這個功能最主要的特點就是用戶的并發(fā)請求高, 在系統(tǒng)設計上, 可以使用非常多的辦法來扛住用戶的高并發(fā)請求, 在本文中簡要介紹使用Redis緩存中間件來實現(xiàn)搶紅包算法,需要的朋友可以參考下

簡介:

搶紅包是我們生活常用的社交功能, 這個功能最主要的特點就是用戶的并發(fā)請求高, 在系統(tǒng)設計上, 可以使用非常多的辦法來扛住用戶的高并發(fā)請求, 在本文中簡要介紹使用Redis緩存中間件來實現(xiàn)搶紅包算法, Redis是一個在內(nèi)存中基于 [key, value] 的緩存數(shù)據(jù)庫, Redis官方性能描述非常高, 所以面對高并發(fā)場景, 使用Redis來克服高并發(fā)壓力是一個不錯的手段, 本文主要基于Redis來實現(xiàn)基本的搶紅包系統(tǒng)設計.

發(fā)紅包模塊:

1:發(fā)紅包模塊流程圖如下:

用戶首先輸入紅包金額和紅包個數(shù), 然后生成當前紅包唯一標識, 并使用二倍均值算法生成隨機金額的紅包, 然后將生成的紅包存入緩存Redis數(shù)據(jù)庫中, Redis數(shù)據(jù)庫中會保存當前剩余的紅包數(shù)量和每個紅包的金額, 由于Redis數(shù)據(jù)庫是作為臨時存儲的地方, 所以發(fā)紅包記錄需要持久化存儲在數(shù)據(jù)庫中, 這里為加快系統(tǒng)響應, 使用異步的方式, 將紅包金額紀錄存儲入Mysql數(shù)據(jù)庫中, 以上就是發(fā)紅包模塊的簡要系統(tǒng)設計.

2:隨機生成紅包金額

對于搶紅包來說, 生成紅包金額是非常關鍵的, 這里有許多生成隨機數(shù)方法, 在本文中介紹一種使用較多的二倍均值算法來隨機生成紅包金額.對于搶紅包來說, 如果發(fā)送一個金額為J的紅包, 那么對與搶紅包的N個人來說, 公平的概率是: 每個人搶到J / N 的金額的概率是相同的, 例如100元紅包發(fā)給10個人,那么最公平的策略是使每個人搶到10元的概率相同, 二倍均值算法就是基于上面這個概率策略. 二倍均值算法流程如下: 首先設置紅包金額為J, 搶紅包人數(shù)為N, 接下來計算隨機數(shù)區(qū)間上U = J / N * 2, 得到隨機數(shù)區(qū)間(0,U), 從而在這個區(qū)間里生成第一個隨機數(shù)金額M, 接下來繼續(xù)生成第二個隨機金額. 首先更新總紅包金額為J-M,總搶紅包人數(shù)為N-1, 然后生成第二個隨機金額區(qū)間(0, (J-M) / (N-1) *2) , 從這個區(qū)間里面生成第二個隨機金額M2, 繼續(xù)迭代, 直到生成最后一個紅包金額, 下圖是二倍均值算法的流程

二倍均值算法案例: 紅包總金額100元, 總計10個人

計算第一個隨機金額區(qū)間: 100/10X2 = 20, 第一個隨機金額的區(qū)間是(0,20 ),區(qū)間均值為10

假設第一個人搶到10元,剩余金額是90 元

計算第二個隨機金額區(qū)間: 90/9X2 = 20, 第一個隨機金額的區(qū)間是(0,20 ),區(qū)間均值為10

假設第二個人搶到10元,剩余金額是80 元 計算第三個隨機金額區(qū)間: 80/8X2 = 20, 第一個隨機金額的區(qū)間是(0,20 ),區(qū)間均值為10

...............

所以使用二倍均值算法能夠在不論誰先搶的情況下, 都能公平保證每個人搶到平均金額的概率是相等的, 二倍均值算法生成紅包金額的代碼如下:

//這里輸入的totalMoney單位是分,例如100元,totalMoney = 10000
public List<Integer> getRedPackage(Integer totalMoney,Integer totalPeopleCount) {
    List<Integer> moneyList = new ArrayList<>();
    //暫存剩余金額為紅包的總金額
    Integer restMoney = totalMoney;
    //暫存剩余的總?cè)藬?shù)-初始化時即為指定的總?cè)藬?shù)
    Integer restPeopleCount = totalPeopleCount;    
    //隨機數(shù)對象
    Random random = new Random();
    //開始循環(huán)迭代生成紅包
    for (int i =0;i< totalPeopleNum-1;i++){
       //加1是為了至少搶到1分錢
       int money = random.nextInt (restMoney / restPeopleCount * 2) + 1;
       restMoney -= money;
       restPeopleCount--;
       moneyList.add(money);
    }
    //添加最后的一個紅包金額
    amountList.add(restAmount);
    return amountList;
}

3: 紅包存儲

為了應對用戶高并發(fā)的請求, 也就是需要頻繁讀取紅包金額和數(shù)量, 所以將紅包金額和數(shù)量存儲在Mysql中是不行的, 所以只能借助基于內(nèi)存的Redis數(shù)據(jù)庫來支持高并發(fā)的讀取操作.Redis中有5種基本的數(shù)據(jù)結(jié)構(gòu)分別是:String, List, Set, Sorted Set, Map這五種, 紅包金額數(shù)量是一個List集合, 所以使用List來存儲最為合適,在發(fā)紅包時, 我們先用二倍均值算法隨機生成一定數(shù)量的紅包金額, 然后將紅包金額和紅包數(shù)量存入Redis緩存中,等待用戶搶紅包

//隨機生成全局唯一的紅包id
redId = getRedId();
//首先生成紅包金額
List<Integer> moneyList = getRedPackage(totalMoney,totalPeopleCount);
//放入redis
redisClient.lpush(redId, moneyList);
//redis中記錄紅包個數(shù)
redisClient.set(redId, moneyList.size());
//異步存儲發(fā)紅包記錄到Mysql數(shù)據(jù)庫
//將紅包id返回
return redId;

搶紅包模塊:

1:搶紅包模塊流程圖如下:

首先判斷用戶是否已經(jīng)搶過紅包了, 是否還有剩余的紅包, 如果搶過或者剩余紅包數(shù)量小于等于0, 則代表紅包已經(jīng)被搶完了, 直接結(jié)束用戶本次搶紅包流程. 如果還有剩余的紅包數(shù)量, 則從Redis緩存列表中彈出一個紅包金額, 然后將剩余紅包數(shù)量減1, 同時異步將用戶搶紅包記錄存入Mysql數(shù)據(jù)庫, 最后將搶到的紅包金額返回給用戶, 結(jié)束本次搶紅包流程

2:首先判斷是否已經(jīng)搶過紅包

通過在Redis中以用戶ID構(gòu)建一個唯一Key來判斷是否搶過紅包, Key的構(gòu)建規(guī)則是:業(yè)務前綴+紅包id+用戶id

redMoney = redisClient.get("rob" + redId + useId)
//如果不為空,則說明已經(jīng)搶過了,直接返回搶過的紅包金額
if (redMoney != null) {
    return redMoney
}

3:判斷是否還有紅包

通過在Redis中以紅包id記錄一個數(shù)量來判斷是否還有紅包, key的構(gòu)建規(guī)則是:業(yè)務前綴+紅包id

totalNum = redisClient.get("totalNum" + redId)
//如果為空或者小于等于0則代表沒有了
if (totalNum == null || totalNum <= 0) {
    return null
}

4:彈出一個紅包金額

因為我們是把紅包金額存儲到Redis的List列表中的, 所以直接使用列表的Pop操作就行了

money = redisClient.rpop(redId)
//如果不為空,則說明搶到了
if (money != null) {
    ....
    紅包個數(shù)減1
    存儲搶紅包記錄
    設置該用戶已經(jīng)搶過紅包
    ....
    //返回搶到的金額
    return money
}
//沒搶到
return null

5:減少紅包個數(shù)

紅包總數(shù)是以一個[key, value] 鍵值對存儲在Redis中的, 所以這里使用Redis的DECR命令就行了

money = redisClient.rpop(redId)
//如果不為空,則說明搶到了
if (money != null) {
    //紅包個數(shù)減1
    redisClient.decr(redId)
    ....
    存儲搶紅包記錄
    設置該用戶已經(jīng)搶過紅包
    ....
    //返回搶到的金額
    return money
}
//沒搶到
return null

6:異步記錄搶紅包記錄

采用異步的方式將記錄存入Mysql數(shù)據(jù)庫, 異步的方式可以采用消息隊列或者多線程的方式來實現(xiàn)

money = redisClient.rpop(redId)
//如果不為空,則說明搶到了
if (money != null) {
    //紅包個數(shù)減1
    redisClient.decr(redId)
    //異步存儲搶紅包記錄
    這里可以使用mq或者多線程的方式來實現(xiàn)
    ....
    設置該用戶已經(jīng)搶過紅包
    ....
    //返回搶到的金額
    return money
}
//沒搶到
return null

7:設置該用戶已經(jīng)搶過紅包

money = redisClient.rpop(redId)
//如果不為空,則說明搶到了
if (money != null) {
    //紅包個數(shù)減1
    redisClient.decr(redId)
    //異步存儲搶紅包記錄
    這里可以使用mq或者多線程的方式來實現(xiàn)
    //設置該用戶已經(jīng)搶過紅包
    redisClient.set("rob" + redId + useId, money)
    //返回搶到的金額
    return money
}
//沒搶到
return null

8: 整體的偽代碼邏輯如下:

redMoney = redisClient.get("rob" + redId + useId)
//如果不為空,則說明已經(jīng)搶過了,直接返回搶過的紅包金額
if (redMoney != null) {
    return redMoney
}
totalNum = redisClient.get("totalNum" + redId)
//如果紅包總數(shù)小于0, 則代表已經(jīng)搶完了, 直接返回空
if (totalNum == null || totalNum <= 0) {
    return null
}
money = redisClient.rpop(redId)
//如果不為空,則說明搶到了
if (money != null) {
    //紅包個數(shù)減1
    redisClient.decr(redId)
    //異步存儲搶紅包記錄
    這里可以使用mq或者多線程的方式來實現(xiàn)
    //設置該用戶已經(jīng)搶過紅包
    redisClient.set("rob" + redId + useId, money)
    //返回搶到的金額
    return money
} 
//沒搶到
return null

9:分布式鎖

這里涉及到了同一個用戶多次高并發(fā)來搶紅包的情況, 并且代碼邏輯中包含了下面這種邏輯: 判斷條件成立然后進行業(yè)務操作,最后設置條件. 這種業(yè)務邏輯如果不防止并發(fā)的話, 就會產(chǎn)生重復操作, 所以需要使用鎖來限制每一個用的訪問頻率, 加鎖的方式是使用分布式鎖, 這是因為我們搶紅包服務不可能只在一臺服務器上部署, 同時基于Redis也能很容易的實現(xiàn)分布式鎖, 使用Redis命令setNx命令就可以實現(xiàn)簡單分布式鎖

redMoney = redisClient.get("rob" + redId + useId)
//如果不為空,則說明已經(jīng)搶過了,直接返回搶過的紅包金額
if (redMoney != null) {
    return redMoney
}
totalNum = redisClient.get("totalNum" + redId)
//如果紅包總數(shù)小于0, 則代表已經(jīng)搶完了, 直接返回空
if (totalNum == null || totalNum <= 0) {
    return null
}
//加分布式鎖
lockResut = redisClient.setNx(useId,redId,timeOut);
//加鎖失敗,直接返回
if(!lockResult){
    return;
}
try{
    money = redisClient.rpop(redId)
    //如果不為空,則說明搶到了
    if (money != null) {
        //紅包個數(shù)減1
        redisClient.decr(redId)
        //異步存儲搶紅包記錄
        這里可以使用mq或者多線程的方式來實現(xiàn)
        //設置該用戶已經(jīng)搶過紅包
        redisClient.set("rob" + redId + useId, money)
        //返回搶到的金額
        return money
    }     
} finally {
    //刪除鎖
    redisClient.del(useId)
}
//沒搶到
return null

總結(jié)

以上就是完整的搶紅包偽代碼流程, 可以基本實現(xiàn)發(fā)紅包以及搶紅包功能, 該方法基于Redis來實現(xiàn)紅包的存儲和搶紅包的操作, 基于二倍均值算法來實現(xiàn)紅包金額的隨即生成, 在整體功能上還有很多不完善的地方, 可以基于整體框架進行擴展開發(fā), 實現(xiàn)更加完整的算法

到此這篇關于基于Redis實現(xiàn)搶紅包和發(fā)紅包功能的文章就介紹到這了,更多相關Redis搶紅包和發(fā)紅包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Linux安裝Redis、后臺運行、系統(tǒng)自啟動的設置方法

    Linux安裝Redis、后臺運行、系統(tǒng)自啟動的設置方法

    Redis是用C語言編寫的開源免費的高性能的分布式內(nèi)存數(shù)據(jù)庫,基于內(nèi)存運行并支持持久化的NoSQL數(shù)據(jù)庫。這篇文章主要介紹了Linux安裝Redis、后臺運行、系統(tǒng)自啟動,需要的朋友可以參考下
    2020-01-01
  • 解決Redis開啟遠程訪問及密碼問題

    解決Redis開啟遠程訪問及密碼問題

    這篇文章主要介紹了Redis開啟遠程訪問及密碼的教程,文中給大家提到了Redis啟動報錯解決方法,需要的朋友可以參考下
    2019-10-10
  • redis以目錄形式存儲和讀取數(shù)據(jù)實現(xiàn)方式

    redis以目錄形式存儲和讀取數(shù)據(jù)實現(xiàn)方式

    這段文章主要討論了在項目中使用Redis進行數(shù)據(jù)寫入與讀取的方法,并強調(diào)了合理設置key的重要性,建議使用特定目錄形式,如“company:companyTree-all”來組織數(shù)據(jù)結(jié)構(gòu),以提高數(shù)據(jù)管理效率
    2026-05-05
  • windows環(huán)境下Redis+Spring緩存實例講解

    windows環(huán)境下Redis+Spring緩存實例講解

    這篇文章主要為大家詳細介紹了windows環(huán)境下Redis+Spring緩存實例教程,感興趣的小伙伴們可以參考一下
    2016-04-04
  • Redis MONITOR命令使用詳解

    Redis MONITOR命令使用詳解

    MONITOR是Redis提供的一個核心調(diào)試與審計命令,用于實時捕獲并打印服務器接收到的所有命令請求,本文就來介紹一下Redis MONITOR命令使用,感興趣的可以了解一下
    2025-11-11
  • Redis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • 一篇文章讓你明白Redis主從同步

    一篇文章讓你明白Redis主從同步

    今天小編就為大家分享一篇關于一篇文章讓你明白Redis主從同步,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • redis的常見用法和問題之緩存擊穿、緩存穿透、緩存雪崩詳解

    redis的常見用法和問題之緩存擊穿、緩存穿透、緩存雪崩詳解

    在現(xiàn)代高并發(fā)的互聯(lián)網(wǎng)應用中,緩存技術(shù)已成為提升系統(tǒng)響應速度與減輕后端數(shù)據(jù)庫壓力的關鍵手段,這篇文章主要介紹了redis的常見用法和問題之緩存擊穿、緩存穿透、緩存雪崩的相關資料,需要的朋友可以參考下
    2026-05-05
  • Redis緩存異常之緩存雪崩問題解讀

    Redis緩存異常之緩存雪崩問題解讀

    文章主要介紹了緩存雪崩、擊穿和穿透問題,以及針對這些問題的解決方法,包括服務熔斷、服務降級、請求限流和布隆過濾器等
    2025-01-01
  • Redis+Caffeine實現(xiàn)雙層緩存的策略對比與詳細指南

    Redis+Caffeine實現(xiàn)雙層緩存的策略對比與詳細指南

    在高并發(fā)場景下,緩存是提升系統(tǒng)性能和并發(fā)處理能力的關鍵手段,本文將基于Spring?Boot,從方案對比分析出發(fā),深入探討Redis、本地Caffeine與雙層緩存的實現(xiàn)與性能差異,并給出選型建議與實際效果驗證
    2025-07-07

最新評論

莎车县| 凭祥市| 隆昌县| 日喀则市| 英超| 石景山区| 泉州市| 平凉市| 蓝山县| 繁昌县| 泰和县| 荃湾区| 蒲江县| 甘肃省| 苏尼特右旗| 田阳县| 黄骅市| 临湘市| 黄陵县| 洛川县| 青神县| 从江县| 综艺| 皮山县| 扎兰屯市| 清水河县| 垦利县| 新民市| 阳泉市| 太保市| 葵青区| 拉孜县| 长武县| 九寨沟县| 故城县| 额济纳旗| 安西县| 东台市| 中西区| 嘉善县| 松原市|