Redis + lua实现高并发抢红包功能

Redis + lua实现高并发抢红包功能

复制代码

我是通过后台管理页面创建红包的.具体步骤
1.小红包预先生成,插到数据库里,红包对应的用户ID是null,红包金额是在min-max的范围内的值.

2.再将红包在数据库中的id与对应的红包金额,以json的格式存入redis的list中。

  RedEnvelopePutDto redEnvelopePutDto = new RedEnvelopePutDto();
  redEnvelopePutDto.setRedEnvelopeRecordId(redEnvelopeRecord.getId()); //红包信息对应的id
  redEnvelopePutDto.setPoint(redEnvelopeRecord.getPoint());  //红包金额, 我的业务是赠送积分,使用point
  //将红包信息放入redis中
  redis.lpush(key1,JSON.toJSONString(redEnvelopePutDto));
 

  3.抢红包

  使用lua脚本控制并发

   4.定时任务获取 已消费的队列 中的数据  数据很多的话,加入线程池处理

   (1) rpop取出已消费队列中的数据,(我是批量取出lua脚本操作)

   (2) 线程池处理,修改数据库中红包数据,为其增加userId, 修改其状态等操作

复制代码

复制代码

1.  抢红包lua (stringRedisTemplate 使用String来接收,再用fastjson转为对象)
--[[  函数:尝试获得红包,如果成功,则返回json字符串,如果不成功,则返回空
      参数:红包队列名, 已消费的队列名,去重的Map名,用户ID
      返回值:nil 或者 json字符串,包含用户ID:userId,红包ID:id,红包金额:money
--]]

if redis.call('hexists', KEYS[3], KEYS[4]) ~= 0 then
  local res =  "{\"status\":\"EXISTS\"}";
  local resJson = cjson.decode(res);
  local point = redis.call('hget', KEYS[3], KEYS[4]);
  resJson['point'] = point;
  local r = cjson.encode(resJson);
  return r;
else
  -- 先取出一个小红包
  local hongBao = redis.call('rpop', KEYS[1]);
  if hongBao then
    local x = cjson.decode(hongBao);
    -- 加入用户ID信息
    x['userId'] = KEYS[4];
    x['status'] = 'SUCCESS';
    local re = cjson.encode(x);
    -- 把用户ID放到去重的set里, value存积分
    local point = x['point'];
    redis.call('hset', KEYS[3], KEYS[4], point);
    -- 把红包放到已消费队列里
    redis.call('lpush', KEYS[2], re);
    return re;
  else
    -- 红包已被抢完
    return "{\"status\":\"NOT_ENOUGH\"}"
  end
end


2. 取红包lua (stringRedisTemplate 使用list来接收, json.parseArray()转为list数组)
--  抢到红包的用户,做后续处理,跟用户赠送积分操作

local len = redis.call('llen', KEYS[1]);
local tbl1 = {};
if len ~= 0 then
  for i=1, len do
     tbl1[i] = redis.call('rpop', KEYS[1])
  end
  return tbl1
else
  return nil
end

复制代码

 

2.红包dto

复制代码

public class RedEnvelopePutDto implements Serializable {


    private static final long serialVersionUID = 6700848681773224907L;
    //红包记录id
    private Integer redEnvelopeRecordId;

    private String userId;

    private Integer point;

    @ApiModelProperty("EXISTS:已存在 NOT_ENOUGH:红包不足,SUCCESS")
    private RedEnvelopeRedisStatus status;

    public Integer getRedEnvelopeRecordId() {
        return redEnvelopeRecordId;
    }

    public void setRedEnvelopeRecordId(Integer redEnvelopeRecordId) {
        this.redEnvelopeRecordId = redEnvelopeRecordId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public Integer getPoint() {
        return point;
    }

    public void setPoint(Integer point) {
        this.point = point;
    }

    public RedEnvelopeRedisStatus getStatus() {
        return status;
    }

    public void setStatus(RedEnvelopeRedisStatus status) {
        this.status = status;
    }
}

复制代码

 

参照博客:https://www.cnblogs.com/zhihuayun/articles/7442522.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值