抢红包实战预热
List队列:将N个红包放到List队列中,用来初始化红包池子
执行命令,如何将多个红包放到放到hongBaoPool中
lpush hongBaoPoolKey {id:rid_1, money:9}
lpush hongBaoPoolKey {id:rid_2, money:8}
lpush hongBaoPoolKey {id:rid_3, money:12}
lpush hongBaoPoolKey {id:rid_N, money:15}
抢红包实战用到的基础命令
List类型:记录用户抢了多少钱
执行命令,如何将多个红包放到放到hongBaoDetailListKey 中
lpush hongBaoDetailListKey {id:rid_N, money:15,userId:N}
lpush hongBaoDetailListKey {id:rid_8, money:15,userId:3}
lpush hongBaoDetailListKey {id:rid_3, money:15,userId:2}
lpush hongBaoDetailListKey {id:rid_1, money:15,userId:1}
Hash类型:记录哪些用户已抢过红包,防止重复抢
执行命令,如何将多个红包放到放到hongBaoPool中
hset userIdRecordKey 001 1
hset userIdRecordKey 002 1
hset userIdRecordKey 003 1
hset userIdRecordKey 00N 1
业务流程
1,先初始化红包池:
lpush hongBaoPool {id:rid_1, money:9} //将N个红包信息放入hongBaoPool 中
2,Lua实现抢红包流程:
代码实现:
常量类:
public class Basic {
public static String ip = "192.168.46.133";
public static int port = 6379;
public static String auth = "12345678";
public static int honBaoCount = 1000;
public static int threadCount = 20;
public static String hongBaoPoolKey = "hongBaoPoolKey"; //LIST类型来模拟红包池子
public static String hongBaoDetailListKey = "hongBaoDetailListKey";//LIST类型,记录所有用户抢红包的详情
public static String userIdRecordKey = "userIdRecordKey";//记录已经抢过红包的用户ID,防止重复抢
/*
* KEYS[1]:hongBaoPool: //键hongBaoPool为List类型,模拟红包池子,用来从红包池抢红包
* KEYS[2]:hongBaoDetailList://键hongBaoDetailList为List类型,记录所有用户抢红包的详情
* KEYS[3]:userIdRecord : //键userIdRecord为Hash类型,记录所有已经抢过红包的用户ID
* KEYS[4]:userid : //模拟抢红包的用户ID
*
*
* jedis.eval( Basic.getHongBaoScript, 4, Basic.hongBaoPoolKey, Basic.hongBaoDetailListKey, Basic.userIdRecordKey, userid);
* Lua脚本 参数个数 key[1] key[2] key[3] key[4]
*/
public static String getHongBaoScript =
//查询用户是否已抢过红包,如果用户已抢过红包,则直接返回nil
"if redis.call('hexists', KEYS[3], KEYS[4]) ~= 0 then\n" +
"return nil\n" +
"else\n" +
//从红包池取出一个小红包
"local hongBao = redis.call('rpop', KEYS[1]);\n" +
//判断红包池的红包是否为不空
"if hongBao then\n" +
"local x = cjson.decode(hongBao);\n" +
//将红包信息与用户ID信息绑定,表示该用户已抢到红包
"x['userId'] = KEYS[4];\n" +
"local re = cjson.encode(x);\n" +
//记录用户已抢过userIdRecordKey hset userIdRecordKey userid 1
"redis.call('hset', KEYS[3], KEYS[4], '1');\n" +
//将抢红包的结果详情存入hongBaoDetailListKey
"redis.call('lpush', KEYS[2], re);\n" +
"return re;\n" +
"end\n" +
"end\n" +
"return nil";
}
生成红包类:
public class GenRedPack {
/**
* 多线程模拟红包池初始化 Jedis类
*/
public static void genHongBao() throws InterruptedException {
final JedisUtils jedis = new JedisUtils(Basic.ip, Basic.port, Basic.auth);
jedis.flushall(); //清空,线上不要用.....
//发枪器
final CountDownLatch latch = new CountDownLatch(Basic.threadCount);
for(int i = 0 ; i < Basic.threadCount; i++){
final int page = i;
Thread thread = new Thread(){
public void run(){
//每个线程要初始化多少个红包
int per = Basic.honBaoCount/Basic.threadCount;
JSONObject object = new JSONObject();
for(int j = page * per ; j < (page+1) * per; j++){ //从0开始,直到
object.put("id", "rid_"+j); //红包ID
object.put("money", j); //红包金额
//lpush key value===lpush hongBaoPoolKey {id:rid_1, money:23}
jedis.lpush("hongBaoPoolKey", object.toJSONString());
}
latch.countDown(); //发枪器递减
}
};
thread.start();
}
latch.await();//所有线程处于等状态
}
}
抢红包类:
/**
* 多线程模拟用户抢红包
*/
public class GetRedPack {
//抢红包的方法
static public void getHongBao() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(Basic.threadCount);//20 //发枪器
for(int i = 0 ; i < Basic.threadCount ; i ++){ //20线程
Thread thread = new Thread(){
public void run(){
//拿到jedis连接
JedisUtils jedis = new JedisUtils(Basic.ip, Basic.port, Basic.auth);
while(true){
//模拟一个用户ID使用UUID XXXX
String userid = UUID.randomUUID().toString();
//抢红包 eval 可以直接调用我们LUA脚本里的业务代码 object ={rid_1:1, money:9, userid:001}
Object object = jedis.eval(Basic.getHongBaoScript,4,Basic.hongBaoPoolKey,Basic.hongBaoDetailListKey,Basic.userIdRecordKey,userid);
if(null != object){
System.out.println("用户ID号:"+userid+" 抢到红包的详情是 "+object);
}else{
if(jedis.llen(Basic.hongBaoPoolKey) == 0){
break;
}
}
}
latch.countDown();
}
};
thread.start();
}
latch.await();
}
}
main:
public class MainTestRedPack {
public static void main(String[] args) throws InterruptedException {
GenRedPack.genHongBao();//初始化红包
GetRedPack.getHongBao();//从红包池抢红包
}
}
Lua实现核心业务-什么是Lua语言
Lua 是一个小巧的脚本语言,由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。 Lua语言里的操作提供原子性。
Lua实现核心业务
Object object = jedis.eval(getHongBaoScript, 4, hongBaoPoolKey, hongBaoDetailListKey, userIdRecordKey, userid );