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