利用redis实现并发超卖的问题 作者:七棵菜 日期:2022-11-30 栏目:计算机分类:1 人气:465 #### 需求 有这样的需求,疫情期间公园每日的预约人数有上线,通过线上预约的方式,当产生并发的时候,可能会产生预约人数多于限定人数的情况。 一般的解决思路是在用户预约的时候判断一下预约人数是否已经达到了上限,但是当预约人数即将达到上限此时产生并发时,就会产生问题。 例如:每日限定1千人,当已经预约了999人后,来了10个并发,那么这10个人都会预约成功。 我们可以借助redis的单进程特性解决此类问题,有两种办法: - redis队列 事先将预约的个数保存到队列中,用户预约的时候从队列依次pop。 ``` // 1.现将预约全部排入队列中. $store = 100; // 原定预约100 $store_key = "coupon_limit"; $redis = new Redis(); $redis->connect('127.0.0.1',6379); $count = $store; // 将预约添加到队列中. if($count) { for($i=0;$i<$count;$i++) { $redis->rpush($store_key,1); } } // 2. 检查队列 执行预约. // 检查是否还有名额 $is_has_number = $redis->rPop($store_key); if (!$is_has_number) { echo "已经预约完毕!"; } // 执行预约逻辑. echo "预约成功! 预约时间:".$redis->llen($store_key); ``` - redis锁 预约时检查是否有人正在预约,如果有人正在预约,提示稍后再来;否则进行预约,并加锁。这样就不会同时预约。 ``` namespace base\business; /** * 枷锁类 */ class BusinessLock { private static $_instance ; private $_redis; private function __construct() { $this->_redis = new \Redis(); $this->_redis ->connect('127.0.0.1'); } public static function getInstance() { if(self::$_instance instanceof self) { return self::$_instance; } return self::$_instance = new self(); } /** * @function 加锁 * @param $key 锁名称 * @param $expTime 过期时间 * @return boolean */ public function set($key, $expTime) { // 初步加锁 $isLock = $this->_redis->setnx($key, time() + $expTime); if ($isLock) { return true; } else { // 加锁失败的情况下。判断锁是否已经存在,如果锁存在且已经过期,那么删除锁。进行重新加锁 $val = $this->_redis->get($key); if ($val && $val<time()) { $this->del($key); } return $this->_redis->setnx($key, time() + $expTime); } } /** * @param $key 解锁 */ public function del($key) { $this->_redis->del($key); } } /* 枷锁操作 */ $lockObj = BusinessLock::getInstance(); $lock_key = 'coupon-' . $bean->level; // 判断是能加锁成功 if (! $lockObj->set($lock_key, 10)) { // 加锁不成功,说明有人正在预约 throw new Exception(''); } // [todo] if ($lock_key && isset($lockObj)) { // 解锁 $lockObj->del($lock_key); } ``` #### 两种方法的区别 - 前者适合抢购,秒杀等活动,在时间明确,库存不是太多的情况,可以提前将队列生成好。因为如果队列太多,占用资源较多。 - 后者适合并发不太高和没有时间约束的情况。例如积分消费,余额消费等。 标签: redis 并发 抢购 上一篇:如何使用mvn命令导入依赖 下一篇:windows10 企业版/专业版激活方法 随便看看 2024-02-19 PHP7 运算符“??” 和“?:”的区别 2022-11-30 Linux 后台运行命令 2022-11-25 关于我们 2022-11-30 centos一键系统安装lnmp集成环境 2022-11-30 linux 生成 ssh 公钥 留言