随着电商业务的发展,秒杀是个十分常见的场景,今天我们来利用Redis实现一个简单的秒杀系统。
假定我们有一个商品id为1,秒杀数量是5。
一般场景:
include 'db.php'; $db = new db([ 'database_type' => 'mysql', 'database_name' => 'test', 'server' => 'www.puresai.com', 'username' => 'puresai', 'password' => '*', 'charset' => 'utf8' ]);
$stock_num= $db->get('goods', 'stock_num', ['id' => 1]);
// 检测库存 if ($stock_num> 0) { sleep(1); //模拟真实环境 $db->update('goods', ["stock_num[-]" => 1], ['id' => 1]); print_r('ok') } else { print_r('sorry') }
|
我们尝试模拟高并发场景,使用ab压测工具,
ab -n 500 -c 500 http://www.puresai.com/test/miaosha.php
运行后发现库存stock_num很可能已经变成负数了,出现了超卖问题。
引入Redis
//实例化Redis $Redis = new Redis(); //连接 $Redis->connect('127.0.0.1', 6379); $key = 'sale'; //检测是否连接成功 // echo "Server is running: " . $Redis->ping(); $Redis->setnx($key, 0); $Redis->watch($key); //监测一个key的值是否被更改
$sale_num = $Redis->get($key); if ($sale_num > 4) { exit(); }
$Redis->multi(); //标记事务 $Redis->incr($key); //销量+1 sleep(1); //模拟真实环境 $ret = $Redis->exec(); // 事务块内所有命令的返回值,按命令执行的先后顺序排列。 if ($ret) { include 'db.php'; $db = new db([ 'database_type' => 'mysql', 'database_name' => 'test', 'server' => 'www.puresai.com', 'username' => 'puresai', 'password' => '*', 'charset' => 'utf8' ]); $db->update('goods', ["stock_num[-]" => 1], ['id' => 1]); }
|
重新增加库存到5,多次测试,发现库存并无出现负数情况,测试通过。