zoukankan      html  css  js  c++  java
  • thinkphp5使用redis实现秒杀商品活动

    如题,废话少说贴码为上↓

    // 初始化redis数据列表 模拟库存50,redis搭建在centos中已开启
    public function redisinit(){
    
        $store=50; // 库存50
        $redis=$this->redis(); //接入redis
        $redis->del('goods_store'); // 删除库存列表
        $res=$redis->llen('goods_store'); //返回库存长度,这里已经是0
        $count=$store-$res;
        for($i=0;$i<$count;$i++){
            $redis->lpush('goods_store',1); //列表推进50个,模拟50个商品库存
        }
        
    }
     // 秒杀入口
    public function kills(){
        $id = input("id"); //商品编号
        if(!$id)
            return $this->insertlog(0);//记录失败日志
        $redis = $this->redis(); // 接入redis
        $count=$redis->lpop('goods_store'); //减少库存,返回剩余库存数
        if(!$count){ //库存为0
           $this->insertlog(0); //记录秒杀失败的 日志
            return false;
        }else{// 有库存
            $ordersn = $this->build_order_no(); //订单号随机生成
            $uid = rand(0,9999); //用户id随机生成,正式项目可以启用登录的session
            $status = 1; // 订单状态
            $data = Db::name("ab_goods")->field("count,amount")->where("id",$id)->find();//查找商品
            if(!$data)
               return $this->insertlog(0); //商品不存在
            $result = Db::name("ab_order")->insert(["order_sn"=>$ordersn,"user_id"=>$uid,"goods_id"=>$id,"price"=>$data['amount'],"status"=>$status,'addtime'=>date('Y-m-d H:i:s')]); //订单入库
            $res = Db::name("ab_goods")->where("id",$id)->setDec("count"); //库存减少
            if($res)
                $this->insertlog(); //记录成功的日志
            else
                $this->insertlog(0);//记录失败的日志
    
        }
    }        
    
    //生成唯一订单
    function build_order_no(){
        return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    }
    
    // 记录日志 状态1成功 0失败
    function insertlog($status=1){
        return Db::name("ab_log")->insertGetId(["count"=>1,"status"=>$status,"addtime"=>date('Y-m-d H:i:s')]);
    }
    

    使用apache压力测试工具AB抢购商品

    AB压力测试,模拟多用户秒杀商品
    -r 指定接收到错误信息时不退出程序
    -t 等待响应的最大时间
    -n 指定压力测试总共的执行次数
    -c 用于指定压力测试的并发数
    例:秒杀商品,60秒内发起3000个请求,并发600次,接口地址 http://192.168.0.20:86/api/kill/kills/id/1
    D:wamp64inapacheapache2.4.23in>ab -r -t 60 -n 3000 -c 600 http://192.168.0.20:86/api/kill/kills/id/1
    正常的逻辑写法秒杀开始时候库存会出现负数

    命令行:D:wamp64inapacheapache2.4.23in>ab -r -t 60 -n 1000 -c 100 http://192.168.0.20:86/api/kill/kills/id/1
    60秒内发起1000个请求,并发100次,秒杀50个库存的商品,库存出现负数(-53),订单有103个!不测不知道,一测吓一跳~ 正常来说50个库存只会生成50个订单,在高并发下测试就懵逼了!

      

    用法:

    1.先跑一波库存接口(初始化50个库存):http://192.168.0.20:86/api/kill/redisinit

    2 命令行:D:wamp64inapacheapache2.4.23in>ab -r -t 60 -n 1000 -c 100 http://192.168.0.20:86/api/kill/kills/id/1

    3.如果ab测试中出现错误,该计算机关闭连接 Test aborted after 10 failures  apr_socket_con等错误请优化apache服务器,或者如下操作

    1、停止Apache服务;
    2、找到apache/conf/httpd.conf文件,用文本编辑器打开找到这两行:
    # Server-pool management (MPM specific)
    # Include conf/extra/httpd-mpm.conf
    把第二行include........这行的注释去掉。
    
    3、找到apache/conf/extra/httpd-mpm.conf文件,打开,找到:
    
    <IfModule mpm_winnt_module>
    ThreadsPerChild 150
    MaxRequestsPerChild 0
    </IfModule>
    
    把上面的150调大,Windows下最大为1920.
    注意:尖括号里的名字是winnt,不要看错了

    centos6.5安装redis指南 http://www.cnblogs.com/leisir/p/8250840.html

    如图

    运行问cmd命令后再来看看数据库

    ab_goods 库存数量count此时已经是0

    ab_order 订单表已经有了50个订单

    ab_log 日志表中有1000条记录,其中50条成功的,950条抢购失败的记录

    表3张 商品 订单 日志 ab_goods ab_order ab_log
    
    CREATE TABLE `ab_goods` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `count` int(11) NOT NULL DEFAULT '0',
      `status` tinyint(1) DEFAULT NULL,
      `title` varchar(255) DEFAULT NULL,
      `amount` decimal(10,2) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    
    
    CREATE TABLE `ab_log` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `addtime` datetime DEFAULT NULL,
      `status` tinyint(1) DEFAULT NULL,
      `count` int(10) unsigned DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8;
    
    CREATE TABLE `ab_order` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `order_sn` varchar(50) NOT NULL,
      `user_id` int(10) NOT NULL,
      `goods_id` int(10) NOT NULL,
      `price` decimal(10,2) NOT NULL,
      `status` tinyint(1) DEFAULT '0',
      `addtime` datetime DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8;
  • 相关阅读:
    局域网内其他机器访问本机80网站失败记录
    百度经纬度获取
    Win10安装安卓ADB驱动
    SQL Server 查看数据库是否存在阻塞
    IP地址接口小结
    雄冠条码PV系统-2016-05-17-收获
    slf4j MDC使用
    Java NIO之通道
    Java NIO之缓冲区
    记一次ThreadPoolExecutor面试
  • 原文地址:https://www.cnblogs.com/leisir/p/8359998.html
Copyright © 2011-2022 走看看