针对一些有一定用户数量的电子商务网站,假如仅仅单纯性的应用关联型数据库(如MySQLOracle)来做抢购,对数据库的工作压力是十分大的,并且如果不应用好数据库的锁体制,还会造成产品、优惠券超售的难题。我所属的企业也碰到了一样的难题,难题产生在优惠券被超额抢购上,在难题产生后大家刚开始想办法解决难题,因为自身应用redis比较多,我提前准备应用redis来解决这个问题。运用redis的性能卓越和事务管理特点来解决网上优惠券被超库存量抢购的难题,下边我得出我临时性解决这个问题的第一版的伪代码,除掉了一些关键点:

/**
 * 抢优惠券(击杀)
 * @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;
 }

 //编码来到这儿,表明该客户是第一次参加击杀,将库存量减一,随后把这个人放进已抢得的结合表
 //multi(),回到一个redis目标,并进到multi-mode方式,一旦进到multi-mode方式,之后启用的全部方式都是会回到同样的目标,
 //直至exec()方式被启用。
 $result = $redis->multi()->decr($key)->sAdd('secKill:'.$couponId.':uid', $uid)->exec();

 if (empty($result)) {//事务管理被撤销
 echo '击杀不成功';
 return false;
 }

 //抢券取得成功,将优惠券ID和UID放进到序列中,由一个独立的过程序列来消費序列里的数据信息,向客户消息推送抢得的优惠券
 $redis->lPush('couponOrder', $couponId.' '.$uid);

 $redis->close();
 return true;
}

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

最先,我仿真模拟设定优惠券ID为11211的优惠券库存量为10个。

PHP+Redis事务解决高并发下商品超卖问题(推荐) 商品超卖 高并发 事务 redis php PHP编程  第1张

随后,大家应用ab专用工具来仿真模拟1000次要求,50并发量来检测

ab -n 1000 -c 50 www.test.com/

随后大家根据Redis Desktop Manager来查询一些Redis的結果

couponOrder序列里早已拥有10个客户的信息内容了

PHP+Redis事务解决高并发下商品超卖问题(推荐) 商品超卖 高并发 事务 redis php PHP编程  第2张

而且优惠券的剩下总数也是0了,已不是负值了

PHP+Redis事务解决高并发下商品超卖问题(推荐) 商品超卖 高并发 事务 redis php PHP编程  第3张

另外,客户抢券结合里也储存了10个客户的UID信息内容。

PHP+Redis事务解决高并发下商品超卖问题(推荐) 商品超卖 高并发 事务 redis php PHP编程  第4张

上边这串编码解决了2个难题:

  • 解决了瞬间的很多查寻到数据库上给数据库导致非常大工作压力的难题,总流量都被阻拦在了redis缓存文件
  • 解决了优惠券被超库存量抢购的难题

可是,这一段编码也存有一定的难题:

  1. 沒有应用redis数据库连接池,经常建立新的redis有一定的特性危害
  2. 因为应用了事务管理,每一次高并发要求中总是有一个客户抢券取得成功,该高并发要求中的其他客户都是会不成功,只有等第二次高并发
  3. 一样還是事务管理造成的库存量遗留,如果有10个产品,1000次要求每一次200并发量,5次高并发要求就完成了1000次要求,可是总是有五个客户取得成功抢到,要是没有事后的要求,会造成库存量也有5份总量

提醒:在消費序列里,假如优惠券派发不成功,一定要马上纪录并短信提醒经营技术人员,看一下是不是能再发或是根据后台管理手动式定项消息推送给客户。

因此,事后我又应用了lua脚本和redis相互配合一起来解决了这个问题。实际编码,我能事后梳理解决填补详细。

小结

到此这篇有关PHP Redis事务管理解决分布式系统下产品超售难题的文章内容就详细介绍到这了,大量有关php redis 解决分布式系统下产品超售內容请搜索之前的文章内容或再次访问 下边的类似文章期待大伙儿之后多多的适用!