DWQA QuestionsCategory: ProgramUse redis seckilling product overshoot phenomenon solution?
phplife asked 3 weeks ago

Redis was recently used in a seckilling activity for performance and response speed. When I wrote it, I paid special attention to put an end to the phenomenon of overoccurrence. The optimistic lock of cas (check and set) based on redis theory was supposed to put an end to this problem, but it still appeared. I was confused and asked for help from god.

<?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; // buying quantity  
if($mywatchkey<$rob_total){  
    $redis->watch("mywatchkey");  
    $redis->multi();  
      
    // set the delay to test the effect.  
    sleep(5);  
    // insert snap data  
    $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 "success! < br / > ";  
        Echo "remaining number: ".($rob_total-$mywatchkey-1)."<br/>";  
        Echo "user list: <pre>";  
        var_dump($mywatchlist);  
    }else{  
        Echo "bad luck, buy again!" ; The exit;  
    }  
}  
?>
13 Answers
liguoyi answered 3 weeks ago

I think this code is still oversold in the case of high concurrency. Suppose: when there is only 1 prize, have 3 people to execute at the same time$redis->watch("mywatchkey")The data that gets is 99, appear then oversold phenomenon.
Due to theredisIs a single thread read, so let’s use the simplest queue implementation.

  1. Write down the number of prizes before drawingredisThe queueaward:100// list of length 100, the value of which is simply a winning list
  2. Concurrent draw
$award = $redis - > lpop (' award: 100 '); // since the queue has only 100 values, it is guaranteed that only 100 people will win
if(!$award){
    Echo "bad luck, buy again!" ; The exit;  
}

// the rest is the operation of the lottery
phplife replied 3 weeks ago

“If three people execute $redis->watch(“mywatchkey”) at the same time and the data is 99, it will be oversold.”Shouldn’t only one of the three people execute successfully and the other two execs fail?

Xiao yong answered 3 weeks ago

Pro test, with ab pressure test concurrent 500 request 4000 no oversold!
<?php
header(“content-type:text/html;charset=utf-8”);
$redis = new redis();
$result = $redis->connect(‘127.0.0.1’, 7379);
$redis->watch(“mywatchlist”);
$len = $redis->hlen(“mywatchlist”);
$rob_total = 100; // buying quantity
if ($len < $rob_total) {

$redis->multi();
$redis->hSet("mywatchlist", "user_id_" . mt_rand(1, 999999), time());
$rob_result = $redis->exec();
file_put_contents("log.txt", $len . PHP_EOL, FILE_APPEND);
if ($rob_result) {
    $mywatchlist = $redis->hGetAll("mywatchlist");
    Echo "success! < br / > ";
    Echo "remaining number:". ($rob_total - $len - 1). "<br/>";
    Echo "user list: <pre>";
    var_dump($mywatchlist);
} else {
    Echo "bad luck, buy again!" ;
    exit;
}

} else {

Echo "sold out!" ;
exit;

}
?>

Poor old man answered 3 weeks ago

Redis used incorrectly. Concurrency should be of redis list queue type. Do not control in code

A little brother answered 3 weeks ago

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

chen19901225 answered 3 weeks ago

Consider this situation.
mywatchkey=99
User A requests mywatchkey and gets 99,
User B requests mywatchkey to get 99,
What should mywatchkey be when A and B request is completed? 101 or 100?