题记:秒杀,主要是在活动开始的一瞬间,服务器将要承受高并发,并且能够快速响应,反馈给用户是否抢购成功。所以必须缩短秒杀接口的处理时间集竟可能的减少处理逻辑,以提高TPS。
看过很多类似的博客,很多都是使用消息队列进行流量削峰,由于消息队列的异步性,并不能实时返回接口,然后前端轮询抢购结果。
也有的是在Nginx进行请求随机拦截,直接减少一大半的用户,也可以有效的减少并发量。
本文主要是结合Redis的Lua脚本实现,因为lua在redis中的原子性,和redis的单线程特性,可以有效防止超卖的现象发生,也可以充分利用Redis的高并发特性。
对于一般的秒杀活动,一般需要三个参数就够了,活动编码,抢购会员号,抢购数量,对于活动数量在活动开始前进行预热写入Redis即可。
java中调用redis的eval方法只需要传递三个参数和lua脚本即可
示例代码:
@RestController("/**")
public class SeckillController{
@ResponseBody
@GetMapping("/****")
public String process(String activeId, String memberNum, Integer buyNum){
// 可以将脚本内置到Redis中
String script = "............";
Object obj = jedis.eval(script, 3, activeId, memberNum, buyNum);
// TODO 解析返回值
}
}
然后根据返回值判断即可。
lua示例脚本(定义为字符串即可):
## -1-库存不足 0-抢购数量大于可抢库存 1-抢购成功
# 通过活动编码获取活动库存数量
local num = redis.call('get', KEYS[1])
if num == 0 then
return -1
elseif num < KEYS[3] then
return 0
else
# 扣减活动库存
redis.call('decrby', KEYS[1], KEYS[3])
# 记录会员购买数量
redis.call('set', KEYS[2], KEYS[3])
return 1
end
活动结束后可以通过定时任务进行消费,正式扣库存等动作。
应对秒杀场景,有很多处理方法和应对的架构,但数据库层最好隔离开,保护好数据库
全篇仅个人想法,如果存在不足之处,请多多指正,只有多说说自己的想法,得到大家的评点,才能从中有所收获,一步步提高自己。