Maison  >  Article  >  base de données  >  Comment utiliser la liste chaînée Redis pour résoudre le problème des produits survendus avec une concurrence élevée

Comment utiliser la liste chaînée Redis pour résoudre le problème des produits survendus avec une concurrence élevée

王林
王林avant
2023-05-27 13:01:191074parcourir

Principe d'implémentation

Utilisez la liste chaînée Redis pour le faire, car l'opération pop est atomique, même si de nombreux utilisateurs arrivent en même temps, ils seront exécutés dans l'ordre, ce qui est recommandé.

Étapes de mise en œuvre

La première étape consiste à mettre l'inventaire du produit dans la file d'attente

/**
 * 添加商品数量到商品队列
 * @param int $couponId 优惠券ID
 */
function addCoupons($couponId)
{
    //1.初始化Redis连接
    $redis = new Redis();
    if (!$redis->connect('127.0.0.1', 6379)) {
        trigger_error('Redis连接出错!!!', E_USER_ERROR);
    } else {
        echo &#39;连接正常<br>&#39;;
    }

    //根据优惠券ID从数据库中查询该优惠券的库存量
    //$sql = "select id, stock from coupon where id = {$couponId}";
    $stock = 10; //假设10就是我们从数据库中查询出的该优惠券在数据库中的库存量

    //我们现在将这10个库存放入到以该商品ID为key的redis链表中,有几件库存,就存入多少次1,链表长度代表商品库存数
    for($i = 0; $i < $stock; $i++) {
        $redis->lPush("secKill:".$couponId.":stock", 1);
    }

    $redis->close();
}
$couponId = 11211;
addCoupons($couponId);

Nous appelons cette méthode, puis vérifions redis, 10 éléments ont été ajoutés à la liste chaînée

Comment utiliser la liste chaînée Redis pour résoudre le problème des produits survendus avec une concurrence élevée

La deuxième étape consiste à démarrez le rush et définissez l'inventaire La période de mise en cache

Cette étape est déterminée en fonction de votre propre entreprise. Si l'entreprise stipule que le coupon sera libéré pendant 2 minutes pour que les utilisateurs puissent le récupérer, définissez une période de validité pour la liste chaînée via. la méthode expire(). Même s'il n'est pas récupéré pendant la période de validité, il y aura toujours L'inventaire n'est pas autorisé à être récupéré par les utilisateurs (puisque les activités de notre entreprise ne fixent pas la période de validité pour la saisie des coupons, je n'ai pas besoin de le faire). faites cette étape)

//设置链表有效期是两分钟
$redis->expire(&#39;key&#39;, 120);

La troisième étape, le client effectue l'opération de capture instantanée

/**
 * 抢优惠券(秒杀)
 * @param int $couponId 商品ID
 * @param int $uid 用户ID
 * @return bool
 */
function secKill($couponId, $uid)
{
    //1.初始化Redis连接
    $redis = new Redis();
    if (!$redis->connect(&#39;127.0.0.1&#39;, 6379)) {
        trigger_error(&#39;Redis连接出错!!!&#39;, E_USER_ERROR);
    } else {
        echo &#39;连接正常<br>&#39;;
    }

    //将已经成功抢购的用户添加到该以该商品ID为key的集合(set)中
    //如果用户已经在集合中,说明用户已经成功秒杀过一次了,不允许再次参与秒杀
    if ($redis->sIsMember(&#39;secKill:&#39;.$couponId.&#39;:uid&#39;, $uid)) {
        echo &#39;秒杀失败&#39;;
        return false;
    }

    //秒杀商品的库存key
    $key = &#39;secKill:&#39;.$couponId.&#39;:stock&#39;;

    //从以该优惠券ID为key的链表中弹出一个值,如果有值,证明优惠券还有库存
    $isSockNotEmpty = $redis->lPop($key);

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

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

    //将成功抢券的用户记录到集合中,防止被已抢过的用户再次秒杀
    $redis->sAdd(&#39;secKill:&#39;.$couponId.&#39;:uid&#39;, $uid);
    $redis->close();
    return true;
}

$couponId = 11211;
$uid      = mt_rand(1, 100);
secKill($couponId, $uid);

La quatrième étape sera réussie. Les utilisateurs de la vente Flash saisissent des données persistantes dans la base de données pour les achats qui n'ont pas une grande quantité de concurrence. , nous pouvons directement écrire les informations dans la base de données après un achat réussi à la troisième étape. Pour ceux qui ont une concurrence relativement importante, elles peuvent être placées dans la file d'attente de messages RabbitMQ pour consommation (raison recommandée pour utiliser la file d'attente RabbitMQ au lieu de). redis est que RabbitMQ peut garantir que les messages sont consommés à 100 %, tandis que redis est relativement moins stable et fiable)

//此处代码省略
//根据自己的业务场景看看是入数据库还是放入rabbitMQ消息队列中消费

Maintenant, nous utilisons l'outil ab pour simuler le comportement de capture de coupons dans des conditions de concurrence élevée (2000 requêtes, 100 concurrence)

ab -n 2000 -c 100 www.test.com/

Ensuite, nous utilisons Redis Desktop Manager pour afficher les résultats Redis

De même, il y a déjà 10 informations contenant l'UID de l'utilisateur et l'ID du coupon dans la file d'attente couponOrder, qui peuvent être consommées par la file d'attente.

Comment utiliser la liste chaînée Redis pour résoudre le problème des produits survendus avec une concurrence élevée

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

Comment utiliser la liste chaînée Redis pour résoudre le problème des produits survendus avec une concurrence élevée

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