抽奖系统

引言:如何设计一个高并发系统?以抽奖系统为例

抽奖系统

高QPS系统需要有什么

总结一个高QPS的业务,要做好:

  • 高qps服务承载:redis
  • 防止打爆下游服务可以使用削峰填谷的消息队列:kafka
  • 流量打入后要漏斗化:越接近底层的服务流量需要越少
  • 要有熔断机制:直接返回未中奖
  • 要有灾备机制:DB+log

抽奖业务

中奖逻辑:

获得抽奖机会>>扣减抽奖机会>>概率计算是否可以中奖>>是否已经中过奖>>中奖>>结束

抽奖系统:

  1. 抽奖次数:有优先级,优先扣除顺序a-b-c

    • 每日有一次机会,不叠加

    • 奖品有再抽一次

    • 商品交易会增加抽奖次数

  2. 奖品:

    • 大量的虚拟奖品(价值低)

    • 少量的实体奖品(价值高):只有消费满一定资格,才有机会抽到

业务特点:

  • QPS很高,流量漏斗化越靠近底层,流量越少
  • 不能超发,会直接带来经济损失
  • 防刷,防止机器人或专业团队薅羊毛
  • 灾备

系统设计

  • 与现有业务分离,防止抽奖影响到既有业务
  • 逐层淘汰不合规请求
    • 是否有中此奖品的权限:
      • 奖品是本交易免单,那么前提就是进行过交易
      • 奖品是实体,要求消费金额>300元
    • 奖品数量:防止超发
  • redis:保证提供高qps服务
    • 存储结构为Hash:Map<String, Map<String, Object>>
    • 分布式锁:setnx,防止刷奖
    • 存储抽奖次数信息: Key : Value
      • 每日一次抽奖:last_timestamp:timestamp
      • 再来一次奖励:one_more_time : cnt
      • 交易抽奖次数:transaction_time : cnt
    • kafka:发奖,削峰填谷

抽奖概率模型

有几种概率模型:

  1. 概率实现确定:画一个数轴,随机数落入哪里,就中什么奖品

    • 实现简单方便,但是大奖可能会早早被抽走
  2. 不要求奖品一定要送完:

    • 抽奖概率可以随时间升高

    • 可以设置在某个时间后一定中奖

发奖和中奖记录

抽奖的奖品可能依赖的下游服务:

  • 优惠券服务
  • 邮寄服务
  • vip服务

抽奖的qps很高,为了不打垮下游服务,因此需要kafka做一个缓存,在中奖之后,写入kafka,再由下游慢慢消费。

中奖记录:kafka+DB+log来存储中奖记录信息。

兜底策略

  1. 如果redis被打爆,那么直接返回未中奖
  2. 中奖结果除了写入kafka、DB,还写入log,做最后兜底
  3. 在关键点加报警
  4. 做好补发奖品的脚本:查log日志,给中奖用户补发奖品