Redis为什么可以支撑秒杀场景
秒杀场景的负载特征对支撑系统的要求
特征一:瞬时并发访问很高。
一般的数据库每秒可以支撑千级别的并发请求,而Redis的并发处理能力达到了万级别。所以当有大量请求涌入系统,我们可以使用Redis先拦截大部分请求,避免很多请求直接发到数据库。
特征二:读多写少,而且读操作是简单查询操作。
一般的场景,需要先验证库存,然后再进行下单和商品购买,而查询库存这一操作也比较简单,适合使用Redis。
Redis 可以在秒杀场景的哪些环节发挥作用
秒杀活动前
在这个阶段,用户会不断刷新商品详情页,这会导致详情页的瞬时请求量剧增。这个阶段的应对方案,一般是尽量把商品详情页的页面元素静态化,然后使用 CDN 或是浏览器把这些静态化的元素缓存起来。这样一来,秒杀前的大量请求可以直接由 CDN 或是浏览器缓存服务,不会到达服务器端了,这就减轻了服务器端的压力。
秒杀活动开始
简单来说这个阶段的操作有三个,库存查验、库存扣减和订单处理,其中查看库存的请求应该是最多的。所以我们可以使用Redis来保存库存数量,减少查询库存给数据库带来的压力。
除了查库存外,订单处理的操作可以放在后端处理。因为这时候只有少部分请求可以到达,所以压力不会太大。
但是扣减库存的操作最好不要放在后端。因为扣减库存放在数据库则需要维护Redis和数据库数据的一致性,会增加额外的开销。而且数据库更新比较慢,可能会导致大量请求查到旧的库存,导致超卖。所以扣减库存的操作最好放在redis中。
秒杀结束后
整个阶段并发量会小很多,并不需要redis过多参与。
Redis 的哪些特点可以支撑秒杀场景
支持高并发
Redis本身就支持高并发,如果有多个秒杀商品,我们也可以使用切片集群,用不同的实例保存不同商品的库存,这样就避免,使用单个实例导致所有的秒杀请求都集中在一个实例上的问题了。
保证库存查验和库存扣减原子性执行
针对这条要求,我们就可以使用 Redis 的原子操作或是分布式锁这两个功能特性来支撑了。
基于原子操作支撑秒杀场景
因为查验库存和扣减库存这两个操作要保证一起执行,一个直接的方法就是使用 Redis 的原子操作。
Redis原子操作有两种办法,原子命令或者Lua脚本。由于这是两个操作,无法使用一个命令,所以这里要使用lua脚本。
基于分布式锁来支撑秒杀场景
使用分布式锁来支撑秒杀场景的具体做法是,先让客户端向 Redis 申请分布式锁,只有拿到锁的客户端才能执行库存查验和库存扣减。这样一来,大量的秒杀请求就会在争夺分布式锁时被过滤掉。而且,库存查验和扣减也不用使用原子操作了,因为多个并发客户端只有一个客户端能够拿到锁,已经保证了客户端并发访问的互斥性。
秒杀场景其他需要注意的点
请求拦截和流控
在秒杀系统的接入层,对恶意请求进行拦截,避免对系统的恶意攻击,例如使用黑名单禁止恶意 IP 进行访问。如果 Redis 实例的访问压力过大,为了避免实例崩溃,我们也需要在接入层进行限流,控制进入秒杀系统的请求数量。
库存信息过期时间处理
Redis 中保存的库存信息其实是数据库的缓存,为了避免缓存击穿问题,我们不要给库存信息设置过期时间。
数据库订单异常处理
如果数据库没能成功处理订单,可以增加订单重试功能,保证订单最终能被成功处理。