Heim > Backend-Entwicklung > PHP-Tutorial > Wie kann das Produkt-Super-Phänomen bei der Verwendung von Redis Flash Sale gelöst werden?

Wie kann das Produkt-Super-Phänomen bei der Verwendung von Redis Flash Sale gelöst werden?

WBOY
Freigeben: 2016-10-17 09:30:08
Original
1201 Leute haben es durchsucht

Kürzlich habe ich eine Flash-Sale-Veranstaltung durchgeführt und aus Gründen der Leistung und Reaktionsgeschwindigkeit habe ich Redis verwendet. Beim Schreiben habe ich besonders darauf geachtet, übernatürliche Phänomene zu verhindern. Ich habe die optimistische Sperre (Cas) verwendet, die auf der Redis-Theorie basiert. Ich dachte, dass dieses Problem behoben werden sollte, aber es trat immer noch auf und um Hilfe gebeten. Der spezifische Code lautet ungefähr wie folgt:

<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>
Nach dem Login kopieren
Nach dem Login kopieren

Antwortinhalt:

Kürzlich habe ich eine Flash-Sale-Veranstaltung durchgeführt und aus Gründen der Leistung und Reaktionsgeschwindigkeit habe ich Redis verwendet. Beim Schreiben habe ich besonders darauf geachtet, übernatürliche Phänomene zu verhindern. Ich habe die optimistische Sperre (Cas) verwendet, die auf der Redis-Theorie basiert. Ich dachte, dass dieses Problem behoben werden sollte, aber es trat immer noch auf und um Hilfe gebeten. Der spezifische Code lautet ungefähr wie folgt:

<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>
Nach dem Login kopieren
Nach dem Login kopieren

Ich denke, dass dieser Code unter Bedingungen hoher Parallelität immer noch überverkauft sein wird. Angenommen: Wenn nur noch 1 Preis übrig ist, drei Personen gleichzeitig $redis->watch("mywatchkey") ausführen und die Daten, die sie erhalten, 99 sind, liegt ein Überverkaufsphänomen vor.

Da es sich bei redis um einen Single-Threaded-Lesevorgang handelt, verwenden wir die einfachste Warteschlangenimplementierung.

  1. Schreiben Sie vor der Lotterie die Anzahl der Preise in die redisWarteschlangeaward:100 // Eine Liste mit einer Länge von 100, der Wert wird nur dazu verwendet, ob der Preis gewonnen wird

  2. Gleichzeitige Ziehungen

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

// 剩下就是中奖操作的事情了</code>
Nach dem Login kopieren

sleep(5);
Akzeptiert Ihr Unternehmen noch Menschen?

Bedenken Sie diese Situation.
mywatchkey=99
Benutzer A fordert mywatchkey an und erhält 99.
Benutzer B fordert mywatchkey an und erhält 99.
Nachdem die Anforderungen von A und B abgeschlossen sind, wie sollte mywatchkey lauten? . 101 oder 100?

Dies ist ein klassischer Check-then-Act-Fehler

Lassen Sie mich zunächst fragen, ob das „überverkaufte“ Ergebnis dieses Codes $mywatchkey > 100 ist (ich denke, das ist unmöglich)
Oder wenn $mywatchkey =100, erscheinen zwei Seiten gleichzeitig“ Erfolgreicher Kauf!“
Ich habe diesen Code nicht getestet, ich habe nur vermutet, ob es der folgende sein würde:

1. Sitzung A: Mywatchkey-Prüfung durchführen, zu diesem Zeitpunkt ist mywatchkey = 99

2. Sitzung B: Nach der Verarbeitung von mywatchkey ist mywatchkey zu diesem Zeitpunkt = 100, hat jedoch keinen Einfluss auf die nachfolgenden Vorgänge von Sitzung A

Fügen Sie zwei weitere Verbindungen hinzu, werfen wir einen Blick darauf, vielleicht gewinnen Sie etwas

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

Wenn Sie dieses Problem grundlegend lösen möchten, lesen Sie bitte zuerst:

1. Sperren.

2. Traditionelle Datenbanktransaktionen.

Dann lernen Sie den Unterschied zwischen Redis und herkömmlichen Datenbanken kennen.

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage