>  기사  >  백엔드 개발  >  PHP에서 높은 동시성을 처리하는 방법

PHP에서 높은 동시성을 처리하는 방법

王林
王林원래의
2019-09-20 17:53:343146검색

PHP에서 높은 동시성을 처리하는 방법

높은 동시성에서의 데이터 보안

우리는 여러 스레드가 동일한 파일에 쓸 때 "스레드 안전" 문제가 발생한다는 것을 알고 있습니다. run 결과는 단일 스레드 작업의 결과와 동일합니다. 즉, 스레드로부터 안전하다는 의미입니다.

MySQL 데이터베이스인 경우 자체 잠금 메커니즘을 사용하여 문제를 해결할 수 있습니다. 그러나 대규모 동시성 시나리오에서는 MySQL을 사용하지 않는 것이 좋습니다. 플래시세일과 급세일 시나리오에는 또 다른 문제가 있는데, 바로 '과잉배송'이다. 이 부분을 잘 관리하지 않으면 과잉배송이 발생하게 된다.

일부 전자상거래 회사에서는 구매자가 주문을 성공적으로 구매한 후 판매자가 주문이 유효한 것으로 인식하지 못하고 상품 배송을 거부한다는 소식도 들었습니다. 여기서 문제는 반드시 가맹점이 배신적이라는 것이 아니라, 시스템의 기술적 수준에서 과잉 발행의 위험이 발생한다는 점일 수 있습니다.

1. 초과배송 이유

급하게 구매하는 상황에서 총 100개의 제품이 있다고 가정해 보겠습니다. 마지막 순간에 99개의 제품을 소비하고 마지막 제품만 남았습니다. 이때 시스템은 여러 개의 동시 요청을 보냈고, 이러한 요청으로 읽은 상품 잔액은 모두 99개였으며 모두 이 잔액 판단을 통과하여 결국 초과 발행으로 이어졌습니다. (기사 앞부분에서 언급한 장면과 동일)

PHP에서 높은 동시성을 처리하는 방법

2. 낙관적 잠금

Optimistic 잠금은 "비관적 잠금"에 비해 느슨한 잠금 메커니즘을 채택하며 대부분 버전 업데이트를 사용합니다. 구현에서는 이 데이터에 대한 모든 요청을 수정할 수 있지만 데이터의 버전 번호를 얻을 수 있습니다. 버전 번호가 일치하는 요청만 성공적으로 업데이트할 수 있으며 다른 요청은 실패로 반환됩니다.

이 경우 대기열 문제를 고려할 필요는 없지만 CPU의 계산 오버헤드가 증가합니다. 그러나 전반적으로 이것이 더 나은 솔루션입니다.

PHP에서 높은 동시성을 처리하는 방법

Redis의 watch와 같이 "낙관적 잠금" 기능을 지원하는 소프트웨어와 서비스가 많이 있습니다. 이 구현을 통해 우리는 데이터 보안을 보장합니다.

최적화 계획: Redis에서 시청

<?php
$redis = new redis();
 $result = $redis->connect(&#39;127.0.0.1&#39;, 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),&#39;meiqiangdao&#39;);
        echo "手气不好,再抢购!";exit;
    }
}
?>

위 내용은 참고용입니다!

추천 튜토리얼: PHP 비디오 튜토리얼

위 내용은 PHP에서 높은 동시성을 처리하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.