主要针对并发状况下,经过redis的分布式锁和队列的方式进行处理的代码git
Queue:{商品ID}: 数据类型是有序集合(zset),成员是用户ID,score是用户入队的时间戳github
Lock:Queue:{商品ID}: 数据类型是字符串(string),存储的是该锁的过时时间redis
goods:{商品ID}:stock: 存储的是商品的库存数量并发
简单介绍demo代码中的实现思路:分布式
将当前秒杀的商品id做为一个队列名称this
$queue_name = “Queue:{商品ID}”;blog
对$queue_name进行加锁队列
经过setnx(知足原子性)实现加锁 :$redis->setnx("Lock:Queue:{商品ID}", $expire time)ip
加锁成功,给该锁设置一个过时时间,主要是为了防止死锁字符串
若是加锁失败,经过设置休眠时间,进行循环请求
加锁成功后,判断队列中的成员数是否超过指定的大小
$count = $this->redis->zCard("Queue:{$name}"); if($count >= $this->redis->get("goods:{$name}:stock")) { $this->lockModel->unlock("Queue:$name"); return '超过指定集合数量'; }
判断用户ID是否存在队列中,如不存在则加入队列(score:存入的是当前时间戳 )
if (false === $this->redis->zScore("Queue:$name", $user_id)) { $this->redis->zAdd("Queue:$name", $score, $user_id); }
入队成功,进行解锁$redis->del("Lock:Queue:{商品ID}");提示用户抢购成功。成功的用户会跳转到确认购买的页面,点击确认后才会生成订单、出队等后续操做
ps: 针对多个帐号,一次性发送多个请求能够经过ip的访问频率的限制来预防
参考文章:http://blog.jobbole.com/95156/
demo代码的下载地址:https://github.com/Ritajiajia/redis_test/tree/master/test/seckill