有什么网站可以做3d免费试用网站空间
前提提要
        今天产品端提了个需求,院校组要求借调我去帮忙,因为我以前做过商城,现在他们需求做一个积分商城,需要做一个秒杀模块,结果毫无意外的我被借调过去了,刚好可以复习一下以前的知识,现在介绍一下redis的秒杀机制,首先大家需要了解redis的基础信息,可以参考小编的前面的文章 https://blog.csdn.net/masterphp/article/details/130728703,现在开始介绍redis秒杀,只要有两种方式来实现,锁和队列
  
 秒杀流程概述
 
在进行Redis的实现之前,我们先简要介绍一下秒杀的流程:
         1.用户在前端页面选择要秒杀的商品,并提交订单;
         2.系统校验用户提交的订单是否合法,如商品库存是否充足、用户是否符合参加条件等;
         3.系统将订单信息写入数据库,并返回给用户订单处理中的状态;
         4.用户在订单处理中不断轮询订单状态,直到订单完成。
 在秒杀流程中,系统需要进行多次校验和处理,其中最关键的部分就是判断商品库存是否充足,这部分需要保证数据的可靠性和并发性。
 秒杀实现原理
 
         1.使用Redis队列存储订单:秒杀活动中,会有大量的订单请求同时涌入系统,若采用传统的关系型数据库进行存储,会导致并发量过大,数据库连接数量过多,从而降低系统的性能和稳定性。为了解决这个问题,我们可以使用队列来存储订单信息。Redis中提供了List类型的数据结构,可用作队列的实现。通过将订单信息放入Redis队列中,系统可以快速处理大量的订单请求,并以先到先服务的顺序进行处理。
        2.使用Redis预减库存:秒杀活动中,需要对商品库存进行实时监控,否则会因为库存不够而导致订单处理失败。但是,如果每个订单都从数据库中查询商品库存,将会增加数据库的压力,导致系统并发性能降低。
 为了解决这个问题,我们可以使用Redis的预减库存策略。当用户抢购时,我们先使用Redis缓存中的商品库存信息,并实时更新该缓存信息,如果库存已经减少至0,则直接返回秒杀失败。
3.使用Redis分布式锁:在秒杀活动中,虽然我们使用Redis队列和预减库存,但是系统仍然需要面对大量的并发请求。在这些请求中,可能会有多个用户同时对同一个商品进行抢购,这就需要我们使用分布式锁来保证数据的可靠性。Redis的分布式锁使用方式非常简单,在抢购开始时,我们使用Redis的SETNX操作来尝试获取分布式锁,如果获取成功,则对库存进行操作,操作完成后,释放分布式锁。如果获取分布式锁失败,则需等待一段时间重试。
 
 乐观锁实现方式
 
//添加商品库存
 public function addGoodsStock(Request $request)
 {
         //接受数据
         $goods_id = $request->input('goods_id');
         $store = $request->input('store');
         //设置商品库存的key
         $key = 'seckill_goods_id_'.$goods_id;
         $res = Redis::set($key,$store);
         return $res;
 }
//用户秒杀商品
 public function buy(Request $request)
 {
         //接受数据
         $uid = $request->input('uid');
         $goods_id = $request->input('goods_id');
        //商品库存key
         $key = 'seckill_goods_id_'.$goods_id;
         //监听对应的key,事务提交之前,如果key被修改,则事务被打断
         Redis::watch($key);
         
         //获取商品库存
         $store = Redis::get($key);
         
         //抢购成功用户集合key
         $setKey = 'userGoodsSuccess';
         //判断该用户是否已经抢购过(该用户id是否在抢购用户集合中)
         $userBuyStatus = Redis::sismember($setKey,$uid);
         if($userBuyStatus){
                 return '您已抢过!';
         }
        if($store){
                 //记录用户信息,更新库存(保证这一组命令,要么全部成功,要么都不成功)
                 Redis::multi();//开始事务
             Redis::decr($key);//减少库存
             //将用户id添加到抢购成功用户集合中
         Redis::sadd($setKey,$uid);
         $result = Redis::exec();//提交,判断当前的key是否被某个客户端修改了
                 //结果判断
         if($result){
               //操作数据库,修改商品库存销量
             DB::table('goods')->where('id', $goods_id)->decrement('stock', 1, ['sale' => DB::raw('`sale`+1')]);
             //创建订单信息
             return '抢购成功!';
         }else{
             return '抢购失败,请重试!';
         }
      }else{
          return '已抢光!';
      }
 }
队列实现方式
//初始化库存队列
 public function init(Request $request)
 {
         //接受参数
     $goods_id = $request->input('goods_id');
     $store = $request->input('store');
         //获取key
     $key = 'list_seckill_goods_id_'.$goods_id;
    //防止对已经设置过的商品库存进行覆盖
     if(!empty(Redis::llen($key))) {
             return '已经设置了库存';
     }
        //初始化缓存,删除抢购用户id队列key和成功信息保存key,这个是抢购时生成的,防止错乱,初始化删除
     $userListKey = 'user_goods_id_'.$goods_id;
     Redis::command('del', [$userListKey, 'success']);
    // 将商品存入Redis链表中
     for($i = 1; $i <= $store; $i++) {
                 Redis::lpush($key, $i);
     }
        //设置过期时间
         Redis::expire($key, 120);
         echo '商品存入队列成功,数量:'.Redis::llen($key);
 }
 //redis队列抢购
 public function start(Request $request)
 {
         // 模拟随机登录用户
     $uid = mt_rand(1, 9999);
         //$uid = $request->input('uid');
     $goods_id = $request->input('goods_id');
         //获取key
     $key = 'list_seckill_goods_id_'.$goods_id;
    //从链表的头部删除一个元素,返回删除的元素,因为pop操作是原子性,即使很多用户同时到达,也是依次执行
     $count = Redis::lpop($key);
     if (!$count) {
             return '已抢光!';
     }
    //已抢购用户id队列
     $userListKey = 'user_goods_id_'.$goods_id;
     //判断该用户是否已经抢购过(该用户id是否在抢购用户集合中)
     $userBuyStatus = Redis::sismember($userListKey,$uid);
     if($userBuyStatus){
             return '您已抢过!';
     }
    //将用户id添加到抢购成功用户集合中
     Redis::sadd($userListKey,$uid);
    $msg = '抢到的人为:'.$uid.',抢到商品的顺序为第'.$count.'个';
     Redis::lpush('success', $msg);
    //操作数据库,修改商品库存销量
     DB::table('goods')->where('id', $goods_id)->decrement('stock', 1, ['sale' => DB::raw('`sale`+1')]);
     //创建订单信息
    return '恭喜您抢购成功!';
 }
  
