높은 동시성에서의 데이터 보안
우리는 여러 스레드가 동일한 파일에 쓸 때 "스레드 안전" 문제가 발생한다는 것을 알고 있습니다. run 결과는 단일 스레드 작업의 결과와 동일합니다. 즉, 스레드로부터 안전하다는 의미입니다.
MySQL 데이터베이스인 경우 자체 잠금 메커니즘을 사용하여 문제를 해결할 수 있습니다. 그러나 대규모 동시성 시나리오에서는 MySQL을 사용하지 않는 것이 좋습니다. 플래시세일과 급세일 시나리오에는 또 다른 문제가 있는데, 바로 '과잉배송'이다. 이 부분을 잘 관리하지 않으면 과잉배송이 발생하게 된다.
일부 전자상거래 회사에서는 구매자가 주문을 성공적으로 구매한 후 판매자가 주문이 유효한 것으로 인식하지 못하고 상품 배송을 거부한다는 소식도 들었습니다. 여기서 문제는 반드시 가맹점이 배신적이라는 것이 아니라, 시스템의 기술적 수준에서 과잉 발행의 위험이 발생한다는 점일 수 있습니다.
1. 초과배송 이유
급하게 구매하는 상황에서 총 100개의 제품이 있다고 가정해 보겠습니다. 마지막 순간에 99개의 제품을 소비하고 마지막 제품만 남았습니다. 이때 시스템은 여러 개의 동시 요청을 보냈고, 이러한 요청으로 읽은 상품 잔액은 모두 99개였으며 모두 이 잔액 판단을 통과하여 결국 초과 발행으로 이어졌습니다. (기사 앞부분에서 언급한 장면과 동일)
2. 낙관적 잠금
Optimistic 잠금은 "비관적 잠금"에 비해 느슨한 잠금 메커니즘을 채택하며 대부분 버전 업데이트를 사용합니다. 구현에서는 이 데이터에 대한 모든 요청을 수정할 수 있지만 데이터의 버전 번호를 얻을 수 있습니다. 버전 번호가 일치하는 요청만 성공적으로 업데이트할 수 있으며 다른 요청은 실패로 반환됩니다.
이 경우 대기열 문제를 고려할 필요는 없지만 CPU의 계산 오버헤드가 증가합니다. 그러나 전반적으로 이것이 더 나은 솔루션입니다.
Redis의 watch와 같이 "낙관적 잠금" 기능을 지원하는 소프트웨어와 서비스가 많이 있습니다. 이 구현을 통해 우리는 데이터 보안을 보장합니다.
최적화 계획: 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!