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


Posted in PHP onSeptember 19, 2019

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

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

文件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, 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=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 相关文章推荐
PHP 反射机制实现动态代理的代码
Oct 22 PHP
谈PHP生成静态页面分析 模板+缓存+写文件
Aug 17 PHP
php 应用程序安全防范技术研究
Sep 25 PHP
php url地址栏传中文乱码解决方法集合
Jun 25 PHP
php 文件上传实例代码
Apr 19 PHP
9段PHP实用功能的代码推荐
Oct 14 PHP
Thinkphp将二维数组变为标签适用的一维数组方法总结
Oct 30 PHP
PHP实现从远程下载文件的方法
Mar 12 PHP
php计算两个日期相差天数的方法
Mar 14 PHP
详解YII关联查询
Jan 10 PHP
PHP实现linux命令tail -f
Feb 22 PHP
PHP获取MySQL执行sql语句的查询时间方法
Aug 21 PHP
php+redis实现消息队列功能示例
Sep 19 #PHP
php文件包含的几种方式总结
Sep 19 #PHP
smarty模板的使用方法实例分析
Sep 18 #PHP
PHP MVC框架中类的自动加载机制实例分析
Sep 18 #PHP
PHP切割整数工具类似微信红包金额分配的思路详解
Sep 18 #PHP
php实现多站点共用session实现单点登录的方法详解
Sep 18 #PHP
PHP实现批量修改文件名的方法示例
Sep 18 #PHP
You might like
php str_pad 函数用法简介
2009/07/11 PHP
php中生成随机密码的自定义函数代码
2013/10/21 PHP
C#使用PHP服务端的Web Service通信实例
2014/04/08 PHP
php中debug_backtrace、debug_print_backtrace和匿名函数用法实例
2014/12/01 PHP
php中smarty变量修饰用法实例分析
2015/06/11 PHP
PHP读取配置文件类实例(可读取ini,yaml,xml等)
2015/07/28 PHP
PHP浮点数的一个常见问题
2016/03/10 PHP
Alliance vs Liquid BO3 第一场2.13
2021/03/10 DOTA
JavaScript 组件之旅(三):用 Ant 构建组件
2009/10/28 Javascript
关于JAVASCRIPT urldecode URL解码的问题
2012/01/08 Javascript
js控制CSS样式属性语法对照表
2012/12/11 Javascript
js中substring和substr的详细介绍与用法
2013/08/29 Javascript
js和jquery设置disabled属性为true使按钮失效
2014/08/07 Javascript
js实现字符串转日期格式的方法
2015/05/20 Javascript
实例讲解使用原生JavaScript处理AJAX请求的方法
2016/05/10 Javascript
JS实现的表格行上下移动操作示例
2016/08/03 Javascript
Javascript设计模式之装饰者模式详解篇
2017/01/17 Javascript
nodejs搭建本地服务器并访问文件的方法
2017/03/03 NodeJs
详解vue-cli构建项目反向代理配置
2017/09/07 Javascript
JavaScript如何获取到导航条中HTTP信息
2017/10/10 Javascript
微信小程序swiper使用网络图片不显示问题解决
2019/12/13 Javascript
js实现二级联动简单实例
2020/01/11 Javascript
[48:12]Secret vs Optic Supermajor 胜者组 BO3 第三场 6.4
2018/06/05 DOTA
Python中用Descriptor实现类级属性(Property)详解
2014/09/18 Python
Python爬虫模拟登录带验证码网站
2016/01/22 Python
Python字符串格式化输出方法分析
2016/04/13 Python
简单了解Python读取大文件代码实例
2019/12/18 Python
NumPy统计函数的实现方法
2020/01/21 Python
利用jupyter网页版本进行python函数查询方式
2020/04/14 Python
办公室副主任岗位职责
2013/11/25 职场文书
某同学的自我鉴定范文
2013/12/26 职场文书
自我鉴定四大框架
2014/01/17 职场文书
社区学习雷锋活动总结
2014/04/25 职场文书
硕士研究生就业推荐信
2014/05/18 职场文书
公司离职证明范本(汇总)
2014/09/10 职场文书
【HBU】数据库第四周 单表查询
2021/04/05 SQL Server