PHP秒杀功能,需要解决超抢和多抢的问题,利用redis的单线程和集合数据不重复的特点可以较好的解决这两个问题
// 秒杀策略 ab -n 1000 -c 100 http://*****/Index/miao_sha
static $redis = null;
public function miao_sha(){
if (!$redis) $redis = new \Think\Cache\Driver\Redis;
// 随机生成用户
$user_id = rand(0,1000);
// 修改$rad_id 便于多次测试
$rad_id = '11';
// 如果是第一次访问,设置库存订单数据
$has_set_order = $redis->get('has_set'.$rad_id);
// 用户等待集合,使用集合防止同一个用户多次访问
$user_wait_key = "user_wait".$rad_id;
// 保存抢购成功的用户
$user_key = "user".$rad_id;
// 库存队列
$store_key = "goods_store".$rad_id;
if (!$has_set_order){
$redis->set('has_set'.$rad_id,1);
$num = 100;
for ($i=0;$i<$num;$i++){
$redis->rPush($store_key,'1');
}
}
// 集合 防止多抢和超抢 redis队列可以防止多并发超抢,因为redis是单线程,使用集合防止存储重复用户id
$result = $redis->sAdd($user_wait_key,$user_id);
if ($result){
// 取出库存中的数据
$count = $redis->lpop($store_key);
if (!$count){
echo '已经抢光'.$user_id;
}else{
$redis->hset($user_key,$user_id,$user_id);
echo '恭喜您抢到了'.$user_id;
}
}
// list 会出现同一个用户抢到多个的情况。会出现同一个用户多次抢到的情况,ab命令行并发执行
// $result = $redis->rPush($wait_key,$user_id);
// if ($result){
// $count = $redis->lpop($store_key);
// if (!$count){
// echo '已经抢光了哦'.$user_id;
// }else{
// $result = $redis->rPush($user_key,$user_id);
// echo '恭喜您抢到了'.$user_id;
// }
// }
}
// 获取秒杀信息
public function get_ms_info(){
static $redis = null;
if (!$redis) $redis = new \Think\Cache\Driver\Redis;
$rad_id = '11';
$user_key = "user".$rad_id;
// die(json_encode(($redis->lGetRange($user_key,0,-1))));
die(json_encode(($redis->hGetAll($user_key))));
}
网友评论