您的位置:首页 > 数据库 > Redis

Redis实现高并发下的抢购,秒杀,解决方案

2017-11-08 10:40 615 查看
在电子商务发达的今天,各种秒杀,抢购活动的场景不少,如何解决高并发下出现的订单超发情况呢?

在常规情况下,我们会根据用户提交的请求去查询商品库存,如果库存小于0则订单生成失败。但是这种情况下经常了订单需要的数量超过了库存数量,即出现负库存。

先讨论常规场景测试:

我们在redis中设置一个库存表,就是个简单的string类型, 用以标示库存即可。 

set inventory 100

使用多进程测试如下:因为我的AB测试不能用。所以使用多进程的方式进行

//register a signal
pcntl_signal(SIGCHLD, SIG_IGN);

$times = 200;
while ($times-- > 0) {
$pid = pcntl_fork();
if ($pid > 0) {
} else {
order();
die;
}
}
sleep(20);
function order() {
$conn = new Redis;
//connect redis
$conn->connect("127.0.0.1", 6379);
$inventory = $conn->get('inventory');
//由于本地服务过访问过快。所以休息50毫秒真实模拟高并发
usleep(50000);
if ($inventory > 0) {
$conn->decr("inventory");
} else {
echo "抢购失败!";
}
die;
}


执行结果变为了负数:



如何解决这个问题呢? 熟悉redis 的同学都知道 redis 支持事务,我们加个事务试试。

<?php

//register a signal
pcntl_signal(SIGCHLD, SIG_IGN);

$times = 200;
while ($times-- > 0) {
    $pid = pcntl_fork();
    if ($pid > 0) {
    } else {
        order();
        die;
    }
}
sleep(20);
function order() {
    $conn = new Redis;
    //connect redis
    $conn->connect("127.0.0.1", 6379);
    $inventory = $conn->get('inventory');
    $conn->multi();
    //由于本地服务过访问过快。所以休息50毫秒真实模拟高并发
    usleep(50000);
    if ($inventory > 0) {
        $conn->decr("inventory");
        $conn->exec();
    } else {
        echo "抢购失败!";
    }
    die;
}

?>


同样结果还是会变成负数。 

接下来可以使用redis 的watch 实现一个乐观锁来试试

<?php

//register a signal
pcntl_signal(SIGCHLD, SIG_IGN);

$times = 200;
while ($times-- > 0) {
$pid = pcntl_fork();
if ($pid > 0) {
} else {
order();
die;
}
}
sleep(20);
function order() {
$conn = new Redis;
//connect redis
$conn->connect("127.0.0.1", 6379);

do {
//watch inventory
$conn->watch('inventory');
$inventory = $conn->get('inventory');
//由于本地服务过访问过快。所以休息50毫秒真实模拟高并发
usleep(50000);
if ($inventory <= 0) {
echo "抢购失败!";
break;
}
$conn->multi();
$conn->decr("inventory");

} while ($conn->exec());

die;
}

?>


执行结果:
大致场景就是这样的, 如果是抢购,每次只抢购一个 可以往队列里添加库存个商品的1 队列, 如图:



当用户每次抢购抛出一个队列,然后再去减少真正的库存即可。  当然真实的场景要稍复杂一些, 不过原理就是这样的。 

成功!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息