Redis秒杀相关点

一、秒杀的特点

  1. 瞬时并发量很大

    qps可能达到几十万,上百万。一般数据库只能支持千级别的并发量,而redis单节点数万的并发量支持,所以可以使用redis来处理大部分请求,最终少量请求进入DB,

  2. 读多写少

    秒杀是大量用户针对少量的库存进行抢,所以最终的下单并不会特别多,所以读操作远远多于写操作。

    秒杀场景下,一般是先读取产品的详情,剩余库存等,查询条件一般是一个简单的产品ID,典型的key-value查询,redis支持高效的key-value查询。

二、库存同步问题

商品的库存全部放入redis,库存的读取直接读取redis,到了下单环节,库存的扣除也直接在redis扣除,然后通过消息队列通知后端数据库,最终把库存的扣减异步同步到后台数据库,避免了对数据库的瞬时压力。

2.1 key-value设置

  1. key:商品id

  2. value:字符串-{total : x, ordered : y}。total代表总库存,ordered代表已经扣减的库存。

2.2 库存原子操作

使用lua脚本

库存的查询验证和扣减放在一个脚本中,通过lua脚本来保证库存扣减的原子性

#获取商品库存信息            
local counts = redis.call("HMGET", KEYS[1], "total", "ordered");
#将总库存转换为数值
local total = tonumber(counts[1])
#将已被秒杀的库存转换为数值
local ordered = tonumber(counts[2])  
#如果当前请求的库存量加上已被秒杀的库存量仍然小于总库存量,就可以更新库存         
if ordered + k <= total then
    #更新已秒杀的库存量
    redis.call("HINCRBY",KEYS[1],"ordered",k)                              
    return k;  
end               
return 0

客户端可以通过lua脚本的返回值来判断是否秒杀成功,返回k成功,返回0,则代表失败。

分布式锁

通过redis锁,把库存的查询验证和扣减放在一个锁中。同样实现了扣减的原子性。

//使用商品ID作为key
key = itemID
//使用客户端唯一标识作为value
val = clientUniqueID
//申请分布式锁,Timeout是超时时间
lock =acquireLock(key, val, Timeout)
//当拿到锁后,才能进行库存查验和扣减
if(lock == True) {
   //库存查验和扣减
   availStock = DECR(key, k)
   //库存已经扣减完了,释放锁,返回秒杀失败
   if (availStock < 0) {
      releaseLock(key, val)
      return error
   }
   //库存扣减成功,释放锁
   else{
     releaseLock(key, val)
     //订单处理
   }
}
//没有拿到锁,直接返回
else
   return

2.3 扣库存的一致性

上面的设计中,扣减库存在先操作redis中,redis操作成功后发送消息队列,最终通过消息队列实现异步同步数据库库存,实现了最终一致性。 但是有几个异常情况:

  1. redis扣减成功,消息队列发送失败。

    解决方案:

    1. 回滚redis的库存扣减操作。返回下单失败
    2. 另外也可以直接返回扣库存失败,不再操作redis,出现少卖情况。
  2. redis扣减成功,消息也发送成功,但是最终由于网络等原因奔溃

    对于这种情况可以让调用方发起还库存操作。还库存api内部可以通过唯一序列号进行关联(扣和还都传入一样的序列号),来判断是否要真正的还库存。

2.4 还库存

还库存先操作数据库,后同步redis,因为秒杀场景还库存的case比较少,直接操作数据库第一时间保证库存的准确性。

还库存的核心在于保证数据库的库存是准确的。如果后续有部分没有同步到redis,也是部分少买问题,再加上秒杀场景中还库存的case比较少,少买问题可以忽略。

扣库存是异步传输到db的,所以会出现这种情况:还库存的请求先于扣库存的到达,这时候需要将这个还库存的请求暂时存储,后续不停尝试,比如结果1小时还是没有还成功,可以进行预警人工干预。

2.5 库存监控

可以在秒杀结束后,针对实际订单量和库存的扣除量做一个对比监控,用于第一时间发现库存不一致的问题,尤其超卖的case。

作者:iBrake
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文地址:https://www.cnblogs.com/Brake/p/14433964.html