基于Lua简单实现秒杀场景

题记:秒杀,主要是在活动开始的一瞬间,服务器将要承受高并发,并且能够快速响应,反馈给用户是否抢购成功。所以必须缩短秒杀接口的处理时间集竟可能的减少处理逻辑,以提高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

活动结束后可以通过定时任务进行消费,正式扣库存等动作。

应对秒杀场景,有很多处理方法和应对的架构,但数据库层最好隔离开,保护好数据库

全篇仅个人想法,如果存在不足之处,请多多指正,只有多说说自己的想法,得到大家的评点,才能从中有所收获,一步步提高自己。

发布了40 篇原创文章 · 获赞 31 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/weixin_38422258/article/details/103743544