高同時実行時のデータ セキュリティ
複数のスレッドが同じファイルに書き込む場合、「スレッド セーフ」が存在することがわかっています (複数のスレッド同じコードを同時に実行します。各実行の結果が単一スレッドの実行の結果と同じであり、結果が期待どおりであれば、スレッドセーフです)。
MySQL データベースの場合は、独自のロック メカニズムを使用して問題を解決できますが、大規模な同時実行シナリオでは MySQL はお勧めできません。フラッシュセールやラッシュセールのシナリオには、「過剰納品」というもう 1 つの問題があり、この点を慎重に制御しないと過剰納品が発生します。
一部の電子商取引会社では、購入者が写真撮影に成功した後、販売者が注文が有効であると認識せず、商品の配送を拒否するパニック買い行為を行っていると聞いています。ここでの問題は、必ずしも販売業者が不正であるということではなく、システムの技術レベルでの過剰発行のリスクによって引き起こされる可能性があります。
1. 過剰納品の理由
特定の急ぎ購入シナリオで、製品が合計で 100 個しかなく、最後の瞬間に、 99 個の商品を消費しました。最後の 1 個だけが残っています。このとき、システムは複数のリクエストを同時に送信し、そのリクエストで読み取った商品残高が99個すべてで残高判定を通過し、最終的に発行過剰に陥ってしまいました。 (記事の前半で説明したシーンと同じです)
2. 楽観的ロック
楽観的ロックは、「悲観的」と比較して使用されます。 lock" より緩和されたロック メカニズムでは、主にバージョンの更新が使用されます。実装では、このデータに対するすべてのリクエストが変更可能ですが、データのバージョン番号が取得されます。バージョン番号が一致しているもののみが正常に更新され、その他のリクエストは失敗に返されます。
この場合、キューの問題を考慮する必要はありませんが、CPU の計算オーバーヘッドが増加します。ただし、全体的には、これはより良い解決策です。
「楽観的ロック」機能をサポートするソフトウェアやサービスは多数あり、Redis の watch もその 1 つです。この実装により、データのセキュリティが確保されます。
最適化計画: Redis で見る
<?php $redis = new redis(); $result = $redis->connect('127.0.0.1', 6379); echo $mywatchkey = $redis->get("mywatchkey"); /* //插入抢购数据 if($mywatchkey>0) { $redis->watch("mywatchkey"); //启动一个新的事务。 $redis->multi(); $redis->set("mywatchkey",$mywatchkey-1); $result = $redis->exec(); if($result) { $redis->hSet("watchkeylist","user_".mt_rand(1,99999),time()); $watchkeylist = $redis->hGetAll("watchkeylist"); echo "抢购成功!<br/>"; $re = $mywatchkey - 1; echo "剩余数量:".$re."<br/>"; echo "用户列表:<pre class="brush:php;toolbar:false">"; print_r($watchkeylist); }else{ echo "手气不好,再抢购!";exit; } }else{ // $redis->hSet("watchkeylist","user_".mt_rand(1,99999),"12"); // $watchkeylist = $redis->hGetAll("watchkeylist"); echo "fail!<br/>"; echo ".no result<br/>"; echo "用户列表:<pre class="brush:php;toolbar:false">"; // var_dump($watchkeylist); }*/ $rob_total = 100; //抢购数量 if($mywatchkey<=$rob_total){ $redis->watch("mywatchkey"); $redis->multi(); //在当前连接上启动一个新的事务。 //插入抢购数据 $redis->set("mywatchkey",$mywatchkey+1); $rob_result = $redis->exec(); if($rob_result){ $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),$mywatchkey); $mywatchlist = $redis->hGetAll("watchkeylist"); echo "抢购成功!<br/>"; echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>"; echo "用户列表:<pre class="brush:php;toolbar:false">"; var_dump($mywatchlist); }else{ $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),'meiqiangdao'); echo "手气不好,再抢购!";exit; } } ?>
上記の内容は参考用です。
推奨チュートリアル: PHP ビデオ チュートリアル
以上がPHPでの高い同時実行性に対処する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。