redis简单实现高并发秒杀功能

前言:

秒杀功能不外乎就是解决下面两个问题,

  1. 第一个是高并发对数据库产生的压力,
  2. 第二个是竞争状态下如何解决库存的正确减少,则超卖问题。

使用redis是最优方式,文件锁和数据库锁都不太好,因为redis可以方便实现分布式锁,而且redis支持的并发量远远大于文件锁和数据库锁。redis使用乐观锁(共享锁),悲观锁(排它锁)都可以,不过悲观锁有个问题就是锁等待的时间会占用大量内存,秒杀一般是少量的数据,所以是读多写少场景,使用乐观锁更加合适。另外redis实现悲观锁不太友好,会产生一些问题,这些问题需要结合lua脚本才能解决。使用队列也可以,但是并发量会使队列的内存瞬间占慢。

redis使用乐观锁非常简单,就是事务结合watch()方法实现监控,因为悲观锁是进程阻塞的,为了用户体验更好,可以手动模拟把阻塞改成非阻塞。以下是实现的代码:


 	 //初始化redis
        $redis = Cache::factory('Redis');

        $stock = 3; //抢购货存数量
        $i = 0;
        $rebeat = 5; //重复执行次数(如果锁冲突了,允许重复执行,直到没有出现锁冲突为止,把阻塞模拟成非阻塞)
        while($i < $rebeat) {
            $watchkey = $redis->handle()->get("watchkey");
            if(!$watchkey)
                $watchkey = 0;

            if ($watchkey < $stock) {
               //1.监控watchlist,因为虽然redis有原子性,但是事务没有原子性,所以watch这里起到一个事务锁(乐观锁)的功能.
               //2.举个例子,假如有两个并发进程去竞争购买权,redis在监控一个key,第一个先到,第二个后到,先到的抢先一步更新了key,后到的虽然也进来的,但是得知key已被更新,不得已只能中断自己当前的执行事务。
               //3.这里监控watchlist和watchkey都可以。
                $redis->handle()->watch("watchlist");
                //$redis->watch("watchkey");

                //开启事务
                $redis->handle()->multi();
                
                //插入抢购数据(先放入redis,等抢购完成之后再异步入库)
                $redis->handle()->hSet("watchlist", "user_id_" . mt_rand(1, 9999), time());
                $redis->handle()->set("watchkey", $watchkey + 1);
                
                //执行事务
                $result = $redis->handle()->exec();
                if ($result) {
                    $watchlist = $redis->handle()->hGetAll("watchlist");
                    return array(
                        'status'=> 1,
                        'msg'=>'抢购成功,剩余数量:'.($stock - $watchkey - 1),
                        'data'=>$watchlist
                    );
                    break;
                } else {
                    //设置一个循环时间防止性能损耗过大
                    usleep(5000);
                    $i++;
                }
            } else {
                return array(
                    'status'=> 0,
                    'msg'=>'抢购失败,商品已经抢购完毕!',
                    'data'=>[]
                );
                break;
            }
        }
        return array(
            'status'=> 0,
            'msg'=>'抢购失败,锁冲突了!',
            'data'=>[]
        );

结果分析:

执行结果如下,使用ab工具模拟多个进程执行也没有出现超卖情况

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值