PHP+redis实现的限制抢购防止商品超发功能详解

前端之家收集整理的这篇文章主要介绍了PHP+redis实现的限制抢购防止商品超发功能详解前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本文实例讲述了PHP+redis实现的限制抢购防止商品超发功能分享给大家供大家参考,具体如下:

  • redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用。redis中key的原子自增incrby和判断key不存在再写入的setnx方法,可以有效的防止超发。
  • 下面使用两个不同的方式来说明利用redis做商品购买库存数量限制。
  • 业务场景很简单,就是限制抢购5个商品,模拟并发请求抢购商品,每抢购一次对应redis中的key值增加一次,通过判断限购的数量来限制抢购,抢购成功写入成功日志,失败写入失败的信息记录,通过记录的数量来判断是否超发。
  • @H_403_9@

    文件index.PHP

    <?PHP
    require_once './myRedis.PHP';
    require_once './function.PHP';
    class sendAward{
      public $conf = [];
      const V1 = 'way1';//版本一
      const V2 = 'way2';//版本二
      const AMOUNTLIMIT = 5;//抢购数量限制
      const INCRAMOUNT = 1;//redis递增数量值
      //初始化调用对应方法执行商品发放
      public function __construct($conf,$type){
        $this->conf = $conf;
        if(empty($type))
          return '';
        if($type==self::V1){
          $this->way1(self::V1);
        }elseif($type==self::V2){
          $this->way2(self::V2);
        }else{
          return '';
        }
      }
      //抢购商品方式一
      protected function way1($v){
        $redis = new myRedis($this->conf);
        $keyNmae = getKeyName($v);
        if(!$redis->exists($keyNmae)){
          $redis->set($keyNmae,0);
        }
        $currAmount = $redis->get($keyNmae);
        if(($currAmount+self::INCRAMOUNT)>self::AMOUNTLIMIT){
          writeLog("没有抢到商品",$v);
          return;
        }
        $redis->incrby($keyNmae,self::INCRAMOUNT);
        writeLog("抢到商品",$v);
      }
      //抢购商品方式二
      protected function way2($v){
        $redis = new myRedis($this->conf);
        $keyNmae = getKeyName($v);
        if(!$redis->exists($keyNmae)){
          $redis->setnx($keyNmae,0);
        }
        if($redis->incrby($keyNmae,self::INCRAMOUNT) > self::AMOUNTLIMIT){
          writeLog("没有抢到商品",$v);
          return;
        }
        writeLog("抢到商品",$v);
      }
    }
    //实例化调用对应执行方法
    $type = isset($_GET['v'])?$_GET['v']:'way1';
    $conf = [
      'host'=>'192.168.0.214','port'=>'6379','auth'=>'test','db'=>2,];
    new sendAward($conf,$type);
    

    文件myRedis.PHP

    <?PHP
    /**
     * @desc 自定义redis操作类
     * **/
    class myRedis{
      public $handler = NULL;
      public function __construct($conf){
        $this->handler = new Redis();
        $this->handler->connect($conf['host'],$conf['port']); //连接Redis
        //设置密码
        if(isset($conf['auth'])){
          $this->handler->auth($conf['auth']); //密码验证
        }
        //选择数据库
        if(isset($conf['db'])){
          $this->handler->select($conf['db']);//选择数据库2
        }else{
          $this->handler->select(0);//默认选择0库
        }
      }
      //获取key的值
      public function get($name){
        return $this->handler->get($name);
      }
      //设置key的值
      public function set($name,$value){
        return $this->handler->set($name,$value);
      }
      //判断key是否存在
      public function exists($key){
        if($this->handler->exists($key)){
          return true;
        }
        return false;
      }
      //当key不存在的设置key的值,存在则不设置
      public function setnx($key,$value){
        return $this->handler->setnx($key,$value);
      }
      //将key的数值增加指定数值
      public function incrby($key,$value){
        return $this->handler->incrBy($key,$value);
      }
    }
    

    文件function.PHP

    <?PHP
    //获取商品key名称
    function getKeyName($v)
    {
      return "send_goods_".$v;
    }
    //日志写入方法
    function writeLog($msg,$v)
    {
      $log = $msg.PHP_EOL;
      file_put_contents("log/$v.log",$log,FILE_APPEND);
    }
    

    1.ab工具并发测试way1方法

    [root@localhost oversend]# ab -c 100 -n 200 http://192.168.0.213:8083/index.PHP?v=way1
    This is ApacheBench,Version 2.3 <$Revision: 655654 $>
    Copyright 1996 Adam Twiss,Zeus Technology Ltd,http://www.zeustech.net/
    Licensed to The Apache Software Foundation,http://www.apache.org/
    Benchmarking 192.168.0.213 (be patient)
    Completed 100 requests
    Completed 200 requests
    Finished 200 requests
    Server Software:    Nginx
    Server Hostname:    192.168.0.213
    Server Port:      8083
    Document Path:     /index.PHP?v=way1
    Document Length:    0 bytes
    Concurrency Level:   100
    Time taken for tests:  0.089 seconds
    Complete requests:   200
    Failed requests:    0
    Write errors:      0
    Total transferred:   30600 bytes
    HTML transferred:    0 bytes
    Requests per second:  2243.13 [#/sec] (mean)
    Time per request:    44.581 [ms] (mean)
    Time per request:    0.446 [ms] (mean,across all concurrent requests)
    Transfer rate:     335.16 [Kbytes/sec] received
    Connection Times (ms)
           min mean[+/-sd] median  max
    Connect:    0  6  2.2   5   17
    Processing:   2  28 16.3   25   55
    Waiting:    1  26 15.2   24   50
    Total:     5  34 16.3   30   60
    Percentage of the requests served within a certain time (ms)
     50%   30
     66%   35
     75%   54
     80%   56
     90%   57
     95%   60
     98%   60
     99%   60
     100%   60 (longest request)
    

    v1方法日志分析

    [root@localhost log]# less -N way1.log
       1 抢到商品
       2 抢到商品
       3 抢到商品
       4 抢到商品
       5 抢到商品
       6 抢到商品
       7 没有抢到商品
       8 没有抢到商品
       9 没有抢到商品
       10 没有抢到商品
       11 没有抢到商品
       12 没有抢到商品
    

    观察日志发现 抢到商品的记录有6条超过正常的5条,说明超发了

    2.ab工具并发测试way2方法

    [root@localhost oversend]# ab -c 100 -n 200 http://192.168.0.213:8083/index.PHP?v=way2
    This is ApacheBench,http://www.apache.org/
    Benchmarking 192.168.0.213 (be patient)
    Completed 100 requests
    Completed 200 requests
    Finished 200 requests
    Server Software:    Nginx
    Server Hostname:    192.168.0.213
    Server Port:      8083
    Document Path:     /index.PHP?v=way2
    Document Length:    0 bytes
    Concurrency Level:   100
    Time taken for tests:  0.087 seconds
    Complete requests:   200
    Failed requests:    0
    Write errors:      0
    Total transferred:   31059 bytes
    HTML transferred:    0 bytes
    Requests per second:  2311.68 [#/sec] (mean)
    Time per request:    43.259 [ms] (mean)
    Time per request:    0.433 [ms] (mean,across all concurrent requests)
    Transfer rate:     350.58 [Kbytes/sec] received
    Connection Times (ms)
           min mean[+/-sd] median  max
    Connect:    0  6  5.4   5   13
    Processing:   3  31 16.6   30   70
    Waiting:    1  30 16.6   30   70
    Total:     5  37 18.5   32   82
    Percentage of the requests served within a certain time (ms)
     50%   32
     66%   41
     75%   45
     80%   50
     90%   68
     95%   80
     98%   81
     99%   82
     100%   82 (longest request)
    

    v2方法日志分析

    [root@localhost log]# less -N v2.log
    [root@localhost log]# less -N way2.log
       1 抢到商品
       2 抢到商品
       3 抢到商品
       4 抢到商品
       5 没有抢到商品
       6 抢到商品
       7 没有抢到商品
       8 没有抢到商品
       9 没有抢到商品
       10 没有抢到商品
    

    总结:观察日志可知抢到商品的日志记录是5条并没有超发,说明利用这种方式可以限制住库存的数量。之所以超发是因为方法一中通过加法来判断限制条件的同时,并发一大,就会越过这个判断条件出现会超发,redis的在这方面就体现优势了。

    完整代码github地址

    更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP+redis数据库程序设计技巧总结》、《PHP面向对象程序设计入门教程》、《PHP基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《PHP字符串(string)用法总结》、《PHP+MysqL数据库操作入门教程》及《PHP常见数据库操作技巧汇总》

    希望本文所述对大家PHP程序设计有所帮助。

    原文链接:https://www.f2er.com/php/525839.html

猜你在找的PHP相关文章