Bootstrap

业务场景 基于mysql+redis的抢红包活动业务场景

目录

1. 活动的配置

2. 触发抢红包动作时,有4台机器并行处理抢红包业务


1. 活动的配置

抢红包可以支持3种类型

  • 固定的总金额,固定的红包数,每个红包金额随机,但总和必须等于总金额(总计100元,10个红包-二倍均值算法)
  • 指定每一个红包的金额,以及红包个数(5个1元,6个2元,7个3元...)
  • 指定总金额,以及单个红包金额的上下限(资金池100元,每个红包1-2元)

每个人可以抢的次数有以下两种情况

  • 一人一次
  • 一人多次

完成配置后

  • 数据库中生成一条活动信息记录(活动id+活动开始时间+活动结束时间+每个人可抢次数),以及若干条红包信息记录(红包id+归属活动id+是否经redis处理标记位+归属人)
  • 以活动id作为key,在redis中申请一个list作为队列,取20条红包信息记录使用lpush加入redis队列
  • 以活动id+"info"作为key,在redis中申请一个hash,并把活动信息存入(活动id+活动开始时间+活动结束时间+每个人可抢次数)

2. 触发抢红包动作时,有4台机器并行处理抢红包业务

客户端发起请求(时间戳+用户手机号+参与活动id)

  1. 每台机器尝试获取redis的分布式锁,基于stringRedisTemplate.putIfAbsent,并设置超时时间为10s防止死锁
  2. 若每人只允许抢一次,可以考虑适用布隆过滤器
  3. 若每人允许抢多次,则:使用redisTemplate.opsForHash.putIfAbsent,key为活动id+“info”,field为用户手机号,value为用户可抢次数
    1. 若返回true,表示该用户还未抢过
      1. 使用lpop获取redis队列中的元素(红包id+红包信息)
      2. 使用redisTemplate.opsForHash.increment,key为活动id+“info”,field为用户手机号,delta为-1(用户剩余可抢次数-1)
      3. 直接返回客户端成功,并通过rocketMq异步发送手机号+红包id,更新数据库
    2. 若返回false,则说明该用户已经抢过一次,获取用户剩余可抢次数
      1. 若>0,说明该用户仍可以抢,重复3.1.1步骤
      2. 若<=0,说明该用户不可以抢了,直接返回客户端失败
  4. 使用llen判断redis中队列长度,若<10,则重新查询20条库表中redis处理标记位为空的记录,使用lpush加入redis队列
  5. 释放分布式锁
;