Redis学习(二十四):代码实战之秒杀场景

1.秒杀场景的划分

我们将秒杀场景一般秒杀前、秒杀中、秒杀后,那么redis一般适用于哪些场景呢?

2.秒杀场景分析

从上面我们也能够得到一些思考,有时候就算是一个不那么大的业务场景,我们再对其进行分析时,也应该能够将其按照时序、或者读写性能的痛点能够进行拆分,因此我们也以秒杀这个场景,来分析其对于应用系统的负载要求

  • 瞬时并发量非常大
  • 读多写少,并且读的场景比较简单的查询操作

那么redis具体在秒杀的哪些环节可以发挥作用呢?

2.1.秒杀前

该阶段用户会不断的刷新页面,因此可以将商品详情的元素静态化并放置到CDN或浏览器将元素缓存起来

所以该阶段一般可以不用redis

2.2.秒杀进行中

秒杀的过程中,主要涉及如下几个操作:查询库存、扣减库存、订单相关、物流等

其中最重要的就是查询库存操作,因为只有当我们查询到了库存有余量才会走下面的步骤,所以大部分的请求都会请求库存,因此面对大量的并发请求我们需要将库存放到redis中进行处理

那库存扣减、订单处理、物流等是不是可以放在数据库进行处理了呢?

答案当然是不是,如果我们将库存扣减放到底层数据库进行处理,会发生什么呢?

  • 额外的开销:数据库扣减完库存之后,还得同步修改redis缓存中的库存
  • 出现超量出售:由于在数据库中如果进行事务处理,则可能出现更新覆盖的场景,也就是不能及时更新库存量,或者说库存量的可见性无法保证,而如果要抱住库存的可见性就不得不使用锁机制,这样就会导致数据库处理速度大大下降,这样就更不是我们能接收的了

所以,库存扣减我们需要放到redis中执行,具体做法就是判断有库存后,就立马减少库存,当然查询库存和减库存这两个操作需要保证原子性,具体如何保证有两个方案:

  • 使用redis的原子性操作desc/incr或lua脚本

  • 使用分布式锁:

    这里我们可以让请求都去请求锁,只有请求到锁的请求才能继续往下走,在请求层面我们就过滤掉了一大批请求。并且我们可以可能用切片集群的不同实例存储锁和商品数据,当没有请求到锁就不会去请求商品实例,减轻了商品实例的负担

但是订单处理、物流等我们能够放到数据库中处理,因为下单、物流等涉及到多张表,要保证处理的事务性,所以可以放在数据库中进行处理,当然redis也能实现事务,但是在数据一致性等方面无法满足

2.3.秒杀结束

这里可以不使用redis,因为到了这个阶段往往请求量并不大了

img

3.Redis为什么适合秒杀场景

  • 支持高并发:edis本身高速处理请求的特性就可以支持高并发。而且,如果有多个秒杀商品,我们也可以使用切片集群,用不同的实例保存不同商品的库存,这样就避免,使用单个实例导致所有的秒杀请求都集中在一个实例上的问题了
  • 保证库存查验和库存扣减的原子性:原子操作、Lua、分布式锁

4.秒杀场景的全景

当然秒杀场景下,光光只讨论redis是不够的,秒杀场景我们应该要考虑到方方面面,例如:

  1. 前端静态页面的设计。秒杀页面上能静态化处理的页面元素,我们都要尽量静态化,这样可以充分利用CDN或浏览器缓存服务秒杀开始前的请求。
  2. 请求拦截和流控。在秒杀系统的接入层,对恶意请求进行拦截,避免对系统的恶意攻击,例如使用黑名单禁止恶意IP进行访问。如果Redis实例的访问压力过大,为了避免实例崩溃,我们也需要在接入层进行限流,控制进入秒杀系统的请求数量。
  3. 库存信息过期时间处理。Redis中保存的库存信息其实是数据库的缓存,为了避免缓存击穿问题,我们不要给库存信息设置过期时间。
  4. 数据库订单异常处理。如果数据库没能成功处理订单,可以增加订单重试功能,保证订单最终能被成功处理。

最后:

秒杀系统最重要的是,把大部分请求拦截在最前面,只让很少请求能够真正进入到后端系统,降低后端服务的压力,常见的方案包括:页面静态化(推送到CDN)、网关恶意请求拦截、请求分段放行、缓存校验和扣减库存、消息队列处理订单。

另外,为了不影响其他业务系统,秒杀系统最好和业务系统隔离,主要包括应用隔离、部署隔离、数据存储隔离

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×