php redis 队列抢红包_thinkphp+redis实现秒杀功能

本文介绍了如何在PHP环境中,结合ThinkPHP框架和Redis实现秒杀系统的队列功能。首先,详细讲述了Redis环境的搭建,包括安装扩展和配置。接着,展示了在项目中配置Redis参数和在函数中使用Redis进行库存处理。文章重点在于秒杀的核心逻辑,通过将商品库存放入队列,并使用Ajax异步处理购买请求,确保并发情况下不超过库存限制。最后,提供了模拟并发测试的方法和注意事项,如开启Redis服务。
摘要由CSDN通过智能技术生成

e21dad61b2cac3f3cbec84475e87e452.png

1,安装redis,根据自己的php版本安装对应的redis扩展(此步骤简单的描述一下)

  1.1,安装 php_igbinary.dll,php_redis.dll扩展此处需要注意你的php版本

1.2,php.ini文件新增 extension=php_igbinary.dll;extension=php_redis.dll两处扩展

ok此处已经完成第一步redis环境搭建完成看看phpinfo

35e491c9146006a03059c88b457c5a03.png

2,项目中实际使用redis

  2.1,第一步配置redis参数如下,redis安装的默认端口为6379:

<?php
/* 数据库配置 */
return array(
    'DATA_CACHE_PREFIX' => 'Redis_',//缓存前缀
    'DATA_CACHE_TYPE'=>'Redis',//默认动态缓存为Redis
    'DATA_CACHE_TIMEOUT' => false,
    'REDIS_RW_SEPARATE' => true, //Redis读写分离 true 开启
    'REDIS_HOST'=>'127.0.0.1', //redis服务器ip,多台用逗号隔开;读写分离开启时,第一台负责写,其它[随机]负责读;
    'REDIS_PORT'=>'6379',//端口号
    'REDIS_TIMEOUT'=>'300',//超时时间
    'REDIS_PERSISTENT'=>false,//是否长连接 false=短连接
    'REDIS_AUTH'=>'',//AUTH认证密码 
);
?>

2.2,实际函数中使用redis:

/**
 * redis连接
 * @access private
 * @return resource
 * @author bieanju
  */
 private function connectRedis(){
     $redis=new Redis();
     $redis->connect(C("REDIS_HOST"),C("REDIS_PORT"));       
     return $redis;
 }

2.3,秒杀的核心问题是在大并发的情况下不会超出库存的购买,这个就是处理的关键所以思路是第一步在秒杀类的先做一些基础的数据生成:

//现在初始化里面定义后边要使用的redis参数
public function _initialize(){
        parent::_initialize();
        $goods_id = I("goods_id",'0','intval');      
        if($goods_id){
            $this->goods_id = $goods_id;
            $this->user_queue_key = "goods_".$goods_id."_user";//当前商品队列的用户情况
            $this->goods_number_key = "goods".$goods_id;//当前商品的库存队列
        }
        $this->user_id = $this->user_id ? $this->user_id : $_SESSION['uid'];      
    }

2.4,第二步就是关键所在,用户在进入商品详情页前先将当前商品的库存进行队列存入redis如下:

/**
  * 访问产品前先将当前产品库存队列
  * @access public
  * @author bieanju
  */
    public function _before_detail(){
        $where['goods_id'] = $this->goods_id;
        $where['start_time'] = array("lt",time());
        $where['end_time'] =  array("gt",time());
        $goods = M("goods")->where($where)->field('goods_num,start_time,end_time')->find();
        !$goods && $this->error("当前秒杀已结束!");
        if($goods['goods_num'] > $goods['order_num']){
            $redis = $this->connectRedis();
            $getUserRedis = $redis->hGetAll("{$this->user_queue_key}");
            $gnRedis = $redis->llen("{$this->goods_number_key}");
            /* 如果没有会员进来队列库存 */
            if(!count($getUserRedis) && !$gnRedis){            
                for ($i = 0; $i < $goods['goods_num']; $i ++) {
                    $redis->lpush("{$this->goods_number_key}", 1);
                }
            }
            $resetRedis = $redis->llen("{$this->goods_number_key}");
            if(!$resetRedis){
                $this->error("系统繁忙,请稍后抢购!");
            }
        }else{
            $this->error("当前产品已经秒杀完!");
        }
    }

接下来要做的就是用ajax来异步的处理用户点击购买按钮进行符合条件的数据进入购买的排队队列(如果当前用户没在当前产品用户的队列就进入排队并且pop一个库存队列,如果在就抛出,):

/**
     * 抢购商品前处理当前会员是否进入队列
     * @access public
     * @author bieanju
     */
    public function goods_number_queue(){
        !$this->user_id && $this->ajaxReturn(array("status" => "-1","msg" => "请先登录"));
        $model = M("flash_sale");
        $where['goods_id'] = $this->goods_id;
        $goods_info = $model->where($where)->find();
        !$goods_info && $this->error("对不起当前商品不存在或已下架!"); 
        /* redis 队列 */  
        $redis = $this->connectRedis();
        /* 进入队列  */
        $goods_number_key = $redis->llen("{$this->goods_number_key}");
        if (!$redis->hGet("{$this->user_queue_key}", $this->user_id)) {
            $goods_number_key = $redis->lpop("{$this->goods_number_key}");
        }
         
        if($goods_number_key){
            // 判断用户是否已在队列
            if (!$redis->hGet("{$this->user_queue_key}", $this->user_id)) {
                // 插入抢购用户信息
                $userinfo = array(
                    "user_id" => $this->user_id,
                    "create_time" => time()
                );               
                $redis->hSet("{$this->user_queue_key}", $this->user_id, serialize($userinfo));
                $this->ajaxReturn(array("status" => "1"));
            }else{
                $modelCart = M("cart");
                $condition['user_id'] = $this->user_id;
                $condition['goods_id'] = $this->goods_id;
                $condition['prom_type'] = 1;
        $cartlist = $modelCart->where($condition)->count();
                if($cartlist > 0){
                    $this->ajaxReturn(array("status" => "2"));
                }else{
                  
                   $this->ajaxReturn(array("status" => "1"));
                  
                }
                 
            }
             
        }else{
            $this->ajaxReturn(array("status" => "-1","msg" => "系统繁忙,请重试!"));
        }
    }

附加一个调试的函数,删除指定队列值:

public function clearRedis(){
         set_time_limit(0);
         $redis = $this->connectRedis();
         //$Rd = $redis->del("{$this->user_queue_key}");
         $Rd = $redis->hDel("goods49",'用户id'');
         $a = $redis->hGet("goods_49_user", '用户id');
         if(!$a){
             dump($a);
         }
         
         if($Rd == 0){
              exit("Redis队列已释放!");           
         }
     }

走到此处的时候秒杀的核心基本就完了,细节还需要自己在去完善,像购物车这边的处理还有订单的处理,好吧开始跑程序利用apache自身的ab可以进行简单的模拟并发测试如下:

8b40d49da803ba9ffdccbacdcc222e19.png

跑起来redis没有任何反应,此时还少一步重要的步骤就是开启redis服务,请根据自己的系统下一个redisbin_x32或者redisbin_x64的redis服务管理工具,点击redis-server.exe,ok至此全部完成如下图:

ae2a1f78e453725fb717b233283d1f40.png

以上内容希望帮助到大家,需要更多文章可以关注公众号:PHP从入门到精通,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些PHP高级、架构视频资料和大厂PHP面试PDF免费获取,需要戳这里PHP进阶架构师>>>实战视频、大厂面试文档免费获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值