秒杀场景问题

2019-04-03  |  技术  |  375 views

       最近面试,关于商品秒杀的问题被问了多次,在这里记录一下个人的一些解决思路。
       首先我们需要先了解下秒杀场景会出现什么问题

  • 高并发,同一时间大量用户请求秒杀接口
  • 超发,也就是有可能出现1个商品发给了2个用户,这个时候数据库记录的库存可能为负

       围绕上面2个问题,我们可以通过下列的一些措施来避免:

  • 前端处理,前端限制用户的点击次数。例如x秒时间内只能允许用户点一次,又或者点击秒杀按钮后页面显示抢购中,防止用户继续点击。

  • 秒杀接口层,限制用户访问次数。接收到用户的请求后,可以把用户的uid,uuid,ip等作为key,访问次数作为value,保存在Redis或Memcached缓存中,每访问一次,增加一次访问次数。另外,给key设置一个过期时间,在key的生命周期内,如果访问次数达到了设定的限制值,则直接返回抢购中或其他提示信息。

  • 逻辑处理层,把成功进入逻辑处理层的请求放入队列中(可用Redis做队列),然后每次从队列中取出一定数量的请求来处理,成功后继续取下一批来处理。如果库存为0了,则返回秒杀完毕。这里如果只有1个秒杀商品的话,也可以使用文件锁来实现,只有一个请求能获得文件锁资源,其他的请求直接就返回秒杀完毕。PHP中文件锁代码大致如下:

    $fp = fopen('a.txt', 'r'); //a.txt是你创建的文件,里面什么都不用写,创建出来就行了
    //获取文件锁成功,非阻塞,如果资源已被占用,请求直接到else操作
    if(flock($fp, LOCK_EX | LOCK_NB)){ 
        //TODO 你的逻辑处理
        flock($fp, LOCK_UN); //释放文件锁
    }else{
        //TODO 获取失败
    }
    fclose($fp); //关闭文件资源
  • MySQL层,把库存字段设置为非负数,即unsigned类型

  • 库存信息也可以保存一份到Redis等缓存中。每次请求进来后,先检查缓存中的库存数是否充足,然后再做后续的处理。

  • 因为前端页面是需要显示商品信息的,所以,后端也可以把商品信息,如商品名称,图片,介绍这些缓存起来,不用每次都去查库,增加数据库的负担。

       以上就是关于秒杀场景的一些解决措施,希望对你有所帮助。

发表新评论