Maison > Questions et réponses > le corps du texte
新客领取优惠券逻辑
判断是否新客
若为新客 查询数据库是否已领取过
未领取过 给用户发券
同一用户并发领券的情况下 会有超领的情况 因为并发进来时查询数据库均没有领取记录
而又不能针对用户和优惠券做唯一索引 因为有些券允许用户领取多张。
于是决定采用redis计数来防同一用户并发超领 新客领券逻辑改成如下
判断是否新客
若为新客 基于用户ID计数 incr {user_id}_receive_count
如果计数大于1 表示同一用户并发领券 直接返回
如果计数==1 表示第一次领取
查询数据库是否已领取过
未领取过 给用户发券
上述逻辑没有问题 但纠结该如何设置计数key的过期时间
设置过期时间为1分钟
基本上大部分并发操作都是在同一秒 过期时间1分钟能满足要求了
设置过期时间为1小时
万一数据库负载高呢 并不能在一分钟内完成一次领券事务操作 如双十一这种场景 还是设的长一点 更保险一点 不管怎样 1小时足够完成一次领券事务操作了吧 但时间设的长了 会不会因为其他原因(如网络超时)导致领券失败回滚 用户要等一小时后 才能重新领券
有没其他防并发领取方案呢? 可以不用纠结这种过期时间的设置呢。
PHP中文网2017-04-27 09:04:40
Il est recommandé de séparer le jugement de la prévention d'une concurrence excessive et celui de juger si un nouveau client est un nouveau client
Le super collier anti-concurrence peut être utilisé comme suit (verrouillé) N'oubliez pas de supprimer la clé (libérer le verrou) une fois chaque opération terminée
// 操作的原子性,如该key在有效时间30秒被设置过返回0,一般请求超时为30秒
$redis->set($key, 1, array("NX", "EX"=>'30'));
Pour déterminer s'il s'agit d'un nouveau client (si l'utilisateur l'a déjà reçu, l'heure de validité est fixée à la fin de l'événement), vous pouvez définir une nouvelle CLÉ comme statut de réception de l'utilisateur, et elle sera directement restitué à l'utilisateur qui a bénéficié de la remise (poursuite de Pour des performances concurrentes, la requête de base de données n'est pas connectée)
Obtenez le coupon (mettez le coupon dans la file d'attente à l'avance et récupérez-le dans la file d'attente, pas dans la base de données. L'avantage ici est que les données de la file d'attente disparaîtront une fois récupérées, et il y aura pas de situation de réception excessive), écrivez Entrez la file d'attente redis
File d'attente de consommation du processus en arrière-plan, j'utilise le type de blocage de liste chaînée pour la consommation (stocker les informations de collecte dans la base de données, puis interroger et déterminer si l'utilisateur a reçu le coupon avant d'entrer dans la base de données)
黄舟2017-04-27 09:04:40
Le plan précis reste à mettre en œuvre en fonction des métiers
Si l'entreprise n'exige pas 100%, chaque personne ne peut recevoir qu'un seul coupon, et votre cluster Redis est hautement disponible. Il suffit alors de le bloquer avec Redis
, le délai d'expiration spécifique de la clé, etc. . Le téléchargement de l'activité sera globalement invalide, car il s'agit d'une solution qui ne rentre pas dans la bibliothèque, donc si vous devez déterminer s'il faut répéter la demande, vous devez vous fier aux données de Redis (et si Redis se bloque). up ? Bien que Redis ait une fonction de persistance imparfaite, la perte La quantité de données est relativement faible, si l'entreprise le permet, elle est toujours acceptable), mais de nombreux scénarios commerciaux nécessitent une journalisation
Les exigences commerciales exigent qu'une personne ait un coupon (la valeur nominale du coupon peut être très importante), j'utiliserai donc toujours la solution Redis
du sujet. Après avoir jugé que c'est la première fois, insérez/mettez à jour directement la base de données (il y aura des solutions asynchrones ici, mais des solutions asynchrones apparaîtront également. Les solutions asynchrones auront également des problèmes similaires à 1 : perte de données. Selon cette solution, on peut garantir que chaque personne ne peut que recevoir). un coupon (déterminé par la base de données) assure la cohérence des données). Comme l'a dit l'intervenant, en fait, vous n'avez pas besoin d'invalider les éléments dans Redis, car si un utilisateur demande à plusieurs reprises et de manière malveillante de tirer des coupons, Redis peut le bloquer directement sans accéder à la base de données pour interroger (il y a un autre problème ici. La solution consiste à mettre à jour le cache d'abord. Mettez à jour à nouveau la base de données, vous devez donc considérer la situation anormale dans laquelle la mise à jour du cache réussit mais la mise à jour de la base de données échoue. Si la base de données est anormale, vous devez vider le cache correspondant à la clé. )
Si vous ne pouvez vraiment pas le gérer (le matériel ne peut pas suivre), vous pouvez utiliser des files d'attente pour résoudre le problème et utiliser des files d'attente pour réduire le pic
La solution de @大woo est également réalisable, mais vous devez considérer Redis
cette situation anormale à un certain moment
滿天的星座2017-04-27 09:04:40
La fonction mentionnée par @大woo est en fait similaire aux ventes flash. J'ai déjà écrit un article. Vous pouvez y jeter un oeil :
Fonctions essentielles pour les produits e-commerce : ventes flash et enchères
淡淡烟草味2017-04-27 09:04:40
Je suis ivre si vous osez utiliser une base de données nosql pour ce genre de chose.
Il est recommandé d'apprendre d'abord la théorie des bases de données, en se concentrant sur le concept de transactions, plusieurs niveaux d'isolation des transactions, les verrous de lignes et de tables, puis d'utiliser une base de données relationnelle traditionnelle pour ce faire.
Si les performances d'un serveur de base de données ne suffisent pas, alors concevez une architecture de tables horizontales, avec différents serveurs, chaque serveur étant responsable d'une partie des données utilisateur. La source théorique de la table de niveaux est le chapitre de hachage des structures de données de premier cycle. Vous pouvez y jeter un œil.