## 秒杀场景的简单实现
完整的版的在迁移博客的时候搞丢了。。。。
队列的特性在日常开发中还可以用于流量削锋跟解耦。这里做流量削锋的秒杀抢购场景的简单示例。
~~~
//监听已抢购的数量
Redis::watch("sk:1:num"); //已经秒杀完的商品数量
$skNum = Redis::hget("sk:h:1",'gum'); //秒杀商品Hash信息
$isSkNum = (int)Redis::get("sk:1:num");
if($isSkNum < $skNum ){
$uid = $this->rand(5);//随机生成用户id
// 暂时用setnx 跟 expire 处理限购 问题是并发情况下会不止10个人进来,但是不影响限购啊
// 没有考虑到更好的解决方案,先这么处理吧
// Redis::set("sk:su:1", 1 , 'NX', 'EX', "1000"); 不清楚predis下set 同时设置 NX和EX为什么老是不生效,暂时用下边的方法处理
if(Redis::setnx("sk:su:".$uid,$uid)){
Redis::expire("sk:su:".$uid,10); //设置过期时间,保证10秒内一个用户只能秒杀成功一次
}else{
Rddis::incr('fail');
echo "10秒内允许抢购一次。";
}
//上述代码不能放在multi之内。 否则if(Redis::setnx("sk:su:".$uid,$uid)) 会报错
//放在multi当中,相当于未执行,结果不会返回,所以会一直报错
Redis::multi();
Redis::incr('sk:1:num');
Redis::lpush("sk:l:1",$uid);
Redis::exec();
}else{
Redis::incr('fail');
echo "不好意思,秒杀已经结束了。";
}
~~~
* * *
ab 1000请求 100并发的请求结果:
~~~
127.0.0.1:6379> get sk:1:num
"10"
127.0.0.1:6379> lrange sk:l:1 0 -1
1) "t106A0502910239"
2) "160A50HR21k23R9"
3) "160i7O502f12Y39"
4) "160j5021W23UzZ9"
5) "Wd160c5i0212539"
6) "1Pw60I502Ae1239"
7) "146050RgG213239"
8) "1605p0aL212p3u9"
9) "16050wyAa2123Y9"
10) "16050fi2012f3j9"
~~~