场景分析


别问 问就是为了面试豁出了老命

秒杀系统

下单减库存

  1. 订单减库存
    • 当用户下了订单之后,则会减库存
    • 保证了秒杀活动是不会超卖
    • 但是如果有订单未支付的话,则会产生少卖
  2. 支付减库存
    • 顾名思义就是说下单的时候是不会对数据库进行操作,只有支付成功后才会进行减库存
    • 如果多个请求发现剩余库存都是1,那么都发起支付会产生超卖的现象
    • 但是保证了不会少卖
  3. 预扣库存
    • 本质上是订单减库存,但是会有有效时间
    • 在有效时间内库存一直被减去,但是一旦失效则立刻回复库存
    • 但是还是难以防止恶意下单导致的库存被占用

流量削峰

  1. 限流算法

    • 令牌桶算法
      令牌桶.jpg
      • 令牌可以源源不断的恒定速度流入桶内,但是如果超过桶的容量则溢出
      • 请求需要时可以直接从令牌桶中拿到令牌,则桶内的令牌减去
      • 允许突发性能
    • 漏桶算法
      漏桶.jpg
      • 漏桶不装水,一旦流入速度大于流出的速度则就会溢出
      • 最大程度上限制了传输的速度
      • 没有突发性能可言
  2. 秒杀大闸

    • 由于令牌桶算法的无限生成,因此需要限制量的大小
    • 则对秒杀量进行初始化,设置秒杀的负载因子
    • 假如秒杀量为10w,负载因子为5,则秒杀大闸是50w
    • 则TPS还是50w,并发程度还是很高,削峰还是不够彻底
  3. 队列泄洪
    队列泄洪

    • 由于限流算法和秒杀大闸无法更好的解决大量的数据流
    • 因此想到异步的操作,先把订单请求存储,之后再慢慢的处理
    • 利用消息队列,将请求先存入队列中,之后异步的处理消息队列中的请求

缓存数据库双写一致性

  1. 先删缓存,再修改数据库
    先删除缓存再更新数据库.jpg
    • 当数据库没有做读写分离时
      • 请求A先删除数据库
      • 请求B同时来查询该数据,则不能命重缓存,但是由于请求A修改的数据还没提交,则回到数据库查询旧值
      • 之后请求A再更新数据库
      • 可以使用延时双删解决
        延时双删
        • 也就是说在A更新完数据库之后,等待一段时间,再删除缓存
    • 当数据库做了读写分离
      • 同上过程,因为数据提交以后,不一定主从同步结束
      • 所以B可能还会拿到旧的数据库
      • 因此当没有在redis中命重数据时,则应该强制到主库去查询,查询后再填充到数据库
  2. 先修改数据库,再删缓存
    先更新数据库再删除缓存.jpg
    • 请求A先更新数据库,则缓存依然存在
    • 请求B查询数据时在缓存中命重
    • 则请求B查询到的数据都是旧的
    • 之后A请求才会删除数据