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

Comment utiliser PHP+Redis pour résoudre le problème de la survente de produits en cas de concurrence élevée

WBOY
WBOYavant
2023-05-26 15:31:061806parcourir

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 &#39;连接正常<br>&#39;;
    }

    //秒杀商品的库存key
    $key = &#39;secKill:&#39;.$couponId.&#39;:stock&#39;;
    $redis->watch($key);

    //获取库存
    $stock = $redis->get($key);

    //秒杀未开始,表示库存为null
    if (!$stock && !is_numeric($stock)) {
        echo &#39;秒杀未开始&#39;;
        return false;
    }

    //判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束
    if ($stock <= 0) {
        echo &#39;秒杀已结束&#39;;
        return false;
    }

    //用户已经成功秒杀过一次了,不允许再次参与秒杀
    if ($redis->sIsMember(&#39;secKill:&#39;.$couponId.&#39;:uid&#39;, $uid)) {
        echo &#39;秒杀失败&#39;;
        return false;
    }

    //代码走到这里,说明该用户是第一次参与秒杀,将库存减一,然后把这个人放到已抢到的集合表
    $redisMulti = $redis->multi();
    $redisMulti->decr($key);
    $redisMulti->sAdd(&#39;secKill:&#39;.$couponId.&#39;:uid&#39;, $uid);
    $result = $redisMulti->exec();

    if (empty($result)) {//事务被取消
        echo &#39;秒杀失败&#39;;
        return false;
    }

    //抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券
    $redis->lPush(&#39;couponOrder&#39;, $couponId.&#39;+&#39;.$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.

Comment utiliser PHP+Redis pour résoudre le problème de la survente de produits en cas de concurrence élevée

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

Comment utiliser PHP+Redis pour résoudre le problème de la survente de produits en cas de concurrence élevée

et il y a des réductions Le reste le nombre de coupons est également 0, ce n'est plus un nombre négatif

Comment utiliser PHP+Redis pour résoudre le problème de la survente de produits en cas de concurrence élevée

En même temps, les informations UID de 10 utilisateurs sont également enregistrées dans le coupon utilisateur collection.

Comment utiliser PHP+Redis pour résoudre le problème de la survente de produits en cas de concurrence élevée

La chaîne de codes ci-dessus résout deux problèmes :

  • résout le problème instantané A un grand nombre de requêtes ont causé beaucoup de pression sur la base de données et le trafic a été intercepté dans la couche de cache Redis

  • Résolu le problème des coupons récupérés en raison d'un excès Inventaire# 🎜🎜#

  • Cependant, ce code présente également certains problèmes :

    n'utilise pas le pool de connexion Redis et le crée fréquemment Le nouveau redis a un certain impact sur les performances
  1. En raison de l'utilisation de transactions, un seul utilisateur réussira à récupérer le coupon dans chaque demande simultanée, et les autres utilisateurs dans la demande simultanée, tout échouera et vous ne pourrez qu'attendre la deuxième simultanéité
  2. C'est aussi un problème d'inventaire causé par la transaction s'il y a 10 produits. et 1 000 requêtes à chaque fois, la simultanéité sera de 200. 5 requêtes simultanées complèteront 1 000 requêtes, mais seuls 5 utilisateurs réussiront à les récupérer. S'il n'y a pas de requêtes ultérieures, il restera 5 copies dans l'inventaire
  3. #. 🎜🎜#

    #🎜 🎜#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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer