超卖问题浅析

问题难点

  • 1 突发访问量
    • 前端优化
      • 秒杀倒计时,不能发送下单请求,下单键不可用
      • 下单后,不能重复下单请求,下单键不可用
      • JS程序设置用户请求最小间隔时间
      • 使用前端缓存,相同页面直接从缓存刷新
    • 后端优化
      • 见后文
    • 行业方案
        1. 使用队列组织 nginx 接收到的请求,业务服务器从队列中取,顺序处理
        1. 负载均衡
        1. 提升机器数量
        1. nginx 接入层筛选限流,再转发到服务器
  • 2 带宽限制
    • 突发流量太大,需要从运营商临时购买
    • 设置CDN缓存页面,分担服务器压力
  • 3 大部分不会生成订单的请求
    • 在 nginx 反向代理层,就进行筛选发送到服务器的请求
  • 4 超卖问题
    • 在同一时间内,数据库中没有及时更新库存量,多个用户抢到商品,但是只能有一个用户买到
    • 行业方案
      • MySQL 悲观锁:数据库层面设置的写锁,保证修改只能同时被一个session执行,在完成前其他都需要等待
        • 优点:稳定
        • 缺点:锁等待,资源消耗
      • MySQL 乐观锁:程序设计时,增加的锁机制,比如增加版本号,在修改时先查询版本号是否被更改,没改动一次就更新版本号,此时只有一条SQL执行成功。
        • 优点:比悲观锁并发量大
        • 缺点:MySQL本身处理不了大量并发请求
      • 队列:使用队列变成有序的请求处理
        • 优点:稳定,可以处理大量并发请求
        • 缺点:本身实时处理请求速率低,大量并发请求内存占用高
      • Redis 分布式锁:SETNX 只能设置一次键值,返回1,再次设置会返回0。基于此,多个线程只有一个线程的 SETNX 返回 1。超时时间后,删除 SETNX 设置的key。
        • 优点:只限制处理库存时,只允许单线程执行
        • 缺点:线程级的限制,资源浪费
      • Redis 乐观锁:Redis watch 机制,比如 watch 库存值得变化。当Redis事务开启后,库存值发生变化,就回滚当前事务。所以并发请求当有一个成功时,其他请求的事务都会回滚。
        • 优点:没有限制线程的执行数量,只是打断冲突线程的执行。
        • 缺点:在这些方法的比较中,缺点不明显,可以使用高性能的语言或者框架,进一步提升性能

方案设计

  • 静态资源处理,图片、js、css、页面等
    • 使用CDN
    • 加大带宽
  • 业务请求处理
    • Nginx 过滤大部分一定不会生成订单的请求
    • Nginx-Lua + Redis 乐观锁解决超卖问题
    • 服务器处理少量请求

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!