Maison  >  Article  >  développement back-end  >  Comment PHP gère-t-il des requêtes simultanées élevées pour les fonctions snap-up ?

Comment PHP gère-t-il des requêtes simultanées élevées pour les fonctions snap-up ?

小云云
小云云original
2018-02-09 09:15:582448parcourir

Il est facile d'avoir deux problèmes avec les paramètres sous des demandes simultanées élevées

1. Des erreurs de données conduisent à des produits survendus.

2. Les opérations fréquentes sur la base de données entraînent une dégradation des performances.

Cet article vous présente principalement en détail comment PHP gère les requêtes à haute concurrence pour les fonctions snap-up. Il a une certaine valeur de référence. Les amis intéressés peuvent s'y référer.

Environnement de test

Windows7
apache2.4.9
php5.5.12
php framework yii2.0
Outil apache bench (apache depuis Avec des outils de requêtes simultanées élevées).

Méthode de traitement habituelle

L'idée de code est visible depuis le contrôleur. Vérifiez d’abord l’inventaire des produits. Si l'inventaire est supérieur à 0, l'inventaire est réduit de 1, les commandes sont produites en même temps et les données des acheteurs urgents sont saisies.


// 常规代码处理高并发
  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]);

      // 生产订单(另外功能,暂且随机赋值)
      $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 &#39;恭喜你,订单<b>&#39;.$order.&#39;</b>抢购成功&#39;;
      }

    }else{
      echo &#39;已被抢购一空!&#39;;
    }
  }

Après avoir défini l'inventaire de produits sur 20, configurez les demandes simultanées de 200 à ab.


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

Le résultat de l'exécution a révélé que l'inventaire était devenu négatif et que le produit était survendu.

La raison est relativement simple, sous un nombre élevé de requêtes simultanées. Avant de produire des commandes et de réduire les stocks, les résultats de l'inventaire seront d'abord interrogés.

Optimisation 1 : Modifier le type de données d'inventaire

La première méthode d'optimisation commence par la base de données. Les résultats de la requête étant inexacts, je vais essayer de réduire l'inventaire. Modifiez le type de données de l'inventaire en non signé (ne peut pas avoir de valeurs négatives).

Le code est toujours similaire à celui ci-dessus, sauf qu'un jugement est porté lorsque l'inventaire est réduit de 1. Évitez de signaler les erreurs.


public function actionNormal(){
    // 查询库存
    $stock = Goods::find()->select(&#39;stock&#39;)->where([&#39;goods_id&#39;=>100001])->asArray()->one();
    // 判断该商品是否还有库存
    if ($stock[&#39;stock&#39;]>0) {
      // 库存减一
      if(Goods::updateAllCounters([&#39;stock&#39; => -1],[&#39;goods_id&#39;=>100001])===false){
        echo "已被抢购一空!";
        return false;
      }

      // 生产订单(另外功能,暂且随机赋值)
      $order = $this->build_order();

      // 秒杀信息入库
      $model = new Highly();
      $model->order_id = $order;
      $model->goods_name = &#39;秒杀商品&#39;;
      $model->buy_time = date(&#39;Y-m-d H:i:s&#39;,time());
      $model->mircrotime = microtime(true);
      if($model->save()===false){
        echo &#39;未能成功抢购!&#39;;
      }else{
        echo &#39;恭喜你,订单<b>&#39;.$order.&#39;</b>抢购成功&#39;;
      }

    }else{
      echo &#39;已被抢购一空!&#39;;
    }
  }

Cette fois, les mêmes 200 simultanéités, les résultats d'exécution sont trouvés. Les données sont correctes et il n’y a pas de situation de survente.
L'idée est en fait relativement simple. Parce que l'inventaire ne peut pas être négatif, lorsque l'inventaire est égal à 0, s'il y a encore des valeurs transmises, une erreur sera signalée. La demande a été interrompue.

Cette méthode d'optimisation évite la survente des produits. Mais d’un autre côté, les demandes exercent toujours une pression sur la base de données. Si plusieurs fonctions utilisent cette base de données, les performances chuteront considérablement.

Optimisation 2 : redis

Utiliser l'atomicité du type pop de liste redis. Avant d'exploiter la base de données, effectuez une vérification. Lorsque les marchandises sont épuisées, aucune autre opération de base de données n'est autorisée.


// redis list 高并发测试
  public function actionRedis(){
    $redis = \Yii::$app->redis;
    // $redis->lpush(&#39;mytest&#39;,1);
    $order = $this->build_order();
    // echo $order;die;
    // echo $redis->llen(&#39;mytest&#39;);
    $reg = $redis->lpop(&#39;mytest&#39;);
    if (!$reg) {
      echo "笨蛋!已经被抢光啦!";
      return false;
    }
    $redis->close();
    $model = new Highly();
    $model->order_id = $order;
    $model->goods_name = &#39;秒杀商品&#39;;
    $model->buy_time = date(&#39;Y-m-d H:i:s&#39;,time());
    $model->mircrotime = microtime(true);

    if($model->save()===false){
      echo &#39;未能成功抢购!&#39;;
    }else{
      echo &#39;恭喜你,订单<b>&#39;.$order.&#39;</b>抢购成功&#39;;
    }
  }
  // 给redis添加商品
  public function actionInsertgoods(){
    $count = yii::$app->request->get(&#39;count&#39;,0);
    if (empty($count)) {
      echo &#39;大兄弟,你还没告诉我需要上架多少商品呢!&#39;;
      return false;
    }
    $redis = \Yii::$app->redis;
    for ($i=0; $i < $count; $i++) { 
      $redis->lpush(&#39;mytest&#39;,1);
    }
    echo &#39;成功添加了&#39;.$redis->llen(&#39;mytest&#39;).&#39;件商品。&#39;;
    $redis->close();

  }

Pour ce code, j'ai écrit deux méthodes. La première méthode est le code de vente flash et la deuxième méthode consiste à définir la quantité des produits de vente flash. Afin de faciliter les tests, ce que je gère ici est relativement simple.

Après tests, le nombre de commandes produites par la base de données est normal et il n'y a aucun problème. Cela évite le problème de dégradation des performances provoqué par la requête de la base de données. Dans le même temps, la vitesse de requête de la base de données en mémoire Redis est beaucoup plus rapide que celle de MySQL.

Recommandations associées :

implémentation en nœud unique du principe de haute concurrence

PHP et Redis implémentent des statistiques d'enregistrement à haute concurrence

Explication détaillée d'exemples de fonctions d'achat urgent et de vente flash sous haute concurrence utilisant PHP et Redis

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn