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>
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>
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.
Schreiben Sie vor der Lotterie die Anzahl der Preise in die redis
Warteschlangeaward:100
// Eine Liste mit einer Länge von 100, der Wert wird nur dazu verwendet, ob der Preis gewonnen wird
Gleichzeitige Ziehungen
<code>$award = $redis->lpop('award:100'); // 由于队列只有100个值,可以确保只有100个人中奖 if(!$award){ echo "手气不好,再抢购!";exit; } // 剩下就是中奖操作的事情了</code>
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.