thinkphp+redis實現秒殺功能

attachments-2020-03-g6zWLUUU5e796d4bbfa25.jpg

 

1,安裝redis,根據本身的php版本安裝對應的redis擴展php

  1.1,安裝 php_igbinary.dll,php_redis.dll擴展此處須要注意你的php版本如圖:ajax

v2-744aa39fc1f62d35768775d815a11014_720w.png

  1.2,php.ini文件新增 extension=php_igbinary.dll;extension=php_redis.dll兩處擴展redis

ok此處已經完成第一步redis環境搭建完成看看phpinfo數據庫

v2-b39984a132deea59fd024044526b45e5_720w.jpg

 

2,項目中實際使用redisapache

  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來異步的處理用戶點擊購買按鈕進行符合條件的數據進入購買的排隊隊列函數

/**
     * 搶購商品前處理當前會員是否進入隊列
     * @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能夠進行簡單的模擬併發測試以下:

v2-12422db14c60f4fa2a57301c57c39584_720w.png

跑起來,我擦跑步起來redis沒有任何反應,此時還少一步重要的步驟就是開啓redis服務。

請根據本身的系統下一個redisbin_x32或者redisbin_x64的redis服務管理工具,點擊redis-server.exe,ok至此所有完成。

以下圖:

v2-2f08d0626af7589c98aad35c3f714fd5_720w.jpg

 

 

attachments-2020-03-vs1V6zrw5e796dacd955b.jpg

相關文章
相關標籤/搜索