概述
1.我的环境是windows下的phpstudy,进入到apache/bin目录里面有个ab.exe,压力测试命令如下
./ab.exe -c 200 -n 1000 http://192.168.1.244/mysql.php
2.mysql.php代码如下
正常的逻辑思维,压力增大后,导致数据库num字段成为负数,将下面代码粘贴到自己网站下测试即可。
在test数据库下,新建一个num(库存)的表,id字段int类型主键自增,num字段int类型
新建一个goods_order(订单)的表,id字段int主键自增,goods_id字段int,user_id字段int类型,
如果发现num字段无法成为负数,打开sleep(2);访问量堆积起来即可
<?php
header("Content-type: text/html; charset=utf-8");
//pdo连接数据库方法
$dbms='mysql';
//数据库类型
$host='localhost'; //数据库主机名
$dbName='test';
//使用的数据库
$user='root';
//数据库连接用户名
$pass='root';
//对应的密码
$dsn="$dbms:host=$host;dbname=$dbName";
try {
$dbh = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8';")); //初始化一个PDO对象
echo "连接成功<br/>";
$sq="select num from num where id=1";
$rs=$dbh->query($sq);
$rs->setFetchMode(PDO::FETCH_ASSOC);
$count = $rs->fetch();
print_r($count);
//sleep(2); 如果压力不够释放此行代码,让访问量堆积,数据库num字段成负数
if($count['num']>0){
//$sql="update num set num=num-1 where id=1 and (num -1 ) >= 0";//开启此行,注释下行,无法破
$sql="update num set num=num-1 where id=1";
echo $sql;
$count = $dbh->exec($sql);
$sql2="insert into goods_order (goods_id,user_id) values(1,123456789)";
echo $sql2;
$count2 = $dbh->exec($sql2);
echo "购买成功<br />";
}
$dbh = null;
} catch (PDOException $e) {
die ("Error!: " . $e->getMessage() . "<br/>");
}
3.开启
$sql="update num set num=num-1 where id=1 and (num -1 ) >= 0";
经过测试num字段最小为0,在压力测试下代码运行正常,
想要增大ab压力并发量测试,
./ab.exe -c 500 -n 1000 http://192.168.1.244/mysql.php
会出现如下(看来要去linux下搭建apache来测试了)
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.244 (be patient)
Completed 100 requests
Total of 125 requests completed
Test aborted after 10 failures
apr_socket_connect(): ******
(730061)
4.redis测试,搭建好linux下的apache后,访问linux下的redis.php压力测试杠杠的,不会报错了
./ab.exe -c 1000 -n 1000 http://192.168.1.233/redis.php
此压力下,redis数据正常,不会出现负数:
<?php
header("content-type:text/html;charset=utf-8");
$redis = new redis();
$result = $redis->connect('192.168.1.233',"6379");
//$num = $redis->set("num",5);
//die;
$num = ($redis->get("num"));
$count=(int)$num;
echo "总共有:".$count;
echo "<br/>";
if($count>0){
//sleep(2);
$redis->set("num",$num-1);
}else{
}
var_dump($num);
?>
5.以上是ab测试,现在分析代码
先分析redis.php,上面的这个实现在只有一个客户端的时候可以执行得很好。 但是, 当多个客户端同时对同一个键进行这样的操作时, 就会产生竞争条件。举个例子, 如果客户端 A 和 B 都读取了键原来的值, 比如 2, 那么两个客户端都会将键的值设为 1 , 但正确的结果应该是 0 才对。
有了 WATCH , 我们就可以轻松地解决这类问题了:
因为redis的性能很高,当num为2时,ab模拟两个并发量后num为1,模拟两个并发量和watch如下:
./ab.exe -c 2 -n 2 http://192.168.1.233/redis.php
修复代码如下,加入watch监听,确保数据准确性:
<?php
//set('num');可以在终端执行
header("content-type:text/html;charset=utf-8");
$redis = new redis();
$result = $redis->connect('192.168.1.233',"6379");
$redis->watch("num");
$num = ($redis->get("num"));
$redis->multi();
$count=(int)$num;
echo "总共有:".$count;
echo "<br/>";
if($count>0){
//sleep(2);
$redis->set("num",$num-1);
$redis->incr("order");
$exec = $redis->exec();
//var_dump($exec);
//die;
if($exec[0]==true){
echo "抢购成功,还剩:".($count-1);
}else{
echo "很不幸,没抢到,可以再抢一把";
}
}else{
echo "活动结束";
}
//var_dump($num);
//$redis->close();
?>
设置100个库存,让100个人去抢,100个人抢到了,数据很精准:
./ab.exe -c 1000 -n 1000 http://192.168.1.233/redis.php
192.168.1.233:6379> set num 100
OK
192.168.1.233:6379> get num
"0"
192.168.1.233:6379> get order
"100"
最后
以上就是曾经大门为你收集整理的模拟测试秒杀的全部内容,希望文章能够帮你解决模拟测试秒杀所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复