laravel 使用Redis 处理秒杀
刨铣:
需要一个排队队列和抢购结果队列及库存队列。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列。
排队队列:user_list 链表(list)
库存队列:good_list 链表(list)
结果队列:result_list 无序集合(set) ps:这里为了方便查找使用集合 hash也是可以的
直接上代码:
1、创建控制器 MiaoshaController.php
部分代码:
...
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Cache;
class MiaoshaController extends Controller{
public $goods_id = 90;//秒杀商品id
public $start_time = "2020-08-10 10:42:00";//秒杀开始时间
//redis并发测试(秒杀场景)
/**
* 重点在于Redis中存储数据的单线程的原子性,!!!无论多少请求同时执行这个方法,依然是依次执行的!!!!!
* 这种方式性能较高,并且确保了对数据库的单一操作,但容错率极低,一旦出现未可预知的错误会导致数据混乱;
*/
public function testRedis(Request $request){
Redis::select(2);//选择DB区
//此处用随机数来演示随机用户
$user_id = mt_rand(100,1000);
//判断抢购结果队列是否存在
if(Redis::sismember('result_list',$user_id)){
$this->DoLog("[".date('Y-m-d H:i:s')."] 只允许抢购一次用户ID##".$user_id);
return;
}
//判断抢购结果队列是否已满
if(Redis::scard('result_list') == 100){
$this->DoLog("[".date('Y-m-d H:i:s')."] 秒杀结束,欢迎下次参与".$user_id);
return;
}
//判断排队队列是否已满
if(Redis::llen('user_list') >= 200){
$this->DoLog("[".date('Y-m-d H:i:s')."] 抢购人数已满,进入失败推送事件".$user_id);
return;
}
Redis::rpush('user_list',$user_id);