Home > Backend Development > PHP Tutorial > How to solve the product super phenomenon when using redis flash sale?

How to solve the product super phenomenon when using redis flash sale?

WBOY
Release: 2016-10-17 09:30:08
Original
1202 people have browsed it

Recently I was doing a flash sale event, and for the sake of performance and response speed, I used redis. When I was writing, I paid special attention to preventing supernormal phenomena. I used cas (check and set) optimistic locking based on redis theory. I thought that this problem should be able to eliminate it, but it still occurred. I was very confused and asked for help. The specific code is roughly as follows:

<code><?php  
header("content-type:text/html;charset=utf-8");  
$redis = new redis();  
$result = $redis->connect('10.10.10.119', 6379);  
$mywatchkey = $redis->get("mywatchkey");  
$rob_total = 100;   //抢购数量  
if($mywatchkey<$rob_total){  
    $redis->watch("mywatchkey");  
    $redis->multi();  
      
    //设置延迟,方便测试效果。  
    sleep(5);  
    //插入抢购数据  
    $redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time());  
    $redis->set("mywatchkey",$mywatchkey+1);  
    $rob_result = $redis->exec();  
    if($rob_result){  
        $mywatchlist = $redis->hGetAll("mywatchlist");  
        echo "抢购成功!<br/>";  
        echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>";  
        echo "用户列表:<pre class="brush:php;toolbar:false">";  
        var_dump($mywatchlist);  
    }else{  
        echo "手气不好,再抢购!";exit;  
    }  
}  
?>  
</code>
Copy after login
Copy after login

Reply content:

Recently I was doing a flash sale event, and for the sake of performance and response speed, I used redis. When I was writing, I paid special attention to preventing supernormal phenomena. I used cas (check and set) optimistic locking based on redis theory. I thought that this problem should be able to eliminate it, but it still occurred. I was very confused and asked for help. The specific code is roughly as follows:

<code><?php  
header("content-type:text/html;charset=utf-8");  
$redis = new redis();  
$result = $redis->connect('10.10.10.119', 6379);  
$mywatchkey = $redis->get("mywatchkey");  
$rob_total = 100;   //抢购数量  
if($mywatchkey<$rob_total){  
    $redis->watch("mywatchkey");  
    $redis->multi();  
      
    //设置延迟,方便测试效果。  
    sleep(5);  
    //插入抢购数据  
    $redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time());  
    $redis->set("mywatchkey",$mywatchkey+1);  
    $rob_result = $redis->exec();  
    if($rob_result){  
        $mywatchlist = $redis->hGetAll("mywatchlist");  
        echo "抢购成功!<br/>";  
        echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>";  
        echo "用户列表:<pre class="brush:php;toolbar:false">";  
        var_dump($mywatchlist);  
    }else{  
        echo "手气不好,再抢购!";exit;  
    }  
}  
?>  
</code>
Copy after login
Copy after login

I think this code will still be oversold under high concurrency conditions. Suppose: When there is only 1 prize left, three people execute $redis->watch("mywatchkey") at the same time and the data they get is 99, then there is an oversold phenomenon.

Since redis is a single-threaded read, then use the simplest queue implementation.

  1. Before drawing the lottery, write the number of prizes into the redisqueueaward:100 // A list with a length of 100, the value is only used as whether you win the prize

  2. Concurrent Lottery

<code>$award = $redis->lpop('award:100'); // 由于队列只有100个值,可以确保只有100个人中奖
if(!$award){
    echo "手气不好,再抢购!";exit;  
}

// 剩下就是中奖操作的事情了</code>
Copy after login

sleep(5);
Does your company still accept people?

Think about this situation.
mywatchkey=99
User A requests mywatchkey and gets 99.
User B requests mywatchkey and gets 99.
When A and B requests are completed, what should mywatchkey be? . 101, or 100?

This is a classic Check-then-Act error

First of all, let me ask you if the "oversold" result of this code is $mywatchkey > 100 (I think it is impossible)
Or when $mywatchkey = 100, two pages appear at the same time "Successful purchase!"
I have no idea about this The code is tested, I just guess whether it will be the following situation:

1.Session A: Perform mywatchkey check, at this time mywatchkey = 99

2.Session B: After processing mywatchkey, mywatchkey=100 at this time, but it does not affect the subsequent operations of Session A

Add two more connections, take a look, you might gain something

transactions-and-watch-statement-in-redis
redis-watch-multi-exec-by-one-client

If you want to fundamentally solve this matter, please study first:

1. Lock.

2. Traditional database transactions.

Then learn the difference between Redis and traditional databases.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template