php如何處理搶購類功能的高并發(fā)請求-創(chuàng)新互聯(lián)

這篇文章將為大家詳細講解有關(guān)php如何處理搶購類功能的高并發(fā)請求,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

成都創(chuàng)新互聯(lián)是網(wǎng)站建設(shè)專家,致力于互聯(lián)網(wǎng)品牌建設(shè)與網(wǎng)絡(luò)營銷,專業(yè)領(lǐng)域包括做網(wǎng)站、網(wǎng)站建設(shè)、電商網(wǎng)站制作開發(fā)、小程序開發(fā)、微信營銷、系統(tǒng)平臺開發(fā),與其他網(wǎng)站設(shè)計及系統(tǒng)開發(fā)公司不同,我們的整合解決方案結(jié)合了恒基網(wǎng)絡(luò)品牌建設(shè)經(jīng)驗和互聯(lián)網(wǎng)整合營銷的理念,并將策略和執(zhí)行緊密結(jié)合,且不斷評估并優(yōu)化我們的方案,為客戶提供全方位的互聯(lián)網(wǎng)品牌整合方案!

本文以搶購、秒殺為例。介紹如何在高并發(fā)狀況下確保數(shù)據(jù)正確。
在高并發(fā)請求下容易參數(shù)兩個問題
1.數(shù)據(jù)出錯,導(dǎo)致產(chǎn)品超賣。
2.頻繁操作數(shù)據(jù)庫,導(dǎo)致性能下降。

測試環(huán)境

Windows7
apache2.4.9
php5.5.12
php框架 yii2.0
工具 apache bench (apache自帶高并發(fā)請求工具)。

通常處理方法

從控制器可以看出代碼思路。先查詢商品庫存。如果庫存大于0 ,則庫存減少1,同時生產(chǎn)訂單,錄入搶購者數(shù)據(jù)。

// 常規(guī)代碼處理高并發(fā)
  public function actionNormal(){
    // 查詢庫存
    $stock = Goods::find()->select('stock')->where(['goods_id'=>100001])->asArray()->one();
    // 判斷該商品是否還有庫存
    if ($stock['stock']>0) {
      // 庫存減一
      Goods::updateAllCounters(['stock' => -1],['goods_id'=>100001]);

      // 生產(chǎn)訂單(另外功能,暫且隨機賦值)
      $order = $this->build_order();

      // 秒殺信息入庫
      $model = new Highly();
      $model->order_id = $order;
      $model->goods_name = '秒殺商品';
      $model->buy_time = date('Y-m-d H:i:s',time());
      $model->mircrotime = microtime(true);
      if($model->save()===false){
        echo '未能成功搶購!';
      }else{
        echo '恭喜你,訂單<b>'.$order.'</b>搶購成功';
      }

    }else{
      echo '已被搶購一空!';
    }
  }

將商品庫存設(shè)置為20后,通過ab 配置200的并發(fā)請求。

ab -n 200 -c 200 http//localhost/highly/normal

執(zhí)行結(jié)果發(fā)現(xiàn)庫存變成了負值,商品超賣了。


php如何處理搶購類功能的高并發(fā)請求

原因比較簡單,在高并發(fā)請求下。在生產(chǎn)訂單,減少庫存之前,會優(yōu)先查詢到庫存結(jié)果。

優(yōu)化一:修改庫存數(shù)據(jù)類型

第一種優(yōu)化方法,從數(shù)據(jù)庫入手。既然查詢到的結(jié)果不準(zhǔn)確,那我就在庫存減少上做手腳。將庫存的數(shù)據(jù)類型改成無符號(不能有負值)。


代碼還是跟上面差不多,只是在庫存減1的地方做了個判斷。避免報錯。

public function actionNormal(){
    // 查詢庫存
    $stock = Goods::find()->select('stock')->where(['goods_id'=>100001])->asArray()->one();
    // 判斷該商品是否還有庫存
    if ($stock['stock']>0) {
      // 庫存減一
      if(Goods::updateAllCounters(['stock' => -1],['goods_id'=>100001])===false){
        echo "已被搶購一空!";
        return false;
      }

      // 生產(chǎn)訂單(另外功能,暫且隨機賦值)
      $order = $this->build_order();

      // 秒殺信息入庫
      $model = new Highly();
      $model->order_id = $order;
      $model->goods_name = '秒殺商品';
      $model->buy_time = date('Y-m-d H:i:s',time());
      $model->mircrotime = microtime(true);
      if($model->save()===false){
        echo '未能成功搶購!';
      }else{
        echo '恭喜你,訂單<b>'.$order.'</b>搶購成功';
      }

    }else{
      echo '已被搶購一空!';
    }
  }

這一次同樣200的并發(fā),執(zhí)行結(jié)果發(fā)現(xiàn)。數(shù)據(jù)正確,并不會出現(xiàn)超賣的情況。
思路其實也比較簡單。因為庫存不能為負值,當(dāng)庫存等于0時,如果還有值傳進來,則會報錯。請求被終止。

這種優(yōu)化方式,雖然避免了商品超賣的情況。但是在另一方面,請求仍然會對數(shù)據(jù)庫造成壓力。如果多個功能使用此數(shù)據(jù)庫,會造成性能下降厲害。

優(yōu)化二:redis

利用 redis list類型的pop的原子性。在操作數(shù)據(jù)庫前,做一個驗證。當(dāng)商品賣完后,就不允許再繼續(xù)進行數(shù)據(jù)庫操作。

// redis list 高并發(fā)測試
  public function actionRedis(){
    $redis = \Yii::$app->redis;
    // $redis->lpush('mytest',1);
    $order = $this->build_order();
    // echo $order;die;
    // echo $redis->llen('mytest');
    $reg = $redis->lpop('mytest');
    if (!$reg) {
      echo "笨蛋!已經(jīng)被搶光啦!";
      return false;
    }
    $redis->close();
    $model = new Highly();
    $model->order_id = $order;
    $model->goods_name = '秒殺商品';
    $model->buy_time = date('Y-m-d H:i:s',time());
    $model->mircrotime = microtime(true);

    if($model->save()===false){
      echo '未能成功搶購!';
    }else{
      echo '恭喜你,訂單<b>'.$order.'</b>搶購成功';
    }
  }
  // 給redis添加商品
  public function actionInsertgoods(){
    $count = yii::$app->request->get('count',0);
    if (empty($count)) {
      echo '大兄弟,你還沒告訴我需要上架多少商品呢!';
      return false;
    }
    $redis = \Yii::$app->redis;
    for ($i=0; $i < $count; $i++) { 
      $redis->lpush('mytest',1);
    }
    echo '成功添加了'.$redis->llen('mytest').'件商品。';
    $redis->close();

  }

這點的代碼,我寫了兩個方法。第一個方法是秒殺的代碼,第二個方法是給秒殺的商品設(shè)置數(shù)量。為了方便測試,我這里處理的比較簡單。

通過測試,數(shù)據(jù)庫生產(chǎn)的訂單數(shù)量正常,并沒有出現(xiàn)問題。而又避免了請求數(shù)據(jù)庫造成性能下降的問題。同時內(nèi)存數(shù)據(jù)庫redis查詢的速度要比mysql快很多。

關(guān)于“php如何處理搶購類功能的高并發(fā)請求”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

網(wǎng)站標(biāo)題:php如何處理搶購類功能的高并發(fā)請求-創(chuàng)新互聯(lián)
分享網(wǎng)址:http://bm7419.com/article46/iiheg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)定制開發(fā)、商城網(wǎng)站、軟件開發(fā)、網(wǎng)站收錄、手機網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)