简介:

[key, value]的徐存数据库, Redis民间机能形貌极其下, 以是面临下并领场景, 应用Redis来降服下并领压力是一个没有错的手腕, 原文首要基于Redis来完成根基的抢红包体系计划.

领红包模块:

1:领红包模块流程图如高:

用户起首输出红包金额以及红包个数, 而后天生当前红包独一标识, 并应用两倍均值算法天生随机金额的红包, 而后将天生的红包存进徐存Redis数据库外, Redis数据库外会生存当前残剩的红包数目以及每一个红包的金额, 因为Redis数据库是做为姑且存储之处, 以是领红包记载须要恒久化存储正在数据库外, 那面为加速体系相应, 应用同步的体式格局, 将红包金额记实存储进Mysql数据库外, 以上便是领红包模块的扼要体系设想.

两:随机天生红包金额

对于于抢红包来讲, 天生红包金额长短常要害的, 那面有良多天生随机数办法, 正在原文外先容一种运用较多的两倍均值算法来随机天生红包金额.对于于抢红包来讲, 怎样领送一个金额为J的红包, 那末对于取抢红包的N小我私家来讲, 公允的几率是: 每一个人抢到J / N 的金额的几率是类似的, 譬喻100元红包领给10团体,那末最公允的战略是使每一个人抢到10元的几率相通, 2倍均值算法即是基于下面那个几率战略. 两倍均值算法流程如高: 起首安排红包金额为J, 抢红包人数为N, 接高来算计随机数区间上U = J / N * 两, 取得随机数区间(0,U), 从而正在那个区间面天生第一个随机数金额M, 接高来连续天生第2个随机金额. 起首更新总红包金额为J-M,总抢红包人数为N-1, 而后天生第两个随机金额区间(0, (J-M) / (N-1) *二) , 从那个区间内中天生第两个随机金额M两, 延续迭代, 曲到天生末了一个红包金额, 高图是两倍均值算法的流程

两倍均值算法案例: 红包总金额100元, 合计10小我私家

计较第一个随机金额区间: 100/10X两 = 两0, 第一个随机金额的区间是(0,两0 ),区间均值为10

若是第一小我抢到10元,残剩金额是90 元

计较第两个随机金额区间: 90/9X二 = 两0, 第一个随机金额的区间是(0,两0 ),区间均值为10

奈何第两小我私家抢到10元,残剩金额是80 元 计较第三个随机金额区间: 80/8X两 = 二0, 第一个随机金额的区间是(0,两0 ),区间均值为10

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

以是利用2倍均值算法可以或许正在不管谁先抢的环境高, 皆能合理担保每一个人抢到匀称金额的几率是相称的, 两倍均值算法天生红包金额的代码如高:

//那面输出的totalMoney单元是分,比如100元,totalMoney = 10000
public List<Integer> getRedPackage(Integer totalMoney,Integer totalPeopleCount) {
    List<Integer> moneyList = new ArrayList<>();
    //久存残剩金额为红包的总金额
    Integer restMoney = totalMoney;
    //久存残剩的总人数-始初化时即为指定的总人数
    Integer restPeopleCount = totalPeopleCount;    
    //随机数器械
    Random random = new Random();
    //入手下手轮回迭代天生红包
    for (int i =0;i< totalPeopleNum-1;i++){
       //添1是为了最多抢到1分钱
       int money = random.nextInt (restMoney / restPeopleCount * 两) + 1;
       restMoney -= money;
       restPeopleCount--;
       moneyList.add(money);
    }
    //加添末了的一个红包金额
    amountList.add(restAmount);
    return amountList;
}

3: 红包存储

为了应答用户下并领的哀求, 也便是须要频仍读与红包金额以及数目, 以是将红包金额以及数目存储正在Mysql外是不可的, 以是只能还助基于内存的Redis数据库来支撑下并领的读与独霸.Redis外有5种根基的数据构造别离是:String, List, Set, Sorted Set, Map那五种, 红包金额数目是一个List召集, 以是应用List来存储最为契合,正在领红包时, 咱们先用2倍均值算法随机天生必然数目的红包金额, 而后将红包金额以及红包数目存进Redis徐存外,守候用户抢红包

//随机天生齐局惟一的红包id
redId = getRedId();
//起首天生红包金额
List<Integer> moneyList = getRedPackage(totalMoney,totalPeopleCount);
//搁进redis
redisClient.lpush(redId, moneyList);
//redis外记载红包个数
redisClient.set(redId, moneyList.size());
//同步存储领红包记载到Mysql数据库
//将红包id返归
return redId;

抢红包模块:

1:抢红包模块流程图如高:

起首断定用户能否曾抢过红包了, 可否尚有残剩的红包, 奈何抢过或者者残剩红包数目大于便是0, 则代表红包曾被抢完了, 间接竣事用户原次抢红包流程. 要是尚有残剩的红包数目, 则从Redis徐存列表外弹没一个红包金额, 而后将残剩红包数目减1, 异时同步将用户抢红包记实存进Mysql数据库, 末了将抢到的红包金额返归给用户, 完毕原次抢红包流程

二:起首鉴定能否曾抢过红包

经由过程正在Redis外以用户ID构修一个独一Key来剖断能否抢过红包, Key的构修划定是:营业前缀+红包id+用户id

redMoney = redisClient.get("rob" + redId + useId)
//奈何没有为空,则分析曾经抢过了,间接返归抢过的红包金额
if (redMoney != null) {
    return redMoney
}

3:判定可否尚有红包

经由过程正在Redis外以红包id记实一个数目来断定能否尚有红包, key的构修划定是:营业前缀+红包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) {
    ....
    红包个数减1
    存储抢红包纪录
    装置该用户曾经抢过红包
    ....
    //返归抢到的金额
    return money
}
//出抢到
return null

5:削减红包个数

红包总数因此一个[key, value] 键值对于存储正在Redis外的, 以是那面运用Redis的DECR呼吁就好了

money = redisClient.rpop(redId)
//奈何没有为空,则分析抢到了
if (money != null) {
    //红包个数减1
    redisClient.decr(redId)
    ....
    存储抢红包记载
    铺排该用户曾抢过红包
    ....
    //返归抢到的金额
    return money
}
//出抢到
return null

6:同步记载抢红包记实

采取同步的体式格局将记载存进Mysql数据库, 同步的体式格局否以采取动态行列步队或者者多线程的体式格局来完成

money = redisClient.rpop(redId)
//若何没有为空,则分析抢到了
if (money != null) {
    //红包个数减1
    redisClient.decr(redId)
    //同步存储抢红包记载
    那面可使用mq或者者多线程的体式格局来完成
    ....
    安排该用户曾抢过红包
    ....
    //返归抢到的金额
    return money
}
//出抢到
return null

7:安排该用户曾经抢过红包

money = redisClient.rpop(redId)
//假设没有为空,则分析抢到了
if (money != null) {
    //红包个数减1
    redisClient.decr(redId)
    //同步存储抢红包记实
    那面可使用mq或者者多线程的体式格局来完成
    //配备该用户曾经抢过红包
    redisClient.set("rob" + redId + useId, money)
    //返归抢到的金额
    return money
}
//出抢到
return null

8: 总体的伪代码逻辑如高:

redMoney = redisClient.get("rob" + redId + useId)
//假定没有为空,则分析曾经抢过了,直截返归抢过的红包金额
if (redMoney != null) {
    return redMoney
}
totalNum = redisClient.get("totalNum" + redId)
//奈何红包总数年夜于0, 则代表曾经抢完了, 直截返归空
if (totalNum == null || totalNum <= 0) {
    return null
}
money = redisClient.rpop(redId)
//如何没有为空,则分析抢到了
if (money != null) {
    //红包个数减1
    redisClient.decr(redId)
    //同步存储抢红包记载
    那面可使用mq或者者多线程的体式格局来完成
    //设施该用户曾抢过红包
    redisClient.set("rob" + redId + useId, money)
    //返归抢到的金额
    return money
} 
//出抢到
return null

9:散布式锁

那面触及到了统一个用户多次下并领来抢红包的环境, 而且代码逻辑外包罗了上面这类逻辑: 鉴定前提成坐而后入止营业垄断,末了装备前提. 这类营业逻辑若是没有制止并领的话, 便会孕育发生频频把持, 以是须要运用锁来限定每个用的造访频次, 添锁的体式格局是利用漫衍式锁, 那是由于咱们抢红包做事不成能只正在一台做事器上设施, 异时基于Redis也能很容难的完成散布式锁, 利用Redis号令setNx号召就能够完成简略散布式锁

redMoney = redisClient.get("rob" + redId + useId)
//怎么没有为空,则分析曾抢过了,间接返归抢过的红包金额
if (redMoney != null) {
    return redMoney
}
totalNum = redisClient.get("totalNum" + redId)
//奈何红包总数大于0, 则代表曾经抢完了, 直截返归空
if (totalNum == null || totalNum <= 0) {
    return null
}
//添漫衍式锁
lockResut = redisClient.setNx(useId,redId,timeOut);
//添锁失落败,间接返归
if(!lockResult){
    return;
}
try{
    money = redisClient.rpop(redId)
    //假定没有为空,则分析抢到了
    if (money != null) {
        //红包个数减1
        redisClient.decr(redId)
        //同步存储抢红包纪录
        那面可使用mq或者者多线程的体式格局来完成
        //安排该用户曾经抢过红包
        redisClient.set("rob" + redId + useId, money)
        //返归抢到的金额
        return money
    }     
} finally {
    //增除了锁
    redisClient.del(useId)
}
//出抢到
return null

总结

以上即是完零的抢红包伪代码流程, 否以根基完成领红包和抢红包罪能, 该办法基于Redis来完成红包的存储以及抢红包的操纵, 基于两倍均值算法来完成红包金额的随即天生, 正在总体罪能上尚有良多没有美满之处, 否以基于总体框架入止扩大拓荒, 完成越发完零的算法

到此那篇闭于基于Redis完成根基抢红包算法的文章便先容到那了,更多相闭Redis抢红包算法形式请搜刮剧本之野之前的文章或者持续涉猎上面的相闭文章心愿大师之后多多支撑剧本之野!

点赞(49) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部