• 请不要在回答技术问题时复制粘贴 AI 生成的内容
woshipanghu
V2EX  ›  程序员

大并发下的抽奖有什么好的实现思路吗?

  •  1
     
  •   woshipanghu · Feb 12, 2020 · 6038 views
    This topic created in 2463 days ago, the information mentioned may be changed or developed.

    并发的时候 怎么保证被抽的奖品确实还有数量

    数据库 mysql 和 redis 都可以用

    v 友们有什么好思路吗

    25 replies  •  2020-02-13 23:24:52 +08:00
    woshipanghu
    woshipanghu
    OP
    Feb 12, 2020
    1
    我自己想的一个逻辑
    奖品数量如果只剩下 1 个的时候,用户抽到这个奖品的时候需要去 redis 拿一个令牌,拿到令牌的用户获得这个奖品。
    其他用户,随机获取剩余奖品中的一样。
    jindeq
    jindeq
    Feb 12, 2020 via Android
    2
    @woshipanghu 并发量足够大的情况下,redis 可能崩的情况下,还需要其他的途径确保唯一性
    woshipanghu
    woshipanghu
    OP
    Feb 12, 2020
    3
    @jindeq 只要服务器正常 redis 我倒不担心崩掉,并发只要抢最后一个奖品的时候会用 redis redis 的并发不会太高
    lsylsy2
    lsylsy2
    Feb 12, 2020
    4
    比如奖品有 100 件,中奖率 1%
    那么就建一个队列,里面有 10000 个 object,object 的内容是中奖或不中奖,提前生成内容随机打乱
    每个“抽奖”的行为就是从队列取一个 object,取不到=谢谢惠顾
    高并发的话,可以把 1 个 10000 长度的队列切成 100 个 100 长度的队列,互相独立,每个 client 随机选一个队列去取。
    sujin190
    sujin190
    Feb 12, 2020
    5
    @lsylsy2 #4 抽奖不是秒杀,假设活动持续三天那么应该是尽可能的匹配人流分布在整个时间段内平均的抽中,否则万一一开始就全抽完了,后面就没法玩了,所以用队列看起来不是很科学吧
    optional
    optional
    Feb 12, 2020
    6
    @sujin190 用队列是可以的,把奖品按照时间分片,分成 n 个几个队列就好(比如队列名加入小时参数)。
    sujin190
    sujin190
    Feb 12, 2020
    7
    我感觉不需要那么复杂,加锁就是了吧,反正概率算法确定是否中奖这个不需要加锁,所以完全可以先抽中从奖池真正取奖品的时候加锁保证唯一性就好了,抽奖人可能很多,中奖人不可能也很多吧

    如果中奖人也很多,那说明你这奖品也不值钱,那就更无所谓了,就算有并发问题,多发个几十几百的这算个毛事,根本无需考虑吧
    sujin190
    sujin190
    Feb 12, 2020
    8
    @optional #6 队列的问题是抽奖人数无法准确预估,如果预估比实际少,一开始很快抽完了会影响活动效果,预估比实际多,受队列限制无法自适应提高中奖概率,也会影响活动效果
    abcbuzhiming
    abcbuzhiming
    Feb 12, 2020
    9
    我见过一个简单的思路,抽奖的请求全部排队,只允许和当前奖品剩余数量相等的请求数进入队列,超出的请求立刻返回“未中奖”。然后进入队列的请求再进行抽奖逻辑,绝不会超出剩余奖品,而且用户体验也还可以,当然对上专业黑产羊毛党会很头疼
    lxml
    lxml
    Feb 12, 2020
    10
    提前按照机器分好,放在内存里,然后对账,准确性和并发你只能选一样
    FaceBug
    FaceBug
    Feb 12, 2020
    11
    @sujin190 抽奖时段如果有三天这种跨度,一般都会分场次了。不需要绝对的考虑公平的问题,因为没法预估第二天流量是否还会保持第一天的热度,也没法确认第一天的热度到底有多高是吧。如果只有一个场次,持续三年,人为的限制了第一天的中奖率,结果第二天第三天没人来了,要么奖品送不完,要么认为干预,导致来的几乎都有奖。
    FaceBug
    FaceBug
    Feb 12, 2020
    12
    本质上是和秒杀一个思路的。先判断是否中奖,中奖了再从奖品队列弹出一个奖品。如果奖品不足,也认为是没有中奖。
    fewok
    fewok
    Feb 12, 2020
    13
    预估下多少并发,每秒 100W 次? 1 亿次?
    wAtcher789
    wAtcher789
    Feb 12, 2020 via Android
    14
    @abcbuzhiming 小米 :我怀疑你看了我们代码
    aliipay
    aliipay
    Feb 13, 2020
    15
    @wAtcher789 小米: 前端 js hash 一下 uid,直接过滤大部分用户请求 (当然后端也会同样 hash 处理), 你不中奖有可能是你 uid 不好 [:doge]
    horkooo
    horkooo
    Feb 13, 2020 via Android
    16
    题目描述比较简单,可以理解成秒杀的场景。对应秒杀场景的解决方案。同时也要兼顾活动的可持续性。每天放出的奖是剩余奖品除以剩余天数。抽奖,奖品,中奖数据全部放 redis,最后合并写库就行了。
    EminemW
    EminemW
    Feb 13, 2020
    17
    @aliipay 所以有的人很容易中奖,身边一个长辈,有一段很迷小米一元购,抽中很多
    18ac0877
    18ac0877
    Feb 13, 2020
    18
    将抽奖和公布结果分离,xxx-xxx 时间抽奖,xxx-xxx 时间后台根据算法抽奖,xxx 时间公布结果。
    18ac0877
    18ac0877
    Feb 13, 2020
    19
    另一个办法:后台先预定哪些用户能中奖,提前算好,如果该用户抽奖了直接返回中奖。
    murmur
    murmur
    Feb 13, 2020
    20
    return 未中奖
    xyooyx
    xyooyx
    Feb 13, 2020
    21
    削峰,然后进队列
    Finest
    Finest
    Feb 13, 2020
    22
    先通过随机数,把一部分流量的直接返回没抽中,这个量可以根据实际流量配置,如 50%。
    xiaoyouqiang
    xiaoyouqiang
    Feb 13, 2020
    23
    这个问题说的比较抽象,大并发解决方案本身就是一个大的领域。什么队列,缓存,复杂均衡都是手段,你要结合自己的情况,搭建一套大并发体系。
    LoremIpSum
    LoremIpSum
    Feb 13, 2020
    24
    1.请求进来
    2.根据预先配置好的中奖概率来判断这个请求能不能中奖
    3.如果可以中奖,锁定库存( redis 分布式锁),返回结果,反之直接返回未中奖
    hankai17
    hankai17
    Feb 13, 2020
    25
    是微 xin 的发 red bag 吗?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2153 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 58ms · UTC 14:40 · PVG 22:40 · LAX 06:40 · JFK 09:40
    ♥ Do have faith in what you're doing.