抽奖需随机+权重+状态控制三重机制,涵盖资格校验、概率分配与结果幂等;主流算法按场景选型:均匀随机适均等概率,加权轮询(别名法)适稀有大奖,分桶预生成适高并发秒杀;风控须严控频次、资格、设备、IP、库存五边界;发奖需异步解耦、事务补偿与人工兜底三层闭环。

抽奖核心逻辑:用随机+权重+状态控制实现公平与可控
抽奖不是简单调用red">Random.nextInt(),关键在三重控制:用户资格校验、奖品概率分配、中奖结果幂等。比如某次活动要求“每人限抽1次,新用户额外加权2倍”,就得先查用户历史参与记录,再根据用户类型动态计算权重值,最后把中奖结果写入数据库并加唯一索引防止重复发放。
主流算法选型:均匀随机、加权轮询、分桶预生成各适用什么场景
三种常用方式不能混用:
• 均匀随机:适合奖品数量多、概率均等(如“100%中奖,50%得积分,30%得优惠券,20%得实物”),直接用ThreadLocalRandom.current().nextInt(100)映射区间;
• 加权轮询(Weighted Random Sampling):适合稀有大奖(如“iPhone中奖率0.1%”),建议用别名法(Alias Method)预构建O(1)查询表,避免每次遍历累加权重;
• 分桶预生成:适合高并发秒杀类抽奖(如“前100名抽中免单”),提前按规则生成中奖号段写入Redis Sorted Set,用户请求时用ZREVRANGEBYSCORE取一个并ZREM,保证原子性。
风控必须卡死的五个边界:频次、资格、设备、IP、奖品库存
光算得准没用,没风控等于送钱:
• 单用户每日最多3次,用Redis key=user:uid:date:draw cnt + EXPIRE 86400;
• 新用户标识需以注册时间+实名状态为准,不能只看登录态;
• 同一设备ID(Android ID / IDFA)1小时内限1次,防脚本群控;
• 短时间大量请求来自同一IP段(如/24),自动触发滑块验证或限流;
• 所有奖品库存走decr原子操作,库存为0时立即下线该奖品配置,不依赖前端隐藏。
发奖闭环:异步解耦+事务补偿+人工兜底缺一不可
中奖不等于到账。推荐三层设计:
• 第一层:中奖后立即落库(user_id, activity_id, prize_id, status=‘pending’),返回前端“已中奖,请稍候”;
• 第二层:MQ投递发奖任务(如RocketMQ),消费端调用积分/短信/物流系统,成功则更新status=‘success’,失败则重试3次后进死信队列;
• 第三层:每小时扫表查status=‘pending’超10分钟的记录,触发人工审核或自动补偿(如补发等价优惠券)。所有关键步骤记全链路traceId,便于对账排查。









