redis实现高并发下的抢购/秒杀功能 您所在的位置:网站首页 抢购秒杀软件咋实现的 redis实现高并发下的抢购/秒杀功能

redis实现高并发下的抢购/秒杀功能

2024-07-08 19:37| 来源: 网络整理| 查看: 265

之前对redis高并发下的抢购/秒杀一直是迷迷糊糊的,还是不认真的原因。今天在慕课网学习了一下视频,讲了些基础,也照着他的代码写了案例(有趣的是:免费的课程,老师讲的太简单,甚至还有漏洞):

1:数据库连接(单例模式的):

class Db{ private static $_instance; private static $_dbConnect; private $_config=array( 'host'=>'172.22.32.107', 'user'=>'itop', 'password'=>'itop', 'db'=>'test_zd_practice' ); private function __construct() {} private function __clone() {} public static function getInstance(){ if(!self::$_instance instanceof self){ self::$_instance=new self(); } return self::$_instance; } public function connection(){ self::$_dbConnect=mysqli_connect($this->_config['host'],$this->_config['user'],$this->_config['password']); if(!self::$_dbConnect){ throw new Exception("mysql connect error".mysql_error()); } mysqli_set_charset(self::$_dbConnect,'utf8'); mysqli_select_db(self::$_dbConnect,$this->_config['db']); return self::$_dbConnect; } }

2:redis_queue.php

$redis=new Redis(); $redis->connect('127.0.0.1',6379); $redis_name="order"; $count=10; for($i=0;$ilLen($redis_name)rPush($redis_name,$uid."%".microtime()); echo $uid."秒杀成功"; }else{ echo $uid."秒杀已结束"; } } $redis->close()

3:save_db.php

include 'db.php'; $redis=new Redis(); $redis->connect('127.0.0.1',6379); $redis_name="order"; while(1){ $user=$redis->lPop($redis_name); if(!$user || $user=='nil'){ sleep(2); continue; } $arr=explode("%",$user); $uid=$arr[0]; $time_stamp=$arr[1]; $db=Db::getInstance(); $conn=$db->connection(); $result=mysqli_query($conn,"insert into redis_queue(uid,time_stamp) values ($uid,$time_stamp)"); if(!$result){ $redis->lPush($redis_name,$user); } sleep(2); } $redis->close();

redis_queue.php  在高并发下是有问题的:

在抢购进行到一定程度,假如现在已经有9个人抢购成功,又来了3个用户同时抢购,这时if条件将会被绕过(条件同时被满足了),这三个用户都能抢购成功。而实际上只剩下一件库存可以抢了。 在高并发下,很多看似不大可能是问题的,都成了实际产生的问题了。要解决“超抢/超卖”的问题,核心在于保证检查库存时的操作是依次执行的,再形象的说就是把“多线程”转成“单线程”。即使有很多用户同时到达,也是一个个检查并给与抢购资格,一旦库存抢尽,后面的用户就无法继续了。 我们需要使用redis的原子操作来实现这个“单线程”。首先我们把库存存在store这个列表中,假设有10件库存,就往列表中push10个数,这个数没有实际意义,仅仅只是代表一件库存。抢购开始后,每到来一个用户,就从store中pop一个数,表示用户抢购成功。当列表为空时,表示已经被抢光了。因为列表的pop操作是原子的,即使有很多用户同时到达,也是依次执行的。抢购的示例代码如下:

$redis=new Redis(); $redis->connect('127.0.0.1',6379); $store="store"; $order="order"; /*到“/抢购的时间到了”可放入其他地方,抢购时间一般是固定的,可在抢购之前就执行这段代码 */ $count=10; $len = $redis->lLen($store); $count = $num - $len; for ($i = 0; $i < $count; $i++) { $redis->lpush($store, 1); } //抢购的时间到了 for($i=0;$ilpop($store); /* 模拟抢购操作,抢购前判断redis队列库存量 */ if (!$count){ echo '秒杀已结束'; }else{ $result = $redis->lpush($order,$uid."%".microtime()); if($result){ echo '秒杀成功'; } } } $redis->close();

本文涉及部分转载,参照:https://www.cnblogs.com/phpper/p/7085663.html 里面写得很好哦!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有