thinkphp redis队列处理_thinkphp+redis实现秒杀功能

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

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

41952b423473c6c4290244907a6c9d07.png

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

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

fc536aaf1be4efdce047f028bfd951b7.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可以进行简单的模拟并发测试如下:

de495b0018645d97a02965af04a2c4b1.png

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

392a4bec056d32cf1c1062820cc1a4a3.png

以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要

PHP进阶架构师>>>视频、面试文档免费获取​docs.qq.com
96ecc0b0aa7d4f2b159a53b4d7c54bb2.png

或 者关注咱们下面的知乎专栏

PHP架构师圈子​zhuanlan.zhihu.com
18e65a14d2f0e14aa5ede1f09bfcc91d.png
来源:https://www.cnblogs.com/bieanju/p/6225722.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值