Maison >base de données >Redis >Comment utiliser PHP+Redis pour résoudre le problème de la survente de produits en cas de concurrence élevée
Pour certains sites e-commerce ayant un certain nombre d'utilisateurs, s'ils utilisent simplement des bases de données relationnelles (comme MySQL, Oracle) pour des achats urgents, la pression sur la base de données sera très forte, et si le verrouillage de la base de données est mal utilisé, le mécanisme entraînera également le problème des produits et des coupons survendus. Mon entreprise a également rencontré le même problème. Le problème s'est produit lorsque les coupons ont été achetés en trop grande quantité. Après que le problème soit survenu, nous avons commencé à réfléchir à des moyens de résoudre le problème. Comme j'utilise beaucoup Redis, je prévois d'utiliser Redis pour résoudre ce problème. . Utilisez les fonctionnalités de haute performance et de transaction de Redis pour résoudre le problème des coupons en ligne récupérés par surstock. Ci-dessous, je donne la première version du pseudo-code que j'ai temporairement résolu ce problème, avec certains détails supprimés :
/** * 抢优惠券(秒杀) * @param int $couponId 商品ID * @param int $uid 用户ID * @return bool */ function secKill($couponId, $uid) { //1.初始化Redis连接 $redis = new Redis(); if (!$redis->connect('127.0.0.1', 6379)) { trigger_error('Redis连接出错!!!', E_USER_ERROR); } else { echo '连接正常<br>'; } //秒杀商品的库存key $key = 'secKill:'.$couponId.':stock'; $redis->watch($key); //获取库存 $stock = $redis->get($key); //秒杀未开始,表示库存为null if (!$stock && !is_numeric($stock)) { echo '秒杀未开始'; return false; } //判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束 if ($stock <= 0) { echo '秒杀已结束'; return false; } //用户已经成功秒杀过一次了,不允许再次参与秒杀 if ($redis->sIsMember('secKill:'.$couponId.':uid', $uid)) { echo '秒杀失败'; return false; } //代码走到这里,说明该用户是第一次参与秒杀,将库存减一,然后把这个人放到已抢到的集合表 $redisMulti = $redis->multi(); $redisMulti->decr($key); $redisMulti->sAdd('secKill:'.$couponId.':uid', $uid); $result = $redisMulti->exec(); if (empty($result)) {//事务被取消 echo '秒杀失败'; return false; } //抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券 $redis->lPush('couponOrder', $couponId.'+'.$uid); return true; } $couponId = 11211; $uid = mt_rand(1, 100); secKill($couponId, $uid);#. 🎜 🎜#Tout d'abord, j'ai simulé la définition de l'inventaire des coupons avec l'ID de coupon 11211 à 10. Ensuite, nous utilisons l'outil ab pour simuler 1000 requêtes et 50 simultanéités pour tester
ab -n 1000 -c 50 www.test.com/Ensuite nous utilisons Redis Desktop Manager pour afficher certains résultats Redis couponOrder Il y a déjà 10 informations utilisateur dans la file d'attente et il y a des réductions Le reste le nombre de coupons est également 0, ce n'est plus un nombre négatif En même temps, les informations UID de 10 utilisateurs sont également enregistrées dans le coupon utilisateur collection. La chaîne de codes ci-dessus résout deux problèmes :
#🎜 🎜#Astuce : Dans la file d'attente de consommation, si le coupon ne parvient pas à être émis, assurez-vous de l'enregistrer immédiatement et d'informer le responsable des opérations par SMS pour voir s'il peut être renvoyé ou poussé manuellement à l’utilisateur via l’arrière-plan.
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!