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