在后端服务和redis的方式实现概率抽奖逻辑

发布于:2025-02-11 ⋅ 阅读:(75) ⋅ 点赞:(0)

需求前言

笔者曾经在保险电商公司任职过,其中负责营销活动服务,一开始开发的抽奖活动,抽奖概率都是一样的,这种呢,很简单,直接用redis的set实现即可:

127.0.0.1:6379> sadd luckydraw 111 222 333 444 555 666 777 888 999 000
(integer) 10
127.0.0.1:6379> srandmember luckydraw
"999"

类似于这样的逻辑。
但随着需求变更,代码版本也需要迭代,每次保险代理人开单满多少金额就拥有一次抽奖机会,而且是开单金额越高,抽到一等奖的概率就越高,这种情况就要配置概率,例如有888、666、233、10元红包,所有概率加起来为1,开单10w以下,概率分别为“0.1”,“0.2”,“0.2”,“0.4”,10w以上,概率就配置为“0.4”,“0.3”,“0.2”,“0.1”,类似于这样的配置,这种配置的好处是扩展性啊,后续有关于新的活动上线,配置其他中奖概率即可。

在后端服务方式实现

public static void main(String[] args) {
		//该probabilities数组就是配置的概率顺序,0.1就是一等奖的概率,0.2是二等奖的概率,依次类推……
        double [] probabilities = {0.1,0.2,0.3,0.4};
        //该awards list相当于一等奖概率对应的奖品,也是依次类似……
        List<String> awards = new ArrayList<>();
        awards.add("一等奖_888元");
        awards.add("二等奖_666元");
        awards.add("三等奖_233元");
        awards.add("四等奖_10元");
        for (int i = 0;i<10000;i++) {
            System.out.println("抽奖结果为" + drawLottery(probabilities, awards));
        }


    }

    public static String drawLottery(double[] probabilities, List<String> awards ){
        Random random = new Random();
        //生成一个0-1的数字,相当于抽奖,例如生成0.1的概率是比0.2要小的,其实在该区间内生成的数字是越大,概率越大
        double v = random.nextDouble();
        System.out.println("查看抽奖的区间为"+v);
        double tempProbabilitie = 0;
        for (int i = 0; i < probabilities.length; i++) {
            tempProbabilitie+=probabilities[i];
            if (v<tempProbabilitie){
                //中奖区间
                return awards.get(i);
            }
        }
        //表示抽奖生成的概率不在中奖区间
        return "没有中奖!";

    }

演示效果

上面配置一等奖、二等奖、三等奖、四等奖的概率分别为0.1,0.2,0.3,0.4,模拟抽奖1w次,笔者分别查看四个奖品抽中的次数:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
都近似于概率。

使用Redis实现

如果抽奖并发过大,后端服务可能无法应对过大请求,于是引入Redis,通过Nginx接收请求后使用lua脚本与Redis连接进行抽奖即可,无需经过后端服务,lua脚本实现抽奖代码如下:

-- Lua 脚本:抽奖逻辑
-- KEYS[1]: 存储概率的 Redis 列表键名
-- KEYS[2]: 存储奖项的 Redis 列表键名

-- 获取概率和奖项列表
local probabilities = redis.call('LRANGE', KEYS[1], 0, -1)
local awards = redis.call('LRANGE', KEYS[2], 0, -1)

-- 生成一个 0-1 的随机数
local randomValue = math.random()

-- 初始化累加概率
local tempProbabilitie = 0

-- 遍历概率列表
for i = 1, #probabilities do
    tempProbabilitie = tempProbabilitie + tonumber(probabilities[i])
    if randomValue < tempProbabilitie then
        -- 返回对应的奖项
        return awards[i]
    end
end

-- 如果没有中奖
return "没有中奖!"

ps:配置的概率也是存在Redis上;

如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论!