首頁  >  文章  >  後端開發  >  php如何處理高並發

php如何處理高並發

王林
王林原創
2019-09-24 17:54:003671瀏覽

php如何處理高並發

高並發下的資料安全性

我們知道在多執行緒寫入同一個檔案的時候,會存現“執行緒安全”的問題(多個執行緒同時運行同一段程式碼,如果每次運行結果和單執行緒運行的結果是一樣的,結果和預期相同,就是執行緒安全的)。如果是MySQL資料庫,可以使用它自帶的鎖定機制很好的解決問題,但是,在大規模並發的場景中,是不建議使用MySQL的。

秒殺和搶購的場景中,還有另一個問題,就是“超發”,如果在這方面控制不慎,會產生發送過多的情況。我們也曾經聽說過,某些電商搞搶購活動,買家成功拍攝後,商家卻不承認訂單有效,拒絕出貨。這裡的問題,也許不一定是商家姦詐,而是系統技術層面有超發風險所導致的。

1、超發的原因

假設某個搶購場景中,我們一共只有100個商品,在最後一刻,我們已經消耗了99個商品,僅剩最後一個。這時候,系統發來多個並發請求,這批請求讀取到的商品餘裕都是99個,然後都通過了這一個餘量判斷,最終導致超發。 (同文章前面說的場景)

php如何處理高並發

在上面的這個圖中,就導致了並髮用戶B也“搶購成功”,多讓一個人獲得了商品。這種場景,在高並發的情況下非常容易出現。

最佳化方案1:將庫存欄位number欄位設為unsigned,當庫存為0時,因為欄位不能為負數,將會傳回false

<?php
//优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false
include(&#39;./mysql.php&#39;);
$username = &#39;wang&#39;.rand(0,1000);
//生成唯一订单
function build_order_no(){
  return date(&#39;ymd&#39;).substr(implode(NULL, array_map(&#39;ord&#39;, str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0,$username){
    global $conn;
    $sql="insert into ih_log(event,type,usernma)
    values(&#39;$event&#39;,&#39;$type&#39;,&#39;$username&#39;)";
    return mysqli_query($conn,$sql);
}
function insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number)
{
      global $conn;
      $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price,username,number)
      values(&#39;$order_sn&#39;,&#39;$user_id&#39;,&#39;$goods_id&#39;,&#39;$sku_id&#39;,&#39;$price&#39;,&#39;$username&#39;,&#39;$number&#39;)";
     return  mysqli_query($conn,$sql);
}
//模拟下单操作
//库存是否大于0
$sql="select number from ih_store where goods_id=&#39;$goods_id&#39; and sku_id=&#39;$sku_id&#39; ";
$rs=mysqli_query($conn,$sql);
$row = $rs->fetch_assoc();
  if($row[&#39;number&#39;]>0){//高并发下会导致超卖
      if($row[&#39;number&#39;]<$number){
        return insertLog(&#39;库存不够&#39;,3,$username);
      }
      $order_sn=build_order_no();
      //库存减少
      $sql="update ih_store set number=number-{$number} where sku_id=&#39;$sku_id&#39; and number>0";
      $store_rs=mysqli_query($conn,$sql);
      if($store_rs){
          //生成订单
          insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number);
          insertLog(&#39;库存减少成功&#39;,1,$username);
      }else{
          insertLog(&#39;库存减少失败&#39;,2,$username);
      }
  }else{
      insertLog(&#39;库存不够&#39;,3,$username);
  }
?>

#2.檔案鎖的想法

對於日IP不高或說並發數不是很大的應用,一般不用考慮這些!用一般的文件操作方法完全沒有問題。但如果並發高,在我們對文件進行讀寫操作時,很有可能多個進程對進一文件進行操作,如果這時不對文件的存取進行相應的獨佔,就容易造成數據丟失。

優化方案4:使用非阻塞的檔案排他鎖

<?php
//优化方案4:使用非阻塞的文件排他锁
include (&#39;./mysql.php&#39;);
//生成唯一订单号
function build_order_no(){
  return date(&#39;ymd&#39;).substr(implode(NULL, array_map(&#39;ord&#39;, str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
    global $conn;
    $sql="insert into ih_log(event,type)
    values(&#39;$event&#39;,&#39;$type&#39;)";
    mysqli_query($conn,$sql);
}
$fp = fopen("lock.txt", "w+");
if(!flock($fp,LOCK_EX | LOCK_NB)){
    echo "系统繁忙,请稍后再试";
    return;
}
//下单
$sql="select number from ih_store where goods_id=&#39;$goods_id&#39; and sku_id=&#39;$sku_id&#39;";
$rs =  mysqli_query($conn,$sql);
$row = $rs->fetch_assoc();
if($row[&#39;number&#39;]>0){//库存是否大于0
    //模拟下单操作
    $order_sn=build_order_no();
    $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
    values(&#39;$order_sn&#39;,&#39;$user_id&#39;,&#39;$goods_id&#39;,&#39;$sku_id&#39;,&#39;$price&#39;)";
    $order_rs =  mysqli_query($conn,$sql);
    //库存减少
    $sql="update ih_store set number=number-{$number} where sku_id=&#39;$sku_id&#39;";
    $store_rs =  mysqli_query($conn,$sql);
    if($store_rs){
      echo &#39;库存减少成功&#39;;
        insertLog(&#39;库存减少成功&#39;);
        flock($fp,LOCK_UN);//释放锁
    }else{
      echo &#39;库存减少失败&#39;;
        insertLog(&#39;库存减少失败&#39;);
    }
}else{
  echo &#39;库存不够&#39;;
    insertLog(&#39;库存不够&#39;);
}
fclose($fp);
 ?>

推薦教學:PHP影片教學

以上是php如何處理高並發的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn