当前位置:首页 > 问答 > 正文

用Redis搞个动态权重抽奖,随机性还能调节,挺有意思的玩法

这个用Redis搞动态权重抽奖的想法,其实是在网上看到一个技术论坛里的讨论,有人问怎么做一个“越抽越容易中”或者“可以控制欧皇”的抽奖系统,用数据库的话,每次抽奖都要算总和、更新数据,人一多数据库就顶不住了,而Redis全内存操作,速度飞快,特别适合这种高并发的场景。

核心思想就一句话:把每个奖品的概率“重量化”,然后在一个总重量范围内“扔飞镖”。

具体怎么玩呢?我们一步步来。

第一步:给奖品分配“权重”

别想复杂的“概率”,就想成“重量”,比如我们有四个奖品:

  • A奖品:一台Switch,重量是 1(非常稀有)
  • B奖品:一个键盘,重量是 5(比较稀有)
  • C奖品:一杯奶茶券,重量是 20(比较常见)
  • D奖品:谢谢参与,重量是 74(非常常见)

那总重量就是 1+5+20+74 = 100,这看起来很像概率对吧?A奖品就是1%的中奖率,但关键在于,这个“重量”是我们可以随时动态调整的!

第二步:在Redis里搭建抽奖“地图”

我们需要用到一个Redis的数据结构,叫做有序集合(Sorted Set),你可以把它想象成一个排行榜,每个成员都有一个分数,我们就把奖品作为成员,而它的“重量”累计值作为分数。

怎么理解“累计值”呢?还是上面那个例子:

  • A奖品(重量1):累计分数范围就是 0 ~ 1 (不包括1,可以理解为 [0, 1) )
  • B奖品(重量5):累计分数就是 1 ~ (1+5)=6 ([1, 6) )
  • C奖品(重量20):累计分数就是 6 ~ (6+20)=26 ([6, 26) )
  • D奖品(重量74):累计分数就是 26 ~ (26+74)=100 ([26, 100) )

这样,我们就在Redis里创建了一个从0到100的“数轴”,每个奖品都占据了一段区间,区间的大小,就是它的权重,权重越大,区间就越宽。

用Redis命令初始化这个有序集合:

ZADD prize_pool 1 A 6 B 26 C 100 D

这里的分数就是每个奖品区间的上限

第三步:开始“扔飞镖”——随机抽奖

抽奖的一瞬间,我们只需要做两件事:

  1. 生成一个随机数,范围在 0 到总权重(这里是100)之间,假设我们随机到了数字 23。
  2. 用Redis的命令 ZRANGEBYSCORE prize_pool 23 +inf LIMIT 0 1

这个命令的意思是:在 prize_pool 这个有序集合里,找出分数大于等于23(+inf是正无穷的意思)的第一个成员,因为我们的分数是累计上限,23落在26这个区间里(26是C奖品的上限),所以找到的成员就是C奖品——“一杯奶茶券”!

这个过程就像在0-100的长度上扔飞镖,扎到哪段区间,就中哪个奖,因为区间宽度代表权重,所以权重大的奖品自然就更容易被扎到。

第四步:好玩的地方来了——动态调节随机性

上面只是基础玩法,真正有趣的是“动态权重”,因为权重存在Redis里,我们可以随时修改,从而实现各种骚操作:

  1. “越抽越容易中”的保底机制:如果有人连续抽中了“谢谢参与”,我们可以用 ZINCRBY 命令,悄悄增加他后续抽奖时其他奖品的权重,每抽空5次,就把Switch的权重从1增加到2,键盘从5增加到7,虽然还是很难中,但希望变大了,用户体验会好很多,这比固定的概率更有人情味。

  2. 控制“欧皇”,照顾“非酋”:我们可以给每个用户记录一个“中奖积分”,如果有人刚中了一个大奖(Switch),我们立刻通过 ZINCRBY 临时调低他账号下所有高价值奖品的权重,甚至在一段时间内将Switch的权重设为0,防止被同一个人薅秃噜皮,反之,对于很久没中奖的用户,可以适当调高权重,体现关怀。

  3. 营造抽奖气氛:在活动开始或某个整点,管理员可以通过Redis命令行,瞬间把所有奖品的权重翻倍,制造一个“爆率翻倍”的狂欢时刻,因为修改Redis的权重值是瞬间生效的,所有用户立刻就能感受到,不需要重启服务或者修改代码。

  4. 奖品库存联动:可以把奖品的剩余库存也作为权重的一部分,比如Switch只有10台,每中奖一台,就用 ZINCRBY 命令将Switch的权重减1,当权重减到0时,自然就抽不中了,完美实现库存控制。

为什么非得用Redis?

想象一下,如果这些操作都去查数据库:每次抽奖都要计算总权重、生成随机数、再用SQL查询区间、最后还要更新库存或用户记录,这在高并发下,数据库压力巨大,速度慢,容易出问题。

而Redis是单线程内存操作,上面这些“查有序集合”和“改权重”的命令都非常快,能轻松应对瞬间的海量抽奖请求,它简单的数据模型和强大的命令,正好完美匹配了这个玩法的所有需求。

这个方案不仅仅是一个抽奖,它提供了一个灵活的“杠杆”,让你可以通过实时调节Redis里的几个数字,来精准地控制整个活动的节奏、用户体验和公平性,这本身就是一件非常有意思的事情。

用Redis搞个动态权重抽奖,随机性还能调节,挺有意思的玩法