首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
woshipanghu
V2EX  ›  程序员

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

  •  1
     
  •   woshipanghu · 52 天前 · 1915 次点击
    这是一个创建于 52 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    数据库 mysql 和 redis 都可以用

    v 友们有什么好思路吗

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

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