Maison > développement back-end > tutoriel php > Explication détaillée de la façon dont PHP gère les demandes à haute concurrence pour les achats urgents

Explication détaillée de la façon dont PHP gère les demandes à haute concurrence pour les achats urgents

php中世界最好的语言
Libérer: 2023-03-26 18:54:01
original
2656 Les gens l'ont consulté

Cette fois, je vais vous apporter une explication détaillée de la mise en œuvre de la gestion par PHP des demandes d'achat urgentes à haute concurrence. Quelles sont les précautions pour gérer les demandes d'achat urgentes à haute concurrence en PHP. Ce qui suit est un cas pratique, jetons un coup d'oeil.

Cet article prend comme exemples les ventes urgentes et les ventes flash. Présentez comment garantir l’exactitude des données dans des conditions de concurrence élevée.
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.

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 '恭喜你,订单<b>'.$order.'</b>抢购成功';
      }
    }else{
      echo '已被抢购一空!';
    }
  }
Copier après la connexion

Après avoir défini l'inventaire de produits sur 20, configurez une demande simultanée de 200 via ab.

ab -n 200 -c 200 http//localhost/highly/normal
Copier après la connexion

Le résultat de l'exécution a révélé que l'inventaire est devenu négatif et que le produit a été 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 l'inventaireType de données

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('stock')->where(['goods_id'=>100001])->asArray()->one();
    // 判断该商品是否还有库存
    if ($stock['stock']>0) {
      // 库存减一
      if(Goods::updateAllCounters(['stock' => -1],['goods_id'=>100001])===false){
        echo "已被抢购一空!";
        return false;
      }
      // 生产订单(另外功能,暂且随机赋值)
      $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 '已被抢购一空!';
    }
  }
Copier après la connexion

Cette fois, la même concurrence de 200 a été trouvée, et les résultats d'exécution ont été 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('mytest',1);
    $order = $this->build_order();
    // echo $order;die;
    // echo $redis->llen('mytest');
    $reg = $redis->lpop('mytest');
    if (!$reg) {
      echo "笨蛋!已经被抢光啦!";
      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();
  }
Copier après la connexion

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.

Je pense que vous maîtrisez la méthode après avoir lu le cas dans cet article. Pour des informations plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de php !

Lecture recommandée :

Explication détaillée des étapes d'implémentation du téléchargement de fichiers php+ajax sans actualisation

Implémentation PHP de l'algorithme de tri de tableaux multidimensionnels a de quelles manières

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal